1.MDS算法简介
多维缩放(Multiple Dimensional Scaling,MDS)算法的的中心思想可以用一句话概括——要求原始空间中样本之间的距离(无特加说明的情况下,默认为欧氏距离)在低维空间得以保持。对于大多数聚类算法来说,距离是将样本分类的重要属性,因此当我们降维后,保持距离不变,那么就相当于保持了样本的相对空间关系不变。
MDS算法可以缓解在高维情况下出现的样本数据稀疏和距离计算困难等问题,与主成分分析法和线性降维分析法都不同的是,MDS的目标不是保留数据的最大可分性,而是更加关注与高维数据内部的特征。
MDS算法共有两类:度量算法和非度量算法,在 scikit-learn 中,MDS类具有两者的实现模块。在度量 MDS 中,输入相似度矩阵源自度量(并因此遵从三角形不等式),输出两点之间的距离被设置为尽可能接近相似度或相异度的数据;在非度量版本中,算法尝试保持距离的控制,并因此寻找在所嵌入空间中的距离和相似/相异之间的单调关系。
2.枯燥又简洁的理论推导
MDS算法的思想很巧妙,通过利用对点(数据)做平移、旋转、翻转等操作,点的距离是不变的这一特性来对原始数据进行操作。
此处对鲁迅先生的“拿来主义”贬义褒用,小编“拿来”周志华老师的《机器学习》理论推导过程双手奉上。
3.MDS算法优缺点
优点:
(1) 不需要先验知识,计算简单;
(2) 保留了数据在原始空间的相对关系,可视化效果比较好。
缺点:
(1) 如果用户对观测对象有一定的先验知识,掌握了数据的一些特征,却无法通过参数化等方法对处理过程进行干预,可能会得不到预期的效果;
(2) 认为各个维度对目标的贡献相同,然而事实上有一些维度对目标的影响很小,有一些对目标是影响比较大。
4.python实战MDS(一)——鸢尾花数据集降维
降维专题写到了第三篇,又要请出万能的鸢尾花数据集来实现降维啦!
话不多说,上代码!
"""
MDS降维
"""
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets,manifold
def load_data():
'''
加载用于降维的数据
:return: 一个元组,依次为训练样本集和样本集的标记
'''
iris=datasets.load_iris()# 使用 scikit-learn 自带的 iris 数据集
return iris.data,iris.target
def test_MDS(*data):
'''
测试 MDS 的用法
:param data: 可变参数。它是一个元组,这里要求其元素依次为:训练样本集、训练样本的标记
'''
X,y=data
for n in [4,3,2,1]: # 依次考察降维目标为 4维、3维、2维、1维
mds=manifold.MDS(n_components=n)
mds.fit(X)
print('stress(n_components=%d) : %s'% (n, str(mds.stress_)))
def plot_MDS(*data):
'''
绘制经过 使用 MDS 降维到二维之后的样本点
:param data: 可变参数。它是一个元组,这里要求其元素依次为:训练样本集、训练样本的标记
'''
X,y=data
mds=manifold.MDS(n_components=2)
X_r=mds.fit_transform(X) #原始数据集转换到二维
### 绘制二维图形
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
colors=((1,0,0),(0,1,0),(0,0,1),(0.5,0.5,0),(0,0.5,0.5),(0.5,0,0.5),
(0.4,0.6,0),(0.6,0.4,0),(0,0.6,0.4),(0.5,0.3,0.2),)# 颜色集合,不同标记的样本染不同的颜色
for label ,color in zip( np.unique(y),colors):
position=y==label
ax.scatter(X_r[position,0],X_r[position,1],label="target= %d"%label,color=color)
ax.set_xlabel("X[0]")
ax.set_ylabel("X[1]")
ax.legend(loc="best")
ax.set_title("MDS")
plt.show()
if __name__=='__main__':
X,y=load_data() # 产生用于降维的数据集
test_MDS(X,y) # 调用 test_MDS
plot_MDS(X,y) # 调用 plot_MDS
当数据集降到不同维度时,输出为:
stress(n_components=4) : 11.853476605734173
stress(n_components=3) : 18.990835625762944
stress(n_components=2) : 135.5269312059442
stress(n_components=1) : 23671.908296829653
将降维后的二维数据点可视化:
5.python实战MDS(二)——度量MDS和非度量MDS
在本文开头介绍过,MDS算法除了是一种非常有效的降维和特征筛选工具之外,也是一种行之有效的高维数据点可视化工具。以下实例选自scikit-learn官方文档,在可视化的基础之上,讨论了度量MDS和非度量MDS的区别(为了避免图像重叠,在绘制图像的过程中对点稍作偏移)。
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.collections import LineCollection
from sklearn import manifold
from sklearn.metrics import euclidean_distances
from sklearn.decomposition import PCA
EPSILON = np.finfo(np.float32).eps
n_samples = 20
seed = np.random.RandomState(seed=3)
X_true = seed.randint(0, 20, 2 * n_samples).astype(np.float)
X_true = X_true.reshape((n_samples, 2))
# 将数据中心化
X_true -= X_true.mean()
similarities = euclidean_distances(X_true)
# 添加噪声
noise = np.random.rand(n_samples, n_samples)
noise = noise + noise.T
noise[np.arange(noise.shape[0]), np.arange(noise.shape[0])] = 0
similarities += noise
mds = manifold.MDS(n_components=2, max_iter=3000, eps=1e-9, random_state=seed,
dissimilarity="precomputed", n_jobs=1)
pos = mds.fit(similarities).embedding_
nmds = manifold.MDS(n_components=2, metric=False, max_iter=3000, eps=1e-12,
dissimilarity="precomputed", random_state=seed, n_jobs=1,
n_init=1)
npos = nmds.fit_transform(similarities, init=pos)
# 将数据集缩放
pos *= np.sqrt((X_true ** 2).sum()) / np.sqrt((pos ** 2).sum())
npos *= np.sqrt((X_true ** 2).sum()) / np.sqrt((npos ** 2).sum())
# 旋转数据集
clf = PCA(n_components=2)
X_true = clf.fit_transform(X_true)
pos = clf.fit_transform(pos)
npos = clf.fit_transform(npos)
fig = plt.figure(1)
ax = plt.axes([0., 0., 1., 1.])
s = 100
plt.scatter(X_true[:, 0], X_true[:, 1], color='navy', s=s, lw=0,
label='True Position')
plt.scatter(pos[:, 0], pos[:, 1], color='turquoise', s=s, lw=0, label='MDS')
plt.scatter(npos[:, 0], npos[:, 1], color='darkorange', s=s, lw=0, label='NMDS')
plt.legend(scatterpoints=1, loc='best', shadow=False)
similarities = similarities.max() / (similarities + EPSILON) * 100
np.fill_diagonal(similarities, 0)
# 规定作图边界
start_idx, end_idx = np.where(pos)
# 连线
segments = [[X_true[i, :], X_true[j, :]]
for i in range(len(pos)) for j in range(len(pos))]
values = np.abs(similarities)
lc = LineCollection(segments,
zorder=0, cmap=plt.cm.Blues,
norm=plt.Normalize(0, values.max()))
lc.set_array(similarities.flatten())
lc.set_linewidths(np.full(len(segments), 0.5))
ax.add_collection(lc)
plt.show()
输出结果为:
除此之外,还可利用MDS算法根据城市之间的距离还原地图、对词向量低维可视化等,感兴趣的读者可以查阅相关资料继续深入学习。
6.下篇预告
下一篇,降维继续走起——
sklearn与机器学习系列专题之降维(四)一文弄懂SVD特征筛选&降维
敬请期待!
欢迎关注公众号“码点联盟”,不定期分享机器学习、深度学习干货,及各种资料大礼包!
另外,这是一个由一线互联网大厂算法工程师及双985研究生创建的公众号,后续会经常分享各类实用机器学习算法技术文章,欢迎交流讨论!