一、谱聚类原理及思想
这里我引用网上一个大佬的文章,原理啥的都写的很详细!
二、算法流程
1、根据输入的相似矩阵(样本间的距离矩阵)构建样本的相似矩阵
2、根据相似矩阵构建邻接矩阵(实际上这两个矩阵相同),构建度矩阵
3、计算拉普拉斯矩阵后再构建标准化的拉普拉斯矩阵
D
−
1
/
2
L
D
−
1
/
2
D^{-1/2}LD^{-1/2}
D−1/2LD−1/2
4、计算
D
−
1
/
2
L
D
−
1
/
2
D^{-1/2}LD^{-1/2}
D−1/2LD−1/2最小的
k
1
k_1
k1个特征值所对应的各自特征向量
f
f
f
5、将各自对应的特征向量组成的矩阵按行标准化,最终成
n
×
k
1
n \times k_1
n×k1维的特征矩阵
F
F
F
6、使用K-means聚类方法进行聚类,聚类维数为
k
2
k_2
k2
7、给到聚类划分
三、python实现部分
from sklearn import datasets
import numpy as np
from sklearn.cluster import KMeans
from matplotlib import pyplot as plt
from itertools import cycle, islice
# 产生内圈和外圈的两个圆环数据集
def makeTwoCircles(n_sample):
x, label = datasets.make_circles(n_sample, factor=0.5, noise=0.05)
return x, label
# 计算两个坐标之间的欧氏距离
def distance(x1, x2):
res = np.sqrt(np.sum((x1 - x2) ** 2))
return res
# 计算数据之间的距离矩阵,分别计算一个坐标与其他坐标间的距离
def distanceMatrix(X):
M = np.array(X)
Z = np.zeros((len(M), len(M)))
for i in range(len(M)):
for j in range(i + 1, len(M)):
Z[i][j] = 1.0 * distance(X[i], X[j])
Z[j][i] = Z[i][j]
return Z
# 计算邻接矩阵,采用全连接法+高斯核函数
def adjacencyMatrix(Z, k, sigma=1.0):
N = len(Z)
A = np.zeros((N, N))
for i in range(N):
dist = zip(Z[i], range(N)) # 将Z矩阵的一行内的元素进行逐个标识下标(从小到大)
dist_index = sorted(dist, key=lambda x: x[0]) # 根据一行的元素进行从小到大排序
neibours_id = [dist_index[m][1] for m in range(k + 1)] # 挑出排序前11的元素的下标索引
for index in neibours_id:
A[i][index] = np.exp(-Z[i][index] / (2 * sigma * sigma))
A[index][i] = A[i][index]
return A
# 计算拉普拉斯矩阵及其特征矩阵
def laplacianMatrix(A):
# 计算度矩阵D
D = np.sum(A, axis=1)
# 计算拉普拉斯矩阵
L = np.diag(D) - A
# 计算标准化之后的拉普拉斯矩阵
squareD = np.diag(1.0 / (D ** (0.5)))
standardization_L = np.dot(np.dot(squareD, L), squareD)
# 计算标准化拉普拉斯矩阵的特征值和特征向量
x, V = np.linalg.eig(standardization_L)
# 将特征值进行排序
x = list(zip(x, range(len(x))))
x = sorted(x, key=lambda x: x[0])
# 按特征值排序后的索引将对应的特征向量重新组合
H = np.vstack(V[:, i] for (v, i) in x[:500]).T
return H
# 绘图函数
def plot(X, y_sp, y_km):
colors = np.array(list(islice(cycle(['#377eb8', '#ff7f00', '#4daf4a',
'#f781bf', '#a65628', '#984ea3',
'#999999', '#e41a1c', '#dede00']),
int(max(y_km) + 1))))
plt.subplot(121)
# 绘制散点图
plt.scatter(X[:, 0], X[:, 1], s=10, color=colors[y_sp])
plt.title("Spectral Clustering")
plt.subplot(122)
plt.scatter(X[:, 0], X[:, 1], s=10, color=colors[y_km])
plt.title("Kmeans Clustering")
plt.savefig(r"F:\DataBuilding\spectral_clustering.png")
plt.show()
if __name__ == '__main__':
data, label = makeTwoCircles(500)
print(np.shape(np.array(data)))
print(np.array(data)[2])
Z = distanceMatrix(data)
M = adjacencyMatrix(Z, 10)
H = laplacianMatrix(M)
# 谱聚类
sp_Kmeans = KMeans(n_clusters=3).fit(H)
# K-means聚类
kmeans = KMeans(n_clusters=3).fit(data)
print(sp_Kmeans.labels_, kmeans.labels_) # 标签
# 根据标签来填充散点的颜色,以达到标识分类效果
plot(data, sp_Kmeans.labels_, kmeans.labels_)
四、 聚类的效果图
由此可见谱聚类的效果要比k-means聚类效果好一点。