为什么更大的困惑往往会在 t-SNE 中产生更清晰的集群?

机器算法验证 聚类 降维 特纳 困惑
2022-03-31 23:36:19

为什么更大的困惑往往会在 t-SNE 中产生更清晰的集群?

通过阅读原始论文,我了解到 t-SNE 中的困惑度是数据点诱导的条件分布的香农熵的并且在论文中提到,它可以解释为对有效邻居数的平滑度量。2

如果一个数据点的条件分布是由高斯分布(SNE)构造的,那么方差越大,香农熵越大,因此困惑度越大。σ2

所以,我建立的直觉是:

困惑度越大,降维结果中保留的非局部信息就越多。

当我在我的两个测试数据集上使用 t-SNE 进行降维时,我观察到 t-SNE 找到的聚类会随着困惑度的增加而变得更加明确。虽然这是一个理想的结果,但我无法用我刚刚建立的直觉来解释这一点。

这是我的结果,用于生成图形的数据和脚本已上传到此处结果

除了我刚才提到的混乱之外,我也不知道如何解释结果。

Random dataset对于 t-SNE 更容易在then中找到定义明确的集群这一事实,可能的解释是Benchmark dataset什么?

2个回答

困惑度越大,降维结果中保留的非局部信息就越多。

是的,我相信这是一个正确的直觉。我认为 t-SNE 中的困惑参数的方式是它设置每个点被吸引到的邻居的有效数量。在 t-SNE 优化中,所有点对都相互排斥,但只有少数点对感受到吸引力。

因此,如果您的困惑度非常小,那么感受到任何吸引力的配对将会减少,并且由此产生的嵌入将趋于“蓬松”:排斥力将占主导地位并将整个嵌入膨胀成气泡状的圆形。

另一方面,如果你的困惑很大,集群往往会缩小成更密集的结构。

这是一个非常简单的解释,我必须说我从未见过对这种现象进行良好的数学分析(我怀疑这样的分析会很重要),但我认为它大致正确。


在模拟中看到它是有启发性的。在这里,我生成了一个数据集,其中包含六个 10 维高斯球(),它们彼此相距很远——到目前为止,即使对于困惑度 100,所有吸引力都在集群内。因此,对于 5 到 100 之间的困惑,如下所示,集群之间永远不存在任何吸引力。然而,人们可以清楚地看到,当困惑度增加时,集群会“缩小”。n=1000

在此处输入图像描述

事实上,一个人可以完全摆脱困惑,让每个点都对其最近的个邻居感到同样强烈的吸引力。这意味着我将高维空间中的高斯核替换为最近个邻居上的“均匀”核。这应该可以简化任何数学分析,并且可以说更直观。人们经常惊讶地发现,结果通常看起来与真实的 t-SNE非常相似。这是的各种值:KKK

在此处输入图像描述


代码

%matplotlib notebook

import numpy as np
import pylab as plt
import seaborn as sns

sns.set_style('ticks')

# https://github.com/KlugerLab/FIt-SNE
import sys; sys.path.append('/home/localadmin/github/FIt-SNE')
from fast_tsne import fast_tsne

col = np.array(['#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99',
                '#e31a1c','#fdbf6f','#ff7f00','#cab2d6','#6a3d9a'])

n = 1000  # sample size per class
p = 10    # dimensionality
k = 6     # number of classes
d = 10    # distance between each class mean and 0

np.random.seed(42)
X = np.random.randn(k*n, p)
for i in range(k):
    X[i*n:(i+1)*n, i] += d

perpl = [5, 30, 100]
Z1 = []
for p in perpl:
    Z = fast_tsne(X, perplexity=p, seed=42)
    Z1.append(Z)

ks = [5, 30, 100]
Z2 = []
for kk in ks:
    Z = fast_tsne(X, K=kk, sigma=10000, seed=42)
    Z2.append(Z)


fig = plt.figure(figsize=(7, 3))

for i,Z in enumerate(Z1):
    plt.subplot(1,3,i+1)
    plt.axis('equal', adjustable='box')
    plt.scatter(Z[:,0], Z[:,1], s=1, c=col[np.floor(np.arange(n*k)/n).astype(int)])
    plt.title('Perplexity {}'.format(perpl[i]))
    plt.gca().get_xaxis().set_visible(False)
    plt.gca().get_yaxis().set_visible(False)

sns.despine(left=True, bottom=True)
plt.tight_layout()


fig = plt.figure(figsize=(7, 3))

for i,Z in enumerate(Z2):
    plt.subplot(1,3,i+1)
    plt.axis('equal', adjustable='box')
    plt.scatter(Z[:,0], Z[:,1], s=1, c=col[np.floor(np.arange(n*k)/n).astype(int)])
    plt.title('K = {}'.format(perpl[i]))
    plt.gca().get_xaxis().set_visible(False)
    plt.gca().get_yaxis().set_visible(False)

sns.despine(left=True, bottom=True)
plt.tight_layout()

我相信这是因为输入(高斯)和输出(学生-t)分布之间的 t-SNE不匹配制作这样的斑点是有益的,以便根据 t 分布的长尾要求与其他一切分开。排斥力占主导地位。

在这种情况下,SNE 可能会更好地工作。你有没有尝试过?