isomap算法主要流程:
1:构建邻接图G:基于输入空间X中流形G上的的邻近点对i,j之间的欧式距离dx (i,j),选取每个样本点距离最近的K个点(K-Isomap)或在样本点选定半径为常数ε的圆内所有点为该样本点的近邻点,将这些邻近点用边连接,将流形G构建为一个反映邻近关系的带权流通图G;
2:计算所有点对之间的最短路径:通过计算邻接图G上任意两点之间的最短路径逼近流形上的测地距离矩阵DG={dG(i,j)},最短路径的实现以Floyd或者Dijkstra算法为主。
3:构建k维坐标向量:根据图距离矩阵DG={dG(i,j)}使用经典Mds算法在d维空间Y中构造数据的嵌入坐标表示,选择低维空间Y的任意两个嵌入坐标向量yi与yj使得代价函数最小。
下面是python实现的代码:
import numpy as np
import matplotlib.pyplot as plt
import sys
def distancematrix(test):
leng=len(test)
resmat=np.zeros([leng,leng],np.float32)
for i in range(leng):
for j in range(leng):
resmat[i,j]=np.linalg.norm(test[i]-test[j])
return resmat #返回距离矩阵
def mds(test,deg):
length= len(test)
re= np.zeros((length, length),np.float32)
if(deg>length):
deg=length
D= distancematrix(test)
ss = 1.0 /length ** 2 * np.sum(D ** 2)
for i in range(length):
for j in range(length):
re[i, j] = -0.5 * (D[i, j] ** 2 - 1.0 / length * np.dot(D[i, :], D[i, :]) - 1.0 / length * np.dot(D[:, j], D[:, j]) + ss)
A, V = np.linalg.eig(re)
list_idx = np.argpartition(A, deg- 1)[-deg:]
a = np.diag(np.maximum(A[list_idx], 0.0))
return np.matmul(V[:, list_idx], np.sqrt(a))
# 使用 Dijkstra 算法获取最短路径,并更新距离矩阵
# test: 距离矩阵,大小 m * m
# start:最短路径的起始点,范围 0 到 m-1
def usedijk(test, start):
count = len(test)
col= test[start].copy()
rem = count - 1
while rem > 0:
i= np.argpartition(col, 1)[1]
length = test[start][i]
for j in range(count):
if test[start][j] > length + test[i][j]:
test[start][j] = length + test[i][j]
test[j][start] = test[start][j]
rem -= 1
col[i] = float('inf')
# isomap 算法的具体实现
# test:需要降维的矩阵
# target:目标维度
# k:k 近邻算法中的超参数
# return:降维后的矩阵
def isomap(test, target, k):
inf = float('inf')
count = len(test)
if k >= count:
raise ValueError('K is too large')
mat_distance = distancematrix(test)
knear = np.ones([count, count], np.float32) * inf
for idx in range(count):
topk = np.argpartition(mat_distance[idx], k)[:k + 1]
knear[idx][topk] = mat_distance[idx][topk]
for idx in range(count):
usedijk(knear, idx)
return mds(knear, target)
if __name__ == '__main__':
print('开始降维.....')
D =np.array([[1,2,3,4],[2,1,5,6],[3,5,1,7],[4,6,7,1]]) #test data
outcome= isomap(D, 2, 3)
sys.stdout.write('降维完成\n')
print(outcome)