数据降维-MDS 算法
文章目录
- 数据降维-MDS 算法
- 算法概述
- 算法步骤
- 算法证明
- 代码
- 参考
算法概述
MDS的初衷是将图结构中的距离在空间的一种表示。
例如,已知几个城市的距离,但是不知道城市的坐标,那么MDS就能通过距离矩阵转换成空间坐标向量来近似描述距离。更重要地是,MDS可以更广泛地应用于任意类型的数据实体相似度或距离描述在低维空间的表示。
多维尺度分析MDS的基本思想:
用低维空间 R k R^k Rk ( k < n ) (k<n) (k<n)的n个点去重新标度高维空间 R n R^n Rn的n个实体间的距离或者相似度。将高维空间的n个研究对象简化到低维空间处理,并且保留高维空间中的n个对象的较高的相似度。
算法步骤
- 输入D
- D的所有元素取原值的平方,得距离平方矩阵 Δ \Delta Δ
- 构造单位矩阵 E E E和全1矩阵 U U U
- 计算点积矩阵 S = − 1 / 2 ( E − U / n ) Δ ( E − U / n ) S=-1/2 (E - U/n)\Delta (E - U/n) S=−1/2(E−U/n)Δ(E−U/n)
- 对S进行特征分解 S = Q ∑ 2 Q T S = Q\sum^2 Q^T S=Q∑2QT
- 选取前k个最大的特征值的根号值 ∑ k \sum k ∑k和正交特征向量 Q k Qk Qk
- 降维表示 D k = ∑ k Q k T Dk = \sum_k Q^T_k Dk=∑kQkT
算法证明
M
D
S
MDS
MDS 是一种基于距离度量的数据降维方法,要求将高维度数据$X \ \in R^(d \times m)
转化为低维数据
转化为低维数据
转化为低维数据Z \in R^{(d \times m)} $后,样本点间相对位置关系不变。所以将目标函数(也可以理解为相似度):
a
i
m
=
∑
m
i
n
(
∣
∣
z
i
−
z
j
∣
∣
−
d
i
j
)
2
aim = \sum_{min} (||z_{i} - z_{j}|| - d_{ij})^2
aim=min∑(∣∣zi−zj∣∣−dij)2
在上式子中,低维样本
z
i
z_i
zi与
z
j
z_j
zj之间的欧式距离。
d
i
j
d_{ij}
dij表示高维样本
X
i
X_i
Xi与
X
j
X_j
Xj之间的距离,距离的度量方法任意但需要满足以下三个条件:
- d i i = 0 d_{ii} = 0 dii=0
- d i j = d j i d_{ij} = d_{ji} dij=dji
- d i k + d j k ≥ d i j d_{ik} + d_{jk} \geq d_{ij} dik+djk≥dij
如何通过上面的目标函数求解出 Z Z Z。
直接求解出Z比较困难,转而求 B = Z T Z B = Z^TZ B=ZTZ
Z ∈ R d ′ × m Z \in R^{d' \times m} Z∈Rd′×m
B ∈ R m × m B \in R^{m\times m} B∈Rm×m
这里B是一个实对称矩阵,如果能够求得B,那么:
B
=
U
Λ
U
T
=
(
Λ
1
2
U
T
)
T
(
Λ
1
2
U
T
)
=
Z
T
Z
B = U \Lambda U^T = (\Lambda^{\frac{1}{2}} U^T)^T (\Lambda^{\frac{1}{2}U^T}) = Z^TZ
B=UΛUT=(Λ21UT)T(Λ21UT)=ZTZ
其中
U
U
U是特征向量,
Λ
\Lambda
Λ是特征值。
在对所求目标进行转化后,并求出以下等式
下面我们来对每一步等式做证明:
证明得到上述的等式后,我们可以根据多项式进行求解B:
到这里已经求得了特征值和特征向量。后面要做的就是对求取的Z做SVD分解,这部分的原理可以参考SVD 理解使用。
代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn.manifold import MDS
def getData():
data = np.loadtxt("./iris.data", dtype="str", delimiter=",")
arr = data[:,:-1]
label = data[:,-1]
arr = np.float32(arr)
return arr, label
def cal_distance(vecs, type = 0):
N, m = vecs.shape
dist = np.zeros([N, N])
for i in range(N):
for j in range(N):
# 计算汉明距离
# dist[i, j] = np.sum( np.abs(vecs[i] - vecs[j]))
# 计算欧式距离
dist[i, j] = np.sqrt(np.sum( (vecs[i] - vecs[j]) ** 2))
return dist
def my_mds(D, dims):
m = len(D)
D = D ** 2
t2 = np.sum(D, axis=1, keepdims=True) / m
t3 = np.sum(D, axis=0, keepdims=True) / m
t4 = np.sum(D) / m**2
B = - (D - t2 - t3 + t4) / 2
eig_val, eig_vector = np.linalg.eig(B)
index_ = np.argsort(-eig_val)[:dims]
simple_vector = eig_vector[:,index_]
simple_val = eig_val[index_]
reduced_vector = simple_vector * simple_val ** 0.5
return reduced_vector
def draw(data_2d, labels):
unque_labs = np.unique(labels)
unque_labs = unque_labs.tolist()
colors = [plt.cm.Spectral(each)
for each in np.linspace(0, 1,len(unque_labs))]
nodes_color = [colors[unque_labs.index(i)] for i in labels]
plt.scatter(data_2d[:,0], data_2d[:,1], c=nodes_color)
if __name__ == '__main__':
arr, label = getData()
dist = cal_distance(arr)
data_2d = my_mds(dist, 2)
draw(data_2d, label)
plt.show()
plt.savefig("./欧式距离.png")
其中用到的数据集是:
运行结果:
参考
- https://blog.csdn.net/ZHT2016iot/article/details/115772127
- 矩阵分解
- 矩阵特征值和特征向量