谱聚类(Iris)
写在前面
谱聚类原理推导实在是看了好久,也半懂不懂,目前的成果还要感谢多篇博客(太多了写懵了没记住都是哪个不好意思)
可能我的文里面还有错误,还有没解决的问题。
欢迎指出错误,有好理解的解释也欢迎评论教我一下,或者易懂的教程、文章、视频在评论区推荐一下~
难兄难弟互助,共同进步~
实验过程
谱聚类函数
# 谱聚类函数
import numpy as np
from kernels import *
# 这里用的是高斯核,可以换别的和,直接复用之前写kernel k-means的核函数文件
# 求关系矩阵W
def W_Matrix(m,dataset, createMatrix,kernel):
'''
对数据集dataset求关系矩阵,用的是kernel核函数
写在createMatrix里面
'''
for i in range(m):
x = dataset[i]
for j in range(m):
y = dataset[j]
createMatrix[i,j] = kernel(x,y) #计算的高斯核函数放入创建的空矩阵中
#createMatrix = createMatrix - np.identity(m) # np.identity()创建单位对角矩阵 // 生成对角线为0的矩阵
return createMatrix
'''
input:
dataset: iris.data 只包含样本的特征值,本实验中大小为150*4
number_cluster: 要分成的类别数,这里是3
num_lowerdim: 谱聚类本意上是降维处理,取L矩阵前k个特征值,这个参数就是这个k。(可惜iris数据集维度不大,不小心就升维了)
kernel: 在构造关系矩阵时,采用全连接方法,核函数可以改变用别的。
cluster_method: 最后对于特征矩阵行元素的聚类方法,这里用的时k-means,可以用别的。
'''
# 谱聚类主函数
def Spectral_Clustering(dataset,number_cluster,num_lowerdim,kernel,cluster_method):
# 创建空矩阵,用来装邻接矩阵W
createMatrix = np.zeros((dataset.shape[0],dataset.shape[0]))
# 通过高斯核求全连接的关系矩阵W
W=W_Matrix(dataset.shape[0],dataset,createMatrix,kernel)
# 对W矩阵每行相加,得到度矩阵D
sumD = []
for i in range(W.shape[0]):
sum = 0
for j in range(W.shape[1]):
sum +=W[i,j]
sumD.append(sum)
D = np.diag(sumD)
# L 拉普拉斯矩阵,等于度矩阵减邻接矩阵
L = D - W
# print(L)
# 求度矩阵的-1/2次,用来给L标准化
Dn = np.mat(np.diag(np.power(sumD,-0.5)))
#W = np.mat(W)
# 对L标准化
L = Dn*L*Dn
# 求L的特征值特征向量
eigvals, eigvecs = np.linalg.eig(L)
# 得到L的最小k个特征值对应的特征向量
k = num_lowerdim
indices = eigvals.argsort()[:k]
k_min_eigvecs = eigvecs[:,indices]
# 将对应的特征向量组成的矩阵按照行,标准化,得到n*k维的特征矩阵F
X = np.linalg.norm(k_min_eigvecs, axis=1)
Y = np.zeros((dataset.shape[0],k))
for i in range(dataset.shape[0]):
for j in range(k):
Y[i,j] = k_min_eigvecs[i,j]/X[i]
# print("特征向量单位化:", Y)
# 标准化的F矩阵,每一行作为一个k维样本,用k-means进行聚类,聚类维数为number_cluster
if cluster_method=='KMeans' :
from sklearn.cluster import KMeans
method = KMeans
NJW = method(n_clusters=number_cluster).fit_predict(k_min_eigvecs)
return NJW
谱聚类流程:
算法步骤
输入:样本集D=(x1,x2,…,xn)(x1,x2,…,xn),相似矩阵的生成方式, 降维后的维度k1k1, 聚类方法,聚类后的维度k2k2
输出: 簇划分C(c1,c2,…ck2)C(c1,c2,…ck2).
1) 根据输入的相似矩阵的生成方式构建样本的相似矩阵S
2)根据相似矩阵S构建邻接矩阵W,构建度矩阵D
3)计算出拉普拉斯矩阵L
4)构建标准化后的拉普拉斯矩阵L‘ = D−1/2LD−1/2D−1/2LD−1/2
5)计算D−1/2LD−1/2D−1/2LD−1/2最小的k1k1个特征值所各自对应的特征向量ff
6) 将各自对应的特征向量ff组成的矩阵按行标准化,最终组成n×k1n×k1维的特征矩阵F
7)对F中的每一行作为一个k1k1维的样本,共n个样本,用输入的聚类方法进行聚类,聚类维数为k2k2。
8)得到簇划分C(c1,c2,…ck2)C(c1,c2,…ck2).
转载自谱聚类(spectral clustering)原理总结 - 刘建平Pinard - 博客园 (cnblogs.com)
变量传递
原理很复杂,但是代码很简单:
D
(
样
本
)
→
W
(
邻
接
矩
阵
)
→
D
(
度
矩
阵
)
→
L
→
L
′
→
f
i
→
F
→
C
D(样本)\rightarrow W(邻接矩阵)\rightarrow D(度矩阵)\rightarrow L\rightarrow L'\rightarrow f_i\rightarrow F\rightarrow C
D(样本)→W(邻接矩阵)→D(度矩阵)→L→L′→fi→F→C
主要函数参数
input:
1. dataset: iris.data 只包含样本的特征值,本实验中大小为150*4
2. num_lowerdim: 谱聚类本意上是降维处理,取L矩阵前k个特征值,这个参数就是这个k。(可惜iris数据集维度不大,不小心就升维了)
3. number_cluster: 要分成的类别数,这里是3
4. kernel: 在构造关系矩阵时,采用全连接方法,核函数可以改变用别的。
5. cluster_method: 最后对于特征矩阵行元素的聚类方法,这里用的时k-means,可以用别的。
output:
一个向量,里面顺次是每个样本聚类的标签,同标签数值相同,但是不一定是几
核函数
用的是kernel k-means时候写的核函数文件,在这里调用的是高斯核,封装成参数写在主函数里面
Main
from sklearn.datasets import load_iris
import numpy as np
from SpectralClustering import *
import matplotlib.pyplot as plt
# 加载数据集,用的是sklearn的数据集
iris = load_iris()
NJW = Spectral_Clustering(iris.data,number_cluster=3,num_lowerdim=3,kernel = squared_exponential_kernel,cluster_method='KMeans')
#将结果与数据拼接在一起
NJW = NJW.squeeze()
NJW = NJW[:,None]
df1 = np.concatenate([iris.data,NJW], axis=1)
#可视化
def draw(data,dim0,dim1):
colorSet = ["black", "blue", "green", "yellow", "red", "purple", "orange", "brown"]
for i in range(iris.data.shape[0]):
x = data[i][dim0]
y = data[i][dim1]
color = colorSet[int(data[i][-1]) % len(colorSet)]
plt.scatter(x,y, marker="o", c=color, s=20)
plt.xlabel("x")
plt.ylabel("y")
plt.show()
draw (df1,0,1)
draw (df1,1,2)
draw (df1,3,0)
没啥好说的,都写在注释里面了。
引入数据集
调用谱聚类主要函数
结果可视化
实验结果
谱聚类笔记
网上有很多文章写的有问题,也有几篇讲的非常好的。书上写的有点复杂,不大好按照思路一步一步引导。
下面是我学的过程中整理的思路,还有问题没解决,之后再进行补充