sklearn.manifold.TSNE相同输入向量输出不同的问题咨询
问题分析与解决方案
这个问题我之前也碰到过,核心是你给TSNE设置的参数踩了坑,导致相同输入向量输出不一致的异常情况,咱们一步步拆解:
为什么会出现这种奇怪的情况?
1. Perplexity参数严重不合理
TSNE的perplexity是控制每个样本近邻数量的关键参数,官方明确推荐的范围是5到50。你设置的perplexity=0.666666远低于最小值,这会直接搞乱TSNE的概率计算逻辑:
- 低到离谱的perplexity会让算法给每个样本分配的近邻数量极少,对于完全重复的向量,条件概率的计算会出现数值不稳定的情况,直接打破了“相同输入应该对应相同输出”的隐含规则。
- 这种情况下,即使你固定了
random_state,优化过程的梯度也会变得极其混乱,很容易因为浮点数计算的微小偏差,让相同向量的最终输出分道扬镳。
2. 低perplexity下的初始化扰动
虽然你用了init='pca'和固定随机种子,但在perplexity不合理的前提下,PCA初始化后的优化过程中,重复向量的梯度计算会出现异常波动,最终导致输出分离。
怎么解决这个问题?
方法1:把Perplexity调到合理范围
这是最直接有效的方案,把perplexity设置到官方推荐的5-50区间里,你的数据集只有9个样本,选个偏小的合理值比如5就可以。修改后的代码如下:
from sklearn import manifold import numpy as np X= np.array([ [2, 1, 3, 5], [2, 1, 3, 5], [2, 1, 3, 5], [2, 1, 3, 5], [12, 1, 3, 5], [87, 22, 3, 5], [3, 23, 9, 5], [43, 87, 3, 5], [121, 65, 3, 5]]) m = manifold.TSNE( n_components=2, perplexity=5, # 调整到合理范围 verbose=0, random_state=42, angle=.99, init='pca', metric='cosine', n_iter=1000) X_embedded = m.fit_transform(X) # 用np.allclose判断浮点数近似相等,避免精度问题 assert(np.allclose(X_embedded[0], X_embedded[1])) assert(np.allclose(X_embedded[1], X_embedded[2]))
这里用np.allclose代替直接判断差值为0,是因为浮点数计算总会有微小的精度误差,直接判断等于0容易误判。
方法2:手动处理重复向量(迫不得已时用)
如果因为业务需求必须用这么低的perplexity,那可以先对输入向量去重,只给唯一向量做TSNE映射,再把结果还原回原始的重复向量:
# 获取唯一向量和原始索引映射 unique_X, inverse_indices = np.unique(X, axis=0, return_inverse=True) # 仅对唯一向量执行TSNE m = manifold.TSNE( n_components=2, perplexity=0.666666, verbose=0, random_state=42, angle=.99, init='pca', metric='cosine', n_iter=1000) unique_embedded = m.fit_transform(unique_X) # 把映射结果还原到原始数组 X_embedded = unique_embedded[inverse_indices] # 现在重复向量的输出完全一致 assert(np.allclose(X_embedded[0], X_embedded[1])) assert(np.allclose(X_embedded[1], X_embedded[2]))
方法3:增加迭代次数(辅助缓解)
低perplexity下,优化过程需要更多迭代才能稳定,你可以尝试把n_iter调大到5000甚至更高,但这只是缓解手段,没法从根本上解决perplexity不合理带来的数值问题。
总结
你的问题本质是perplexity参数设置严重超出合理范围导致的异常行为,把它调到5-50之间后,相同输入向量就能得到几乎一致的输出(考虑浮点数精度)。如果必须用低perplexity,手动去重后再映射是最可靠的办法。
内容的提问来源于stack exchange,提问作者Samer Aamar
相关产品推荐
相关产品推荐

