Yizhong's Blog

使用t-SNE可视化高维数据

在机器学习的问题中,高维变量是非常常见的,他们对于机器来讲很容易计算,但是对于人来说,看起来就非常痛苦了。所以,有很多给数据降维的手段,比如PCA,LDA等。t-SNE也是其中的一种,但它属于非线性降维,所以t-SNE降维的主要作用貌似只能用来数据可视化和分析数据,并不能进一步作为feature来使用。但瑕不掩瑜,它的可视化效果是非常好的,学习起来也并不难。

t-SNE是从SNE演化来的,他们都采用了将空间中的距离转换为概率的方式来表示点与点之间的相似度,然后求高维空间和低维空间的概率分布的KL Divergence作为两个分布的距离,希望最小化这个距离函数。SNE中对于高维和低维空间都使用高斯分布来建模,但是会造成“拥挤问题”,也就是最后低维空间中的数据点会聚集在一起。所以t-SNE使用了t分布来定义低维空间中点的相似性。具体的原理在Laurens van der Maaten视频讲解里讲的特别清楚,可以花半个多小时的时间看一下。另外,这篇中文博文讲的也不错, 还给出了手工实现的代码,可以学习一个。

但是这里我们并不打算自己造轮子,Python的scikit-learn包已经支持了t-SNE工具,很方便调用,使用近似算法可以将复杂度降低到O(nlogn),下面我们用这个工具对MNIST数据集进行一个可视化的实验,来看看它究竟效果如何。

首先,import相关的包,并且加载MNIST数据集:

import numpy as np
import matplotlib.pyplot as plt
from time import time
from sklearn import datasets, manifold

然后,我们先定义好画图的函数,使之能将二维的embedding显示出来:

# Scale and visualize the embedding vectors                            
def plot_embedding(X, title=None):     
    x_min, x_max = np.min(X, 0), np.max(X, 0)
    X = (X - x_min) / (x_max - x_min)                           

    plt.figure()              
    ax = plt.subplot(111)      
    for i in range(X.shape[0]):                          
        plt.text(X[i, 0], X[i, 1], str(digits.target[i]),    
                 color=plt.cm.Set1(y[i] / 10.),         
                 fontdict={'weight': 'bold', 'size': 9})
    plt.xticks([]), plt.yticks([])
    if title is not None:
        plt.title(title)

最后,我们调用t-SNE工具包,将数据降维后进行绘制:

# t-SNE embedding of the digits dataset
print("Computing t-SNE embedding")           
tsne = manifold.TSNE(n_components=2, init='pca', random_state=0)
t0 = time()
X_tsne = tsne.fit_transform(X)

plot_embedding(X_tsne,                                   
            "t-SNE embedding of the digits (time %.2fs)" %
            (time() - t0))                           

plt.show() 

绘制的图表如下:

t-SNE image

可以看到,对于1083个64维的数据点,共花费了6.39秒的时间进行训练,时间还是很慢的。但是,分类的效果特别好,相同的digit基本都聚集在了一起。

script>