目录
- 1. 作者介绍
- 2. 算法介绍
- 2.1 t-SNE介绍
- 2.2.SNE基本原理
- 2.3.拥挤问题
- 2.4.t-SNE基本原理
- 2.5.t-SNE算法过程
- 3. 泰坦尼克号数据集降维实验
- 3.1.数据集介绍
- 3.2 任务介绍
- 3.3 代码实现
- 3.4 实验结果
- 参考连接
1. 作者介绍
刘方星,男,西安工程大学电子信息学院,2023级研究生
研究方向:机器视觉与人工智能
电子邮件:406201373@qq.com
孙思伟,男,西安工程大学电子信息学院,2023级研究生
研究方向:深度强化学习与人工智能
电子邮件:sunsiwei0109@163.com
2. 算法介绍
2.1 t-SNE介绍
t-SNE(t-distributed stochastic neighbor embedding)是用于降维的一种机器学习算法,是由Laurens van der Maaten和Geoffrey Hinton在08年提出来。此外,t-SNE是一种非线性降维算法,非常适用于高维数据降维到2维或者3维,进行可视化。t-SNE是由SNE(Stochastic Neighbor Embedding,SNE;Hinton and Roweis,2002)发展而来。
2.2.SNE基本原理
SNE是通过仿射变换将数据点映射到概率分布上,主要包括两个步骤:
SNE构建一个高维对象之间的概率分布,使得相似的对象有更高的概率被选择,而不相似的对象有较低的概率被选择。
SNE在低维空间里在构建这些点的概率分布,使得这两个概率分布之间尽可能的相似。
2.3.拥挤问题
拥挤问题就是说各个簇聚集在一起,无法区分。比如有一种情况,高维度数据在降维到10维下,可以有很好的表达,但是降维到两维后无法得到可信映射,比如降维如10维中有11个点之间两两等距离的,在二维下就无法得到可信的映射结果(最多3个点)。进一步的说明,假设一个以数据点为中心,半径为r的m维球(三维空间就是球),其体积是按增长的。
尽管SNE提供了很好的可视化方法,但是他很难优化,而且存在拥挤问题。后续中,Hinton等人又提出了t-SNE的方法。与SNE不同,主要如下:
使用对称版的SNE,简化梯度公式。
低维空间下,使用t分布替代高斯分布表达两点之间的相似度。
t-SNE在低维空间下使用更重长尾分布的t分布来避免拥挤问题和优化问题。
从上图可以看到,随着维度的增大,大部分数据点都聚集在m维球的表面附近,与点的距离分布极不均衡。如果直接将这种距离关系保留到低维,就会出现拥挤问题。Cook et al.(2007) 提出一种slight repulsion的方式,在基线概率分布(uniform background)中引入一个较小的混合因子,这样就永远不会小于 (因为一共了n(n-1)个pairs),这样在高维空间中比较远的两个点之间的总是会比大一点。这种称之为UNI-SNE,效果通常比标准的SNE要好。优化UNI-SNE的方法是先让为0,使用标准的SNE优化,之后用模拟退火的方法的时候,再慢慢增加。
2.4.t-SNE基本原理
t-SNE的基本思想是将高维数据映射到低维空间,同时保留数据间的局部结构。具体而言,给定一个高维数据集X={ X1,X2…Xn},其中 ∈Rd ,要将其映射到一个d维的空间Y = {Y1 ,…, Yn} 且d≪D。与其他降维算法不同的是,t-SNE旨在保持数据点之间的局部相似性,即将高维空间中距离接近的点映射到低维空间中距离仍然较近的位置。为了实现这个目标,t-SNE建立了一个概率模型,用于将数据点从高维空间映射到低维空间。具体地,它假设在高维空间中距离接近的点在低维空间中也有更大的概率被选择为临近点。
在t-SNE中,每个高维数据点 对应一个在低维空间中的概率分布 ,用于描述 在低维空间中的位置。与此同时,为了保留其局部结构,还需要为每个 建立一个概率分布 ,用于描述 与其它数据点之间的相似性。在t-SNE中,用采用的是高斯分布,即
其中P( Xi∣Xj )表示在高维空间中,Xi在以 Xj为中心的局部高斯分布中出现的概率密度。它的定义为:
其中σj是一个尺度参数,用于控制局部邻域的大小。同样地,我们也需要定义一个低维空间中的概率分布q(i,j)。在t-SNE中,这个概率分布是由一个类似于softmax的归一化因子给出的,形式为:
其中( 1 + || yi − yj||2)−1可以解释成一个t分布。
t-SNE的目标函数定义为两个概率分布之间的KL散度,即
为了最小化KL散度,可以采用梯度下降法来求解。因为KL散度没有解析解,所以梯度需要通过自动微分或其他数值方法进行计算。
t-SNE的基本思想是在高维数据空间和低维嵌入空间中分别构建高斯分布和t-分布,在两个空间中寻找相同的邻居,并最小化两个概率分布之间的差异。
首先,它将通过选择一个随机数据点并计算与其他数据点的欧几里得距离来创建概率分布。从所选数据点附近的数据点将获得更多的相似度值,而距离与所选数据点较远的数据点将获得较少的相似度值。使用相似度值,它将为每个数据点创建相似度矩阵(S1)由上图可知,我们可以说X1的邻域 N(X1)= {X2,X3,X4,X5,X6},这意味着X2,X3,X4,X5和X6是X1的邻居。 它将在相似度矩阵“S1”中获得更高的价值。这是通过计算与其他数据点的欧几里得距离来计算的。另一方面,X20远离X1。这样它将在S1中获得较低的值。其次,它将根据正态分布将计算出的相似距离转换为联合概率。通过以上的计算,t-SNE将所有数据点随机排列在所需的较低维度上。t-SNE将再次对高维数据点和随机排列的低维数据点进行所有相同的计算。但是在这一步中,它根据t分布分配概率。这就是名称t-SNE的原因。
t-SNE中使用t分布的目的是减少拥挤问题,t分布→视觉上t分布看起来很像正态分布,但尾部通常更胖,这意味着数据的可变性更高。对于较低维的数据点,还将创建一个相似度矩阵(S2)。然后该算法将S1与S2进行比较,并通过处理一些复杂的数学运算来使S1与S2之间有所不同。包括使用两个分布之间的Kullback Leibler散度(KL散度)作为损失函数运行梯度下降算法。使用KL散度通过将两个分布之间相对于数据点位置的值最小化,帮助t-SNE保留数据的局部结构。
2.5.t-SNE算法过程
算法过程:
3. 泰坦尼克号数据集降维实验
3.1.数据集介绍
Titanic数据集在数据分析领域是十分经典的数据集。泰坦尼克号轮船的沉没是历史上最为人熟知的海难事件之一。1912年4月15日,在她的处女航中,泰坦尼克号在与冰山相撞后沉没,在船上的 2224 名乘客和机组人员中,共造成 1502 人死亡。这场耸人听闻的悲剧震惊了国际社会,从而促进了船舶安全规定的完善。造成海难失事的原因之一是乘客和机组人员没有足够的救生艇。尽管在沉船事件中幸存者有一些运气因素,但有些人比其他人更容易存活下来,究竟有哪些因素影响着最终乘客的生存与否。
数据集包含11个特征,分别是:
Pclass:乘客所持票类,有三种值(lower,middle,upper)
Survived:0代表死亡,1代表存活
Name:乘客姓名
Sex:乘客性别
Age:乘客年龄(有缺失)
SibSp:乘客兄弟姐妹/配偶的个数(整数值)
Parch:乘客父母/孩子的个数(整数值)
Ticket:票号(字符串)
Fare:乘客所持票的价格(浮点数,0-500不等)
Cabin:乘客所在船舱(有缺失)
Embark:乘客登船港口:S、C、Q(有缺失)
titanic = sns.load_dataset('titanic')
titanic = titanic.dropna()
这两行加载seaborn库提供的泰坦尼克号数据集,并移除了所有包含NaN值的行。
3.2 任务介绍
任务中我们分别使用PCA、LDA和t-SNE三种算法将数据集降为2维,并可视化观察其数据分布情况,之后通过K-最近邻算法(K-NN)对三种算法降维后的数据集进行分类,对比其准确性。
本任务涉及以下几个环节:
a)加载Titanic数据集
b)分别使用PCA、LDA、t-SNE算法进行降维
c)使用K-NN分类器分别在三种算法降维后的数据上建模
3.3 代码实现
import pandas as pd
from sklearn.decomposition import PCA
from sklearn.discriminant_analysis import (LinearDiscriminantAnalysis)
from sklearn.manifold import TSNE
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from time import time
import seaborn as sns
import matplotlib.pyplot as plt
def show_pic(data, target, title):
plt.scatter(data[:, 0], data[:, 1], c=target)
plt.title(title)
plt.show()
pd.read_csv('D:\\titanic\\train.csv')
titanic = sns.load_dataset('titanic')
titanic = titanic.dropna()
features = ['pclass', 'age', 'fare']
data = titanic[features]
target = titanic['survived']
# 使用不同的算法将数据降为2维
# 1、PCA降维可视化
pca = PCA(n_components=2).fit(data)
pca_data = pca.transform(data) # 降维转换
show_pic(pca_data, target, 'PCA')
# 2、LDA降维可视化
lda = LinearDiscriminantAnalysis(n_components=1).fit(data, target)
def show_pic(data, target, title):
if data.shape[1] == 1: # 如果数据只有一维
plt.scatter(data[:, 0], [0] * len(data), c=target) # 使用0作为所有点的第二维度的占位符
plt.title(title)
plt.xlabel("LD1")
plt.yticks([]) # 移除y轴的刻度
else:
plt.scatter(data[:, 0], data[:, 1], c=target)
plt.title(title)
plt.show()
lda_data = lda.transform(data) # 降维转换
show_pic(lda_data, target, 'LDA')
# 3、TSNE降维可视化(计算复杂度高,较慢)
print(' t-SNE降维中,请耐心等待......')
start = time() # 开始时间
tsne = TSNE(n_components=2, init='pca', random_state=0)
tsne_data = tsne.fit_transform(data)
end = time() # 完成时间
show_pic(tsne_data, target, 't-SNE (cost {:.1f} seconds)'.format(end-start))
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
# 评估三种算法降维后(均降成2维)的分类准确性(基于KNN算法)
def eval_model(new_data, target, label):
X_train, X_test, y_train, y_test = train_test_split(new_data, target, random_state=0) # 拆分数据集
model = KNeighborsClassifier(3).fit(X_train, y_train)
score = model.score(X_test, y_test) # 在测试集上评估模型成绩
print(label, score) # 打印模型成绩
print('titanic数据集降成2维后,使用K-NN分类准确性对比:')
eval_model(pca_data, target, 'PCA accuracy:')
eval_model(lda_data, target, 'LDA accuracy:')
eval_model(tsne_data, target, 't-SNE accuracy:')
3.4 实验结果
参考连接
[1]基于t-SNE的Digits数据集降维与可视化
[2]t-SNE完整笔记