六、基于图的算法
6.1 谱聚类
6.2 算法原理
RatioCut算法
NCut算法
6.3 如何选择合适的K值
6.4 谱聚类的应用场景
示例代码1:对鸢尾花数据集进行聚类,并绘制结果
# 导入所需的库
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans
from sklearn.metrics.pairwise import rbf_kernel
# 加载鸢尾花数据集
iris = load_iris()
X = iris.data
y = iris.target
# 定义谱聚类的函数
def spectral_clustering(X, k, gamma):
# 计算相似度矩阵
S = rbf_kernel(X, gamma=gamma)
# 计算度矩阵
D = np.diag(np.sum(S, axis=1))
# 计算拉普拉斯矩阵
L = D - S
# 计算特征值和特征向量
eig_val, eig_vec = np.linalg.eig(L)
# 选择最小的k个特征值对应的特征向量
idx = np.argsort(eig_val)[:k]
U = eig_vec[:, idx]
# 对每一行进行归一化
T = np.linalg.norm(U, axis=1, keepdims=True)
U = U / T
# 应用k-means算法
kmeans = KMeans(n_clusters=k, random_state=0)
kmeans.fit(U)
# 返回簇标签
return kmeans.labels_
# 调用谱聚类的函数,设置k=3,gamma=0.1
y_pred = spectral_clustering(X, k=3, gamma=0.1)
# 绘制原始数据和聚类结果的散点图
plt.figure(figsize=(12, 6))
plt.subplot(121)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap='rainbow')
plt.title('Original Data')
plt.xlabel('Sepal Length')
plt.ylabel('Sepal Width')
plt.subplot(122)
plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap='rainbow')
plt.title('Spectral Clustering')
plt.xlabel('Sepal Length')
plt.ylabel('Sepal Width')
plt.show()
示例代码2:
这是一个用于评估聚类结果的函数,它可以计算互信息、准确度和纯度等指标。这些指标都是用来评估聚类结果的有效性的。
互信息 (Mutual Information) 是衡量两个随机变量之间的依赖程度的一个度量,它反映了两个变量共享的信息量。在聚类中,互信息可以用来衡量聚类结果与真实标签之间的一致性,互信息越大,表示聚类结果越符合真实标签。
准确度 (Accuracy) 是衡量聚类结果与真实标签之间的匹配程度的一个度量,它反映了聚类结果中正确分类的样本比例。在聚类中,准确度可以用来衡量聚类结果的正确性,准确度越高,表示聚类结果越正确。
纯度 (Purity) 是衡量聚类结果中每个簇的纯净程度的一个度量,它反映了每个簇中占比最大的真实标签的比例。在聚类中,纯度可以用来衡量聚类结果的纯净性,纯度越高,表示聚类结果越纯净。
# 导入 math 模块,用于进行数学运算
import math
# 导入 numpy 模块,用于进行数组操作
import numpy as np
# 定义一个函数,名为 eva,接受两个参数,分别是 A 和 B,表示两种聚类结果的标签
def eva(A, B):
# 计算样本点数,即 A 和 B 的长度,赋值给 total
total = len(A)
# 将 A 中的不同标签转换为一个集合,赋值给 A_ids
A_ids = set(A)
# 将 B 中的不同标签转换为一个集合,赋值给 B_ids
B_ids = set(B)
# 初始化互信息为 0,赋值给 MI
MI = 0
# 定义一个很小的正数,赋值给 eps,用于避免对 0 取对数的错误
eps = 1.4e-45
# 初始化准确度为 0,赋值给 acc
acc = 0
# 初始化纯度为 0,赋值给 purity
purity = 0
# 对于 A 中的每个标签,赋值给 idA
for idA in A_ids:
# 初始化最大纯度为 0.0,赋值给 max_purity
max_purity = 0.0
# 对于 B 中的每个标签,赋值给 idB
for idB in B_ids:
# 找出 A 中标签为 idA 的样本的索引,赋值给 idAOccur
idAOccur = np.where(A == idA) # 返回下标
# 找出 B 中标签为 idB 的样本的索引,赋值给 idBOccur
idBOccur = np.where(B == idB)
# 找出 A 和 B 中同时标签为 idA 和 idB 的样本的索引,赋值给 idABOccur
idABOccur = np.intersect1d(idAOccur, idBOccur)
# 计算 A 中标签为 idA 的样本的比例,赋值给 px
px = 1.0*len(idAOccur[0])/total
# 计算 B 中标签为 idB 的样本的比例,赋值给 py
py = 1.0*len(idBOccur[0])/total
# 计算 A 和 B 中同时标签为 idA 和 idB 的样本的比例,赋值给 pxy
pxy = 1.0*len(idABOccur)/total
# 根据公式计算互信息,累加到 MI 上
MI = MI + pxy*math.log(pxy/(px*py)+eps, 2) # 互信息计算
# 如果 idA 和 idB 相等,说明 A 和 B 中的标签一致
if idA == idB:
# 将 pxy 累加到 acc 上,表示准确度
acc = acc + pxy # 准确度计算
# 如果 idABOccur 的长度大于 max_purity,说明这是一个较纯的簇
if len(idABOccur) > max_purity: # 纯度计算
# 更新 max_purity 的值
max_purity = len(idABOccur)
# 将 idABOccur 的比例累加到 purity 上,表示纯度
purity = purity + 1.0*len(idABOccur)/total
# 计算标准化互信息,即互信息除以 A 和 B 的熵的平均值
# 初始化 A 的熵为 0,赋值给 Hx
Hx = 0
# 对于 A 中的每个标签,赋值给 idA
for idA in A_ids:
# 计算 A 中标签为 idA 的样本的个数,赋值给 idAOccurCount
idAOccurCount = 1.0*len(np.where(A == idA)[0])
# 根据公式计算 A 的熵,累加到 Hx 上
Hx = Hx - (idAOccurCount/total)*math.log(idAOccurCount/total+eps, 2)
# 初始化 B 的熵为 0,赋值给 Hy
Hy = 0
# 对于 B 中的每个标签,赋值给 idB
for idB in B_ids:
# 计算 B 中标签为 idB 的样本的个数,赋值给 idBOccurCount
idBOccurCount = 1.0*len(np.where(B == idB)[0])
# 根据公式计算 B 的熵,累加到 Hy 上
Hy = Hy - (idBOccurCount/total)*math.log(idBOccurCount/total+eps, 2)
# 计算标准化互信息,赋值给 NMI
NMI = 2.0*MI/(Hx+Hy)
# 返回 NMI,acc 和 purity 三个指标
return NMI, acc, purity
这是一个用于实现谱聚类算法的源代码,它可以对不同形状的数据进行聚类分析
flame.txt 数据集
# 从 sklearn.cluster 模块导入 KMeans 函数,用于进行 K-Means 聚类
from sklearn.cluster import KMeans
# 导入 numpy 模块,用于进行数组操作
import numpy as np
# 导入 math 模块,用于进行数学运算
import math as m
# 导入 matplotlib.pyplot 模块,用于绘制图形
import matplotlib.pyplot as plt
# 导入 evaluate 模块,用于评估聚类结果
import evaluate as eval
# 定义几个数据集的文件名,用于读取数据
# flame.txt
# Jain_cluster=2.txt
# Aggregation_cluster=7.txt
# Spiral_cluster=3.txt
# Pathbased_cluster=3.txt
# 定义数据集的路径,这里使用 flame.txt 数据集
d