初探t-sne(附python代码)
九月下旬啦!
封校不能出门 只能乖乖在校科研了
(厦门加油~同安稳住鸭!)
今天做一个简单的知识记录/代码记录
T-sne
t-SNE(t-distributed stochastic neighbor embedding)是用于降维的一种机器学习算法,可以将高维数据内部的特征放大,使得相似的数据在低维中能更加接近,不相似的数据在低维中距离更远
降维,简而言之,就是将高维空间的数据在低维空间进行展示。
与之前写过的PCA(https://www.jianshu.com/p/7cc617ee0f0c)相比,t-sne属于非线性降维,PCA为线性降维。线性降维算法主要问题是它们集中将不相似的数据点放置在较低维度区域时,数据点相距甚远。但是为了在低维、非线性流型上表示高维数据,也需要把相似的数据点靠近在一起展示,这并不是线性降维算法所能做的,且线性降维不能解释特征直接复杂的多项式关系,具有一定的局限性。t-SNE是基于在邻域图上随机游走的概率分布,可以在数据中找到其结构关系,故,t-sne在降维上比PCA更胜一筹。
算法
t-sne是在sne的基础上提出来的,这边对sne就不展开过多的介绍
具体可见(https://blog.csdn.net/scott198510/article/details/76099700)t-sne搬运(https://zhuanlan.zhihu.com/p/148170862)
步骤1:先测量一个点相对于其他点的距离。
(不是直接处理这些距离,而是将它们映射到一个概率分布。)在分布中,相对于当前点距离最小的点有很高的可能性,而远离当前点的点有很低的可能性。
步骤2:除以概率总和
(请注意蓝色的点团比绿色的点团更分散。我们需要解决比例上的差异)
因此,尽管两点之间的绝对距离不同,但它们被认为是相似的。
数学概念:正态分布
把指数前面的所有东西都放下,用另一个点代替均值,得到了方程:
步骤3:如何使用缩小的特征空间
首先,我们创建一个n_samples x n_components矩阵(在本例中为9x1),并用随机值(即位置)填充它
如果采用与上面相似的方法(测量点之间的距离并将它们映射到一个概率分布),得到以下等式: 。
如果能使简化特征空间中的点的概率分布近似于原始特征空间中的点,就能得到定义良好的聚类。为了做到这一点,我们使用了一种叫做KL散度的东西。KL散度是衡量一个概率分布与另一个概率分布的差异。(KL散度值越低,两个分布越接近。KL散度为0意味着这两个分布是相同的。) 在t-SNE中,我们使用梯度下降最小化所有数据点上的Kullback-Leiber差异的总和。
最后,对成本函数对每一点求偏导数,以便得到每次更新的方向。
一点总结:
1.非线性降维算法t-SNE通过基于具有多个特征的数据点的相似性识别观察到的模式来找到数据中的规律。
2.它不是一个聚类算法,而是一个降维算法,可以较好地通过视觉可视化来验证算法的性能。
t3.-SNE的核心思想是保证在低维上数据的分布与原始特征空间的分布相似性高。相似性度量是依赖于KL散度以及计算欧式距离并概率化。换句话说,它依然受到维度灾难的影响,如果在低维空间上本身不存在区分度或者高维空间中欧式距离差别很小的话,效果也不好。
代码
1.经典手写数字数据集的降维与可视化
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.manifold import TSNE
# 加载数据
def get_data():
"""
:return: 数据集、标签、样本数量、特征数量
"""
digits = datasets.load_digits(n_class=10)
data = digits.data # 图片特征
label = digits.target # 图片标签
n_samples, n_features = data.shape # 数据集的形状
return data, label, n_samples, n_features
# 对样本进行预处理并画图
def plot_embedding(data, label, title):
"""
:param data:数据集
:param label:样本标签
:param title:图像标题
:return:图像
"""
x_min, x_max = np.min(data, 0), np.max(data, 0)
data = (data - x_min) / (x_max - x_min) # 对数据进行归一化处理
fig = plt.figure() # 创建图形实例
ax = plt.subplot(111) # 创建子图
# 遍历所有样本
for i in range(data.shape[0]):
# 在图中为每个数据点画出标签
plt.text(data[i, 0], data[i, 1], str(label[i]), color=plt.cm.Set1(label[i] / 10),
fontdict={'weight': 'bold', 'size': 7})
plt.xticks() # 指定坐标的刻度
plt.yticks()
plt.title(title, fontsize=14)
# 返回值
return fig
# 主函数,执行t-SNE降维
def main():
data, label , n_samples, n_features = get_data() # 调用函数,获取数据集信息
print('Starting compute t-SNE Embedding...')
ts = TSNE(n_components=2, init='pca', random_state=0)
# t-SNE降维
reslut = ts.fit_transform(data)
# 调用函数,绘制图像
fig = plot_embedding(reslut, label, 't-SNE Embedding of digits')
# 显示图像
plt.show()
# 主函数
if __name__ == '__main__':
main()
原文链接:https://blog.csdn.net/tszupup/article/details/84997804
2.t-SNE可视化两个图片数据集合的差异
import os
import numpy as np
import cv2
from time import time
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from sklearn import datasets #手写数据集要用到
from sklearn.manifold import TSNE
#该函数是关键,需要根据自己的数据加以修改,将图片存到一个np.array里面,并且制作标签
#因为是两类数据,所以我分别用0,1来表示
def get_data(Input_path): #Input_path为你自己原始数据存储路径,我的路径就是上面的'./Images'
Image_names=os.listdir(Input_path) #获取目录下所有图片名称列表
data=np.zeros((len(Image_names),40000)) #初始化一个np.array数组用于存数据
label=np.zeros((len(Image_names),)) #初始化一个np.array数组用于存数据
#为前500个分配标签1,后500分配0
for k in range(500):
label[k]=1
#读取并存储图片数据,原图为rgb三通道,而且大小不一,先灰度化,再resize成200x200固定大小
for i in range(len(Image_names)):
image_path=os.path.join(Input_path,Image_names[i])
img=cv2.imread(image_path)
img_gray=cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
img=cv2.resize(img_gray,(200,200))
img=img.reshape(1,40000)
data[i]=img
n_samples, n_features = data.shape
return data, label, n_samples, n_features
‘’‘下面的两个函数,
一个定义了二维数据,一个定义了3维数据的可视化
不作详解,也无需再修改感兴趣可以了解matplotlib的常见用法
’‘’
def plot_embedding_2D(data, label, title):
x_min, x_max = np.min(data, 0), np.max(data, 0)
data = (data - x_min) / (x_max - x_min)
fig = plt.figure()
for i in range(data.shape[0]):
plt.text(data[i, 0], data[i, 1], str(label[i]),
color=plt.cm.Set1(label[i]),
fontdict={'weight': 'bold', 'size': 9})
plt.xticks([])
plt.yticks([])
plt.title(title)
return fig
def plot_embedding_3D(data,label,title):
x_min, x_max = np.min(data,axis=0), np.max(data,axis=0)
data = (data- x_min) / (x_max - x_min)
ax = plt.figure().add_subplot(111,projection='3d')
for i in range(data.shape[0]):
ax.text(data[i, 0], data[i, 1], data[i,2],str(label[i]), color=plt.cm.Set1(label[i]),fontdict={'weight': 'bold', 'size': 9})
return fig
#主函数
def main():
data, label, n_samples, n_features = get_data('./Images') #根据自己的路径合理更改
print('Begining......') #时间会较长,所有处理完毕后给出finished提示
tsne_2D = TSNE(n_components=2, init='pca', random_state=0) #调用TSNE
result_2D = tsne_2D.fit_transform(data)
tsne_3D = TSNE(n_components=3, init='pca', random_state=0)
result_3D = tsne_3D.fit_transform(data)
print('Finished......')
#调用上面的两个函数进行可视化
fig1 = plot_embedding_2D(result_2D, label,'t-SNE')
plt.show(fig1)
fig2 = plot_embedding_3D(result_3D, label,'t-SNE')
plt.show(fig2)
if __name__ == '__main__':
main()
参考:https://zhuanlan.zhihu.com/p/67491123
ENDing~冲冲冲!