t-分布邻域嵌入算法(t-SNE algorithm)简单理解
来源:互联网 发布:dota2网络连接超时 编辑:程序博客网 时间:2024/06/06 09:42
这篇文章主要介绍一个有效的数据降维的方法 t-SNE.
大数据时代,数据量不仅急剧膨胀,数据也变得越来越复杂,数据的维度也随之增加。比如大图片,数据维度指的是像素的数量级,范围从数千到数百万。计算机可以处理任意多维的数据集,但我们人类认知只局限于3维空间,计算机依然需要我们(值得庆幸的),所以需要通过一些方法有效的可视化高维数据。通过观察现实世界的数据集发现其存在一些较低的本征维度。想像一下你拿着相机在拍照,可以把每张图片认为是16,000,000维空间的点(假设相机是16像素的),但是这些照片是近似分布在三维空间,这个低维空间使用一个复杂的、非线性的方法嵌入到高维空间,这种结构隐藏在数据中,只有通过一定的数学分析方法还原。
这里讲到的是流行学习方法,也可以说非线性降维方法,ML的一个分支(更具体的说,是非监督学习)。这篇文章主要讲到一个流行的数据降维的方法t-SNE,由Laurens vander Maaten和 Geoffrey Hinton提出(原文章).算法成功的应用于很多真实数据集。这里根据原文的思想处理手写数字识别库mnist,使用Python和scikit-learn .
可视化mnist
首先import一些libraries。
import numpy as npfrom numpy import linalgfrom numpy.linalg import normfrom scipy.spatial.distance import squareform, pdist
- 1
- 2
- 3
- 4
再import sklearn
import sklearnfrom sklearn.manifold import TSNEfrom sklearn.datasets import load_digitsfrom sklearn.preprocessing import scalefrom sklearn.metrics.pairwise import pairwise_distancesfrom sklearn.manifold.t_sne import (_joint_probabilities, _kl_divergence)from sklearn.utils.extmath import _ravel
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
随机状态值
RS = 20150101
- 1
使用图形库matplotlib
import matplotlib.pyplot as pltimport matplotlib.patheffects as PathEffectsimport matplotlib%matplotlib inline
- 1
- 2
- 3
- 4
使用seaborn更好绘制图
import seaborn as snssns.set_style('darkgrid')sns.set_palette('muted')sns.set_context("notebook", font_scale=1.5, rc={"lines.linewidth": 2.5})
- 1
- 2
- 3
- 4
- 5
使用matplotlib 和 moviepy生成动画
from moviepy.video.io.bindings import mplfig_to_npimageimport moviepy.editor as mpy
- 1
- 2
加载手写数字识别库,共有1797张图片,每张大小8X8
digits = load_digits()digits.data.shapeprint(digits['DESCR'])
- 1
- 2
- 3
Data Set Characteristics:
:Number of Instances: 5620
:Number of Attributes: 64
:Attribute Information: 8x8 image of integer pixels in the range 0..16.
:Missing Attribute Values: None
nrows, ncols = 2, 5plt.figure(figsize=(6,3))plt.gray()for i in range(ncols * nrows): ax = plt.subplot(nrows, ncols, i + 1) ax.matshow(digits.images[i,...]) plt.xticks([]); plt.yticks([]) plt.title(digits.target[i])plt.savefig('images/digits-generated.png', dpi=150)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
现在运行t-SNE算法:
X = np.vstack([digits.data[digits.target==i] for i in range(10)])y = np.hstack([digits.target[digits.target==i] for i in range(10)])digits_proj = TSNE(random_state=RS).fit_transform(X)
- 1
- 2
- 3
- 4
- 5
下面是一个显示转换后数据集的函数
def scatter(x, colors): # We choose a color palette with seaborn. palette = np.array(sns.color_palette("hls", 10)) # We create a scatter plot. f = plt.figure(figsize=(8, 8)) ax = plt.subplot(aspect='equal') sc = ax.scatter(x[:,0], x[:,1], lw=0, s=40, c=palette[colors.astype(np.int)]) plt.xlim(-25, 25) plt.ylim(-25, 25) ax.axis('off') ax.axis('tight') # We add the labels for each digit. txts = [] for i in range(10): # Position of each label. xtext, ytext = np.median(x[colors == i, :], axis=0) txt = ax.text(xtext, ytext, str(i), fontsize=24) txt.set_path_effects([ PathEffects.Stroke(linewidth=5, foreground="w"), PathEffects.Normal()]) txts.append(txt) return f, ax, sc, txts
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
结果:
scatter(digits_proj, y)plt.savefig('images/digits_tsne-generated.png', dpi=120)
- 1
- 2
不同颜色的点代表不同的数字,可以观察到相同的数字被清晰的分到不同的聚集区域.
数学框架
下面介绍算法的工作原理。首先,介绍几个定义:
数据点X_i分布在原始数据空间R^D,数据空间的维度为D=64,每个点代表手写数字识别库中的每张图片。总共有N=1797个点。
映射点y_i在映射空间R^2,映射空间是我们对数据的最终表达。数据点和映射点之间存在双射关系,一个映射点表示一张原始图片。
我们该怎样选择映射点的位置呢?如果两个数据点距离比较近,我们希望对应的两个映射点的位置也相对比较接近。另|x_i−x_j|计算两个数据点间的欧式距离,|y_i−y_j| 表示映射点的距离。首先定义两数据点间的条件相似性:
公式度量了x_i与x_j的距离,σ_i^2为满足高斯分布的x_i的方差。原文详细讲解方差的计算,这里不再写。
现在定义相似度:
我们从原始图像获得一个相似矩阵,这个矩阵是怎样的呢?
相似矩阵
下面的函数定义了计算相似矩阵函数,常量 σ:
def _joint_probabilities_constant_sigma(D, sigma): P = np.exp(-D**2/2 * sigma**2) P /= np.sum(P, axis=1) return P# Pairwise distances between all data points.D = pairwise_distances(X, squared=True)# Similarity with constant sigma.P_constant = _joint_probabilities_constant_sigma(D, .002)# Similarity with variable sigma.P_binary = _joint_probabilities(D, 30., False)# The output of this function needs to be reshaped to a square matrix.P_binary_s = squareform(P_binary)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
现在可以显示数据点的距离阵:
plt.figure(figsize=(12, 4))pal = sns.light_palette("blue", as_cmap=True)plt.subplot(131)plt.imshow(D[::10, ::10], interpolation='none', cmap=pal)plt.axis('off')plt.title("Distance matrix", fontdict={'fontsize': 16})plt.subplot(132)plt.imshow(P_constant[::10, ::10], interpolation='none', cmap=pal)plt.axis('off')plt.title("$p_</span>{j|i}$ (constant $\sigma$)", fontdict={'fontsize': 16})plt.subplot(133)plt.imshow(P_binary_s[::10, ::10], interpolation='none', cmap=pal)plt.axis('off')plt.title("$p_</span>{j|i}$ (variable $\sigma$)", fontdict={'fontsize': 16})plt.savefig('images/similarity-generated.png', dpi=120)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
接下来定义映射点的相似矩阵:
pij和qij足够的接近,即达到使数据点和映射点足够接近的目的。
结构分析
如果两个映射点距离较远但是数据点较近,他们会相互吸引,当两个映射点较远数据点较近,他们会排斥。当达到平衡时获得最后的映射。下面的插图展示了这一特点:
算法
以上物理的类比来源于数学的算法,最小化两个分布的 Kullback-Leiber发散程度:
这里度量了两个相似矩阵的距离。
使用梯度下降最优化结果:
u_ij对应于y_j到y_i的向量,梯度表达的是作用在映射节点i上的所有弹缩力的和。
# This list will contain the positions of the map points at every iteration.positions = []def _gradient_descent(objective, p0, it, n_iter, n_iter_without_progress=30, momentum=0.5, learning_rate=1000.0, min_gain=0.01, min_grad_norm=1e-7, min_error_diff=1e-7, verbose=0, args=[]): # The documentation of this function can be found in scikit-learn's code. p = p0.copy().ravel() update = np.zeros_like(p) gains = np.ones_like(p) error = np.finfo(np.float).max best_error = np.finfo(np.float).max best_iter = 0 for i in range(it, n_iter): # We save the current position. positions.append(p.copy()) new_error, grad = objective(p, *args) error_diff = np.abs(new_error - error) error = new_error grad_norm = linalg.norm(grad) if error < best_error: best_error = error best_iter = i elif i - best_iter > n_iter_without_progress: break if min_grad_norm >= grad_norm: break if min_error_diff >= error_diff: break inc = update * grad >= 0.0 dec = np.invert(inc) gains[inc] += 0.05 gains[dec] *= 0.95 np.clip(gains, min_gain, np.inf) grad *= gains update = momentum * update - learning_rate * grad p += update return p, error, isklearn.manifold.t_sne._gradient_descent = _gradient_descent
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
<link rel="stylesheet" href="http://csdnimg.cn/release/phoenix/production/markdown_views-d4dade9c33.css"> </div>
- t-分布邻域嵌入算法(t-SNE algorithm)简单理解
- t-分布邻域嵌入算法(t-SNE algorithm)简单理解
- 诠释数据降维算法:一文讲尽t-分布邻域嵌入算法(t-SNE)如何有效利用
- 诠释数据降维算法:一文讲尽t-分布邻域嵌入算法(t-SNE)如何有效利用
- 理解 t-SNE (Python)
- t-SNE理解
- t-SNE
- t-SNE
- (R/Python)t-SNE聚类算法实践指南
- 使用 t-SNE算法和JavaScript语言可视化Visualizing Top Tweeps with t-SNE, in Javascript
- t-SNE介绍
- t-SNE初学
- t-SNE详细介绍
- t-SNE学习笔记
- Visualizing with t-SNE
- [机器学习]t-SNE聚类算法实践指南
- 非常好的t-SNE介绍
- t-SNE高维数据可视化(python)
- FPGA基础实验:用计数器读取ROM数据产生信号波形(直接数字频率合成DDS)
- 计算机硬件--笔记
- 内存管理
- C语言位运算符
- Eclipse Maven "Create a simple project" 没有web.xml文件
- t-分布邻域嵌入算法(t-SNE algorithm)简单理解
- 解决在Android 7.0上PopupWindow.showAsDropDown不起作用
- 笔记:对numpy中shape的理解
- >mysql -uroot -p Enter password: ERROR 1045 (28000): Access denied ,被mysql连接问题折磨到问题解决,分享
- 浅谈ES6新特性
- 台湾大学深度学习课程 学习笔记 lecture1-2 Neural Network Basics
- 汇编 in out的用法示例
- 哈尔滨理工大学第七届程序设计竞赛决赛(网络赛-高年级组)B题幸运大奖
- cuda dirver API总结