评估聚类算法的性能并不像统计错误数量或计算监督分类算法的准确率和召回率那么简单。特别是任何度量指标不应考虑簇标签的绝对值,而是如果这个聚类方式分离的数据类似与一些真实类或满足某些假设,这样在同于一个相似性度量下,属于同一个类内的成员比不同类的成员更加类似。
调整兰德指数 (adjusted_rand_score 函数)
adjusted_rand_score 函数
描述
计算并返回两个标签分配之间的调整兰德指数(ARI)。调整兰德指数是对兰德指数的修正版本,考虑了偶然达成一致的可能性,其取值范围为[-1, 1],其中1表示完美匹配,0表示随机标签分配的期望相似度,负值表示匹配程度低于随机水平。
参数
labels_true
: int array, shape = [n_samples]- 数据集的真实标签,作为基准。
labels_pred
: array-like of shape (n_samples,)- 预测的标签,与
labels_true
相比以评估相似性或一致性。
- 预测的标签,与
返回值
ari
: float- 调整兰德指数,评估
labels_true
和labels_pred
之间的相似度。该值越高,表示两组标签越相似。完全随机的标签将趋向于得到一个接近0的得分,而完美的匹配得分为1.0。
- 调整兰德指数,评估
内部数学形式
给定两组标签分配 UUU 和 VVV,其中 UUU 包含 nnn 个元素被划分为 KKK 类,VVV 包含同样的 nnn 个元素但被划分为 CCC 类。
定义:
- aija_{ij}aij 表示在 UUU 中属于类 iii 并且在 VVV 中属于类 jjj 的元素数量。
- ai=∑jaija_i = \sum_j a_{ij}ai=∑jaij 表示在 UUU 中属于类 iii 的所有元素的数量。
- bj=∑iaijb_j = \sum_i a_{ij}bj=∑iaij 表示在 VVV 中属于类 jjj 的所有元素的数量。
则调整兰德指数(ARI)的计算公式为:
ARI=∑i,j(aij2)−[∑i(ai2)∑j(bj2)]/(n2)12[∑i(ai2)+∑j(bj2)]−[∑i(ai2)∑j(bj2)]/(n2) ARI = \frac{\sum_{i,j} \binom{a_{ij}}{2} - [\sum_i \binom{a_i}{2} \sum_j \binom{b_j}{2}] / \binom{n}{2}} {\frac{1}{2}[\sum_i \binom{a_i}{2} + \sum_j \binom{b_j}{2}] - [\sum_i \binom{a_i}{2} \sum_j \binom{b_j}{2}] / \binom{n}{2}} ARI=21[∑i(2ai)+∑j(2bj)]−[∑i(2ai)∑j(2bj)]/(2n)∑i,j(2aij)−[∑i(2ai)∑j(2bj)]/(2n)
其中 (n2)\binom{n}{2}(2n) 表示从 nnn 个不同元素中取出 2 个元素的组合数。
以下是adjusted_rand_score 函数使用的一个简单示例:
python
import numpy as np
from sklearn.metrics import adjusted_rand_score
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
# --- 示例 1: 完全一致 ---
print("=== 示例 1: 聚类结果与真实标签完全一致 ===")
# 真实标签
labels_true = [0, 0, 1, 1, 2, 2]
# 聚类结果 (完全匹配,只是标签编号不同)
labels_pred_same = [1, 1, 0, 0, 2, 2] # 0<->1 互换, 2 不变
ari_same = adjusted_rand_score(labels_true, labels_pred_same)
print(f"真实标签: {labels_true}")
print(f"聚类标签: {labels_pred_same}")
print(f"调整兰德指数 (ARI): {ari_same:.6f}")
print("解释: ARI=1.0,尽管标签编号不同,但样本对的分配关系完全一致。")
print()
# --- 示例 2: 完全不一致 (随机) ---
print("=== 示例 2: 聚类结果与真实标签完全不一致 ===")
labels_true = [0, 0, 1, 1, 2, 2]
# 一个非常差的聚类结果
labels_pred_random = [0, 1, 2, 0, 1, 2]
ari_random = adjusted_rand_score(labels_true, labels_pred_random)
print(f"真实标签: {labels_true}")
print(f"聚类标签: {labels_pred_random}")
print(f"调整兰德指数 (ARI): {ari_random:.6f}")
print("解释: ARI 接近 0 或为负,表示聚类结果与真实结构几乎没有关联。")
print()
# --- 示例 3: 部分一致 ---
print("=== 示例 3: 聚类结果部分一致 ===")
labels_true = [0, 0, 0, 1, 1, 1, 2, 2, 2]
# 聚类结果: 前两个类分对了,但第三个类被错误地分到了前两类中
labels_pred_partial = [0, 0, 1, 1, 1, 1, 0, 0, 0]
ari_partial = adjusted_rand_score(labels_true, labels_pred_partial)
print(f"真实标签: {labels_true}")
print(f"聚类标签: {labels_pred_partial}")
print(f"调整兰德指数 (ARI): {ari_partial:.6f}")
print("解释: ARI > 0 但 < 1,表示有一定的一致性,但存在明显错误。")
print()
# --- 示例 4: 不同簇数 ---
print("=== 示例 4: 聚类簇数与真实类别数不同 ===")
labels_true = [0, 0, 1, 1, 2, 2] # 3 个真实类别
# 聚类结果: 只分成了 2 个簇
labels_pred_2clusters = [0, 0, 0, 0, 1, 1]
ari_2clusters = adjusted_rand_score(labels_true, labels_pred_2clusters)
print(f"真实标签 (3类): {labels_true}")
print(f"聚类标签 (2类): {labels_pred_2clusters}")
print(f"调整兰德指数 (ARI): {ari_2clusters:.6f}")
print("解释: ARI 可以处理簇数不同的情况。这里 ARI 较低,因为无法完美匹配 3 个类别。")
print()
# --- 示例 5: 实际应用 - 用 K-Means 聚类 ---
print("=== 示例 5: 实际应用 - K-Means 聚类评估 ===")
# 生成一个简单的聚类数据集 (3个簇)
X, y_true = make_blobs(n_samples=300, centers=3, cluster_std=0.60, random_state=42)
# 应用 K-Means 聚类
kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
y_pred = kmeans.fit_predict(X)
# 计算 ARI
ari_kmeans = adjusted_rand_score(y_true, y_pred)
print(f"K-Means 聚类结果 (n_clusters=3):")
print(f"调整兰德指数 (ARI): {ari_kmeans:.6f}")
print(f"注: ARI 非常接近 1.0,说明 K-Means 在这个数据集上聚类效果极好。")
print()
# --- 可视化 ---
plt.figure(figsize=(15, 5))
# 子图 1: 真实标签
plt.subplot(1, 3, 1)
scatter1 = plt.scatter(X[:, 0], X[:, 1], c=y_true, cmap='viridis', alpha=0.7)
plt.title('真实标签')
plt.xlabel('特征 1')
plt.ylabel('特征 2')
plt.colorbar(scatter1)
# 子图 2: K-Means 聚类结果
plt.subplot(1, 3, 2)
scatter2 = plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap='viridis', alpha=0.7)
plt.title(f'K-Means 聚类 (ARI={ari_kmeans:.3f})')
plt.xlabel('特征 1')
plt.ylabel('特征 2')
plt.colorbar(scatter2)
# 子图 3: 聚类结果 (2个簇) - 用于对比
kmeans_2 = KMeans(n_clusters=2, random_state=42, n_init=10)
y_pred_2 = kmeans_2.fit_predict(X)
ari_kmeans_2 = adjusted_rand_score(y_true, y_pred_2)
scatter3 = plt.scatter(X[:, 0], X[:, 1], c=y_pred_2, cmap='viridis', alpha=0.7)
plt.title(f'K-Means (2簇, ARI={ari_kmeans_2:.3f})')
plt.xlabel('特征 1')
plt.ylabel('特征 2')
plt.colorbar(scatter3)
plt.tight_layout()
plt.show()
# --- 补充: ARI vs 其他指标 ---
print("=== 补充: ARI 与其他指标对比 ===")
print("真实标签:", y_true[:10]) # 只显示前10个
print("K-Means预测:", y_pred[:10])
# 计算其他常见指标
from sklearn.metrics import homogeneity_score, completeness_score, v_measure_score
homogeneity = homogeneity_score(y_true, y_pred)
completeness = completeness_score(y_true, y_pred)
v_measure = v_measure_score(y_true, y_pred)
print(f"同质性 (Homogeneity): {homogeneity:.3f}")
print(f"完整性 (Completeness): {completeness:.3f}")
print(f"V-Measure: {v_measure:.3f}")
print(f"调整兰德指数 (ARI): {ari_kmeans:.3f}")
print("解释: 这些指标都从不同角度评估聚类质量。ARI 是一个综合且常用的单一分数。")
结果分析
python
=== 示例 1: 聚类结果与真实标签完全一致 ===
真实标签: [0, 0, 1, 1, 2, 2]
聚类标签: [1, 1, 0, 0, 2, 2]
调整兰德指数 (ARI): 1.000000
解释: ARI=1.0,尽管标签编号不同,但样本对的分配关系完全一致。
=== 示例 2: 聚类结果与真实标签完全不一致 ===
真实标签: [0, 0, 1, 1, 2, 2]
聚类标签: [0, 1, 2, 0, 1, 2]
调整兰德指数 (ARI): -0.142857
解释: ARI 接近 0 或为负,表示聚类结果与真实结构几乎没有关联。
=== 示例 3: 聚类结果部分一致 ===
真实标签: [0, 0, 0, 1, 1, 1, 2, 2, 2]
聚类标签: [0, 0, 1, 1, 1, 1, 0, 0, 0]
调整兰德指数 (ARI): 0.266667
解释: ARI > 0 但 < 1,表示有一定的一致性,但存在明显错误。
=== 示例 4: 聚类簇数与真实类别数不同 ===
真实标签 (3类): [0, 0, 1, 1, 2, 2]
聚类标签 (2类): [0, 0, 0, 0, 1, 1]
调整兰德指数 (ARI): 0.000000
解释: ARI 可以处理簇数不同的情况。这里 ARI 较低,因为无法完美匹配 3 个类别。
=== 示例 5: 实际应用 - K-Means 聚类评估 ===
K-Means 聚类结果 (n_clusters=3):
调整兰德指数 (ARI): 1.000000
注: ARI 非常接近 1.0,说明 K-Means 在这个数据集上聚类效果极好。
=== 补充: ARI 与其他指标对比 ===
真实标签: [0 1 2 0 1 2 0 1 2 0]
K-Means预测: [1 2 0 1 2 0 1 2 0 1]
同质性 (Homogeneity): 1.000
完整性 (Completeness): 1.000
V-Measure: 1.000
调整兰德指数 (ARI): 1.000
解释: 这些指标都从不同角度评估聚类质量。ARI 是一个综合且常用的单一分数。
关键点总结
- 评估聚类质量 : ARI 是评估聚类算法性能的黄金标准之一,当你有真实标签时。
- 基于样本对: 它的核心是比较所有样本对在两个标签分配中的"一致程度"。
- 调整随机性 : 最大的优点是它对随机分配进行了校正,使得
ARI=0
成为一个有意义的基准线(随机水平)。 - 标签无关性 : ARI 只关心样本的分组关系,不关心类别标签的具体数字或顺序。
[0,0,1,1]
和[1,1,0,0]
的 ARI 是 1.0。 - 簇数无关性: ARI 可以比较簇数不同的聚类结果与真实标签。即使簇数不匹配,也能给出有意义的分数。
- 取值范围: [-1, 1],越接近 1 越好。
- 何时使用: 当你需要客观地比较不同聚类算法、不同参数下的聚类效果,并且有真实标签可供参考时。
总而言之,adjusted_rand_score
是一个强大、鲁棒且解释性强的聚类评估指标。它是 sklearn.metrics
中最常用的外部评估指标之一。记住,它需要真实标签,因此主要用于算法开发、调参和基准测试。
基于互信息(mutual information)的得分(adjusted_mutual_info_score函数、mutual_info_score函数、normalized_mutual_info_score函数)
函数:adjusted_mutual_info_score
参数:
labels_true
: int array, shape = [n_samples]- 样本的真实标签。
labels_pred
: array-like of shape (n_samples,)- 样本的预测标签。
average_method
: string, optional (default: 'arithmetic')- 计算期望互信息时使用的平均方法。可选值有'warn', 'arithmetic', 'geometric', 'max'。
返回值:
ami
: float- 调整互信息得分,在0到1之间,完全匹配时为1。
内部数学形式:
给定两组标签分配 UUU 和 VVV,其中 UUU 包含 nnn 个元素被划分为 KKK 类,VVV 包含同样的 nnn 个元素但被划分为 CCC 类。
AMI定义如下:
AMI(U,V)=MI(U,V)−E(MI(U,V))max(H(U),H(V))−E(MI(U,V)) AMI(U,V) = \frac{MI(U,V) - E(MI(U,V))}{\max(H(U), H(V)) - E(MI(U,V))} AMI(U,V)=max(H(U),H(V))−E(MI(U,V))MI(U,V)−E(MI(U,V))
其中,
- MI(U,V)MI(U,V)MI(U,V) 表示UUU和VVV之间的互信息。
- E(MI(U,V))E(MI(U,V))E(MI(U,V)) 表示在随机分布下UUU和VVV互信息的期望值。
- H(U)H(U)H(U) 和 H(V)H(V)H(V) 分别是UUU和VVV的信息熵。
期望的互信息E(MI(U,V))E(MI(U,V))E(MI(U,V))的计算依赖于所选择的average_method
。
adjusted_mutual_info_score函数使用示例
python
import numpy as np
from sklearn.metrics import adjusted_mutual_info_score, adjusted_rand_score
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
# --- 示例 1: 完全一致 ---
print("=== 示例 1: 聚类结果与真实标签完全一致 ===")
# 真实标签
labels_true = [0, 0, 1, 1, 2, 2]
# 聚类结果 (完全匹配,只是标签编号不同)
labels_pred_same = [1, 1, 0, 0, 2, 2] # 0<->1 互换, 2 不变
ami_same = adjusted_mutual_info_score(labels_true, labels_pred_same)
ari_same = adjusted_rand_score(labels_true, labels_pred_same)
print(f"真实标签: {labels_true}")
print(f"聚类标签: {labels_pred_same}")
print(f"调整互信息分数 (AMI): {ami_same:.6f}")
print(f"调整兰德指数 (ARI): {ari_same:.6f}")
print("解释: AMI 和 ARI 都为 1.0,表示完全一致。")
print()
# --- 示例 2: 完全不一致 (随机) ---
print("=== 示例 2: 聚类结果与真实标签完全不一致 ===")
labels_true = [0, 0, 1, 1, 2, 2]
# 一个非常差的聚类结果
labels_pred_random = [0, 1, 2, 0, 1, 2]
ami_random = adjusted_mutual_info_score(labels_true, labels_pred_random)
ari_random = adjusted_rand_score(labels_true, labels_pred_random)
print(f"真实标签: {labels_true}")
print(f"聚类标签: {labels_pred_random}")
print(f"调整互信息分数 (AMI): {ami_random:.6f}")
print(f"调整兰德指数 (ARI): {ari_random:.6f}")
print("解释: AMI 和 ARI 都接近 0 或为负,表示聚类结果与真实结构几乎没有关联。")
print()
# --- 示例 3: 部分一致 ---
print("=== 示例 3: 聚类结果部分一致 ===")
labels_true = [0, 0, 0, 1, 1, 1, 2, 2, 2]
# 聚类结果: 前两个类分对了,但第三个类被错误地分到了前两类中
labels_pred_partial = [0, 0, 1, 1, 1, 1, 0, 0, 0]
ami_partial = adjusted_mutual_info_score(labels_true, labels_pred_partial)
ari_partial = adjusted_rand_score(labels_true, labels_pred_partial)
print(f"真实标签: {labels_true}")
print(f"聚类标签: {labels_pred_partial}")
print(f"调整互信息分数 (AMI): {ami_partial:.6f}")
print(f"调整兰德指数 (ARI): {ari_partial:.6f}")
print("解释: AMI 和 ARI 都大于 0 但小于 1,表示有一定的一致性。")
print()
# --- 示例 4: 不同簇数 ---
print("=== 示例 4: 聚类簇数与真实类别数不同 ===")
labels_true = [0, 0, 1, 1, 2, 2] # 3 个真实类别
# 聚类结果: 只分成了 2 个簇
labels_pred_2clusters = [0, 0, 0, 0, 1, 1]
ami_2clusters = adjusted_mutual_info_score(labels_true, labels_pred_2clusters)
ari_2clusters = adjusted_rand_score(labels_true, labels_pred_2clusters)
print(f"真实标签 (3类): {labels_true}")
print(f"聚类标签 (2类): {labels_pred_2clusters}")
print(f"调整互信息分数 (AMI): {ami_2clusters:.6f}")
print(f"调整兰德指数 (ARI): {ari_2clusters:.6f}")
print("解释: AMI 和 ARI 都可以处理簇数不同的情况。")
print()
# --- 示例 5: 实际应用 - 用 K-Means 聚类 ---
print("=== 示例 5: 实际应用 - K-Means 聚类评估 ===")
# 生成一个简单的聚类数据集 (3个簇)
X, y_true = make_blobs(n_samples=300, centers=3, cluster_std=0.60, random_state=42)
# 应用 K-Means 聚类
kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
y_pred = kmeans.fit_predict(X)
# 计算 AMI 和 ARI
ami_kmeans = adjusted_mutual_info_score(y_true, y_pred)
ari_kmeans = adjusted_rand_score(y_true, y_pred)
print(f"K-Means 聚类结果 (n_clusters=3):")
print(f"调整互信息分数 (AMI): {ami_kmeans:.6f}")
print(f"调整兰德指数 (ARI): {ari_kmeans:.6f}")
print(f"注: AMI 和 ARI 都非常接近 1.0,说明 K-Means 在这个数据集上聚类效果极好。")
print()
# --- 可视化 ---
plt.figure(figsize=(15, 5))
# 子图 1: 真实标签
plt.subplot(1, 3, 1)
scatter1 = plt.scatter(X[:, 0], X[:, 1], c=y_true, cmap='plasma', alpha=0.7)
plt.title('真实标签')
plt.xlabel('特征 1')
plt.ylabel('特征 2')
plt.colorbar(scatter1)
# 子图 2: K-Means 聚类结果 (AMI)
plt.subplot(1, 3, 2)
scatter2 = plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap='plasma', alpha=0.7)
plt.title(f'K-Means 聚类 (AMI={ami_kmeans:.3f})')
plt.xlabel('特征 1')
plt.ylabel('特征 2')
plt.colorbar(scatter2)
# 子图 3: K-Means 聚类结果 (ARI)
plt.subplot(1, 3, 3)
scatter3 = plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap='plasma', alpha=0.7)
plt.title(f'K-Means 聚类 (ARI={ari_kmeans:.3f})')
plt.xlabel('特征 1')
plt.ylabel('特征 2')
plt.colorbar(scatter3)
plt.tight_layout()
plt.show()
# --- 补充: AMI vs ARI vs 其他指标 ---
print("=== 补充: AMI, ARI 与其他指标对比 ===")
print("真实标签:", y_true[:10]) # 只显示前10个
print("K-Means预测:", y_pred[:10])
# 计算其他常见指标
from sklearn.metrics import homogeneity_score, completeness_score, v_measure_score
homogeneity = homogeneity_score(y_true, y_pred)
completeness = completeness_score(y_true, y_pred)
v_measure = v_measure_score(y_true, y_pred)
print(f"同质性 (Homogeneity): {homogeneity:.3f}")
print(f"完整性 (Completeness): {completeness:.3f}")
print(f"V-Measure: {v_measure:.3f}")
print(f"调整互信息分数 (AMI): {ami_kmeans:.3f}")
print(f"调整兰德指数 (ARI): {ari_kmeans:.3f}")
print("\n解释:")
print("1. AMI 和 ARI 都是综合性的单一分数,常用于算法比较。")
print("2. 同质性 (Homogeneity): 每个聚类只包含一个类别的样本。")
print("3. 完整性 (Completeness): 一个类别的所有样本都被分到同一个聚类中。")
print("4. V-Measure: 同质性和完整性的调和平均数。")
print("5. 在这个理想案例中,所有指标都接近 1.0。")
结果分析
python
=== 示例 1: 聚类结果与真实标签完全一致 ===
真实标签: [0, 0, 1, 1, 2, 2]
聚类标签: [1, 1, 0, 0, 2, 2]
调整互信息分数 (AMI): 1.000000
调整兰德指数 (ARI): 1.000000
解释: AMI 和 ARI 都为 1.0,表示完全一致。
=== 示例 2: 聚类结果与真实标签完全不一致 ===
真实标签: [0, 0, 1, 1, 2, 2]
聚类标签: [0, 1, 2, 0, 1, 2]
调整互信息分数 (AMI): -0.045945
调整兰德指数 (ARI): -0.142857
解释: AMI 和 ARI 都接近 0 或为负,表示聚类结果与真实结构几乎没有关联。
=== 示例 3: 聚类结果部分一致 ===
真实标签: [0, 0, 0, 1, 1, 1, 2, 2, 2]
聚类标签: [0, 0, 1, 1, 1, 1, 0, 0, 0]
调整互信息分数 (AMI): 0.234856
调整兰德指数 (ARI): 0.266667
解释: AMI 和 ARI 都大于 0 但小于 1,表示有一定的一致性。
=== 示例 4: 聚类簇数与真实类别数不同 ===
真实标签 (3类): [0, 0, 1, 1, 2, 2]
聚类标签 (2类): [0, 0, 0, 0, 1, 1]
调整互信息分数 (AMI): 0.000000
调整兰德指数 (ARI): 0.000000
解释: AMI 和 ARI 都可以处理簇数不同的情况。
=== 示例 5: 实际应用 - K-Means 聚类评估 ===
K-Means 聚类结果 (n_clusters=3):
调整互信息分数 (AMI): 1.000000
调整兰德指数 (ARI): 1.000000
注: AMI 和 ARI 都非常接近 1.0,说明 K-Means 在这个数据集上聚类效果极好。
=== 补充: AMI, ARI 与其他指标对比 ===
真实标签: [0 1 2 0 1 2 0 1 2 0]
K-Means预测: [1 2 0 1 2 0 1 2 0 1]
同质性 (Homogeneity): 1.000
完整性 (Completeness): 1.000
V-Measure: 1.000
调整互信息分数 (AMI): 1.000
调整兰德指数 (ARI): 1.000
解释:
1. AMI 和 ARI 都是综合性的单一分数,常用于算法比较。
2. 同质性 (Homogeneity): 每个聚类只包含一个类别的样本。
3. 完整性 (Completeness): 一个类别的所有样本都被分到同一个聚类中。
4. V-Measure: 同质性和完整性的调和平均数。
5. 在这个理想案例中,所有指标都接近 1.0。
关键点总结
-
信息论视角 : AMI 从信息共享 的角度评估聚类质量,而 ARI 从样本对一致性的角度评估。两者都是有效的,但理论基础不同。
-
调整随机性 : 最大的优点是它对随机分配进行了校正,使得
AMI=0
成为一个有意义的基准线(随机水平)。 -
标签无关性: AMI 只关心标签分配的联合分布,不关心类别标签的具体数字或顺序。
-
簇数无关性: AMI 可以比较簇数不同的聚类结果与真实标签。
-
取值范围: [-1, 1],越接近 1 越好。
-
与 ARI 的关系:
- 相似性: AMI 和 ARI 通常给出非常相似的结论,尤其是在聚类效果好或差的极端情况下。
- 差异性: 在某些情况下(如类别严重不均衡),AMI 和 ARI 的值可能会有差异。AMI 有时被认为对簇数更敏感。
-
何时使用: 当你需要客观地比较不同聚类算法、不同参数下的聚类效果,并且有真实标签可供参考时。它和 ARI 是最常用的两个外部评估指标。
总而言之,adjusted_mutual_info_score
是一个基于信息论的强大聚类评估指标。它与 adjusted_rand_score
一起,构成估聚类算法性能的"双子星"。在实际应用中,你可以选择其中一个,或者同时报告两者来获得更全面的评估。
函数:mutual_info_score
参数:
labels_true
: array-like, shape = [n_samples]- 样本的真实标签。
labels_pred
: array-like, shape = [n_samples]- 样本的预测标签。
返回值:
mi
: float- 互信息得分,无单位量纲,其值越大表示两组标签之间的相关性越强。
内部数学形式:
给定两个离散随机变量 XXX 和 YYY,它们的互信息定义为:
MI(X;Y)=∑y∈Y∑x∈Xp(x,y)log(p(x,y)p(x) p(y)) MI(X;Y) = \sum_{y \in Y} \sum_{x \in X} p(x,y) \log{\left(\frac{p(x,y)}{p(x)\,p(y)}\right)} MI(X;Y)=y∈Y∑x∈X∑p(x,y)log(p(x)p(y)p(x,y))
其中,
- p(x,y)p(x,y)p(x,y) 是联合概率分布函数 XXX 和 YYY。
- p(x)p(x)p(x) 和 p(y)p(y)p(y) 分别是边缘概率分布函数。
在实际应用中,对于有限的数据样本,我们通常使用以下估计方式计算互信息:
- 首先通过样本数据估计出联合概率分布p(x,y)p(x,y)p(x,y)和边缘概率分布p(x)p(x)p(x)、p(y)p(y)p(y)。
- 然后利用上述公式计算互信息。
在mutual_info_score
函数中,互信息是基于输入的两组标签来估算的,它衡量的是这两组标签之间的相似度或依赖关系。注意,互信息不受标签值的具体数值影响,而是依赖于标签之间的匹配模式。
使用示例
python
import numpy as np
from sklearn.metrics import mutual_info_score, adjusted_mutual_info_score
import matplotlib.pyplot as plt
# --- 示例 1: 完全独立 ---
print("=== 示例 1: 两个变量完全独立 ===")
# 变量 A 和 B 的值
A = [0, 0, 1, 1, 0, 1, 0, 1]
B = [0, 1, 0, 1, 1, 0, 1, 0] # B 的值与 A 无关
mi_independent = mutual_info_score(A, B)
print(f"变量 A: {A}")
print(f"变量 B: {B}")
print(f"互信息分数 (MI): {mi_independent:.6f}")
print("解释: MI ≈ 0,表示 A 和 B 几乎没有共享信息,是独立的。")
print()
# --- 示例 2: 完全相关 ---
print("=== 示例 2: 两个变量完全相关 ===")
A = [0, 0, 1, 1, 0, 1, 0, 1]
B = [0, 0, 1, 1, 0, 1, 0, 1] # B 完全等于 A
mi_perfect = mutual_info_score(A, B)
print(f"变量 A: {A}")
print(f"变量 B: {B}")
print(f"互信息分数 (MI): {mi_perfect:.6f}")
print("解释: MI > 0,且等于 A 或 B 的熵(不确定性),表示它们完全共享信息。")
print()
# --- 示例 3: 部分相关 ---
print("=== 示例 3: 两个变量部分相关 ===")
A = [0, 0, 1, 1, 0, 1, 0, 1]
# B 的值大部分与 A 相同,但有少量错误
B = [0, 0, 1, 0, 0, 1, 1, 1] # 第 4 和第 7 个值不同
mi_partial = mutual_info_score(A, B)
print(f"变量 A: {A}")
print(f"变量 B: {B}")
print(f"互信息分数 (MI): {mi_partial:.6f}")
print("解释: MI > 0 但 < 完全相关时的值,表示 A 和 B 有一定关联,但不完全。")
print()
# --- 示例 4: 探索 MI 的性质 ---
print("=== 示例 4: 探索 MI 的性质 ===")
# 创建一个更复杂的例子
labels_true = [0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 1]
labels_pred = [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1]
mi_raw = mutual_info_score(labels_true, labels_pred)
ami_adjusted = adjusted_mutual_info_score(labels_true, labels_pred)
print(f"真实标签: {labels_true}")
print(f"聚类标签: {labels_pred}")
print(f"原始互信息分数 (MI): {mi_raw:.6f}")
print(f"调整互信息分数 (AMI): {ami_adjusted:.6f}")
print("解释: 原始 MI 为正值,但难以判断这个值是'好'还是'坏'。")
print(" AMI 对随机性进行了校正,AMI=0 表示等同于随机,更有解释性。")
print()
# --- 示例 5: 特征选择 (简单演示) ---
print("=== 示例 5: 特征选择 (简单演示) ===")
# 假设我们有目标变量 y 和三个特征 X1, X2, X3
y = [0, 0, 1, 1, 0, 1, 0, 1] # 目标 (二分类)
X1 = [0, 0, 1, 1, 0, 1, 0, 1] # 与 y 完全相关
X2 = [0, 1, 0, 1, 1, 0, 1, 0] # 与 y 完全独立
X3 = [0, 0, 1, 0, 0, 1, 0, 1] # 与 y 部分相关
mi_X1 = mutual_info_score(y, X1)
mi_X2 = mutual_info_score(y, X2)
mi_X3 = mutual_info_score(y, X3)
print(f"目标 y: {y}")
print(f"特征 X1: {X1} -> MI(y, X1) = {mi_X1:.6f}")
print(f"特征 X2: {X2} -> MI(y, X2) = {mi_X2:.6f}")
print(f"特征 X3: {X3} -> MI(y, X3) = {mi_X3:.6f}")
print("\n结论: 根据 MI,特征重要性排序为: X1 > X3 > X2")
print(" X1 与目标最相关,X2 与目标无关,应被丢弃。")
print()
# --- 可视化 MI 随相关性变化 ---
print("=== 示例 6: 可视化 MI 随相关性变化 ===")
# 生成一个基础序列
np.random.seed(42)
base = np.random.randint(0, 2, 1000) # 1000 个随机 0/1
# 创建一系列与 base 相关的序列,相关性从 0 到 1
noise_levels = np.linspace(0, 0.5, 20) # 噪声比例从 0% 到 50%
mis = []
aris = []
for noise in noise_levels:
# 通过随机翻转一定比例的位来引入噪声
corrupted = base.copy()
flip_indices = np.random.choice(len(base), int(noise * len(base)), replace=False)
corrupted[flip_indices] = 1 - corrupted[flip_indices] # 翻转 0<->1
mi = mutual_info_score(base, corrupted)
ari = adjusted_rand_score(base, corrupted)
mis.append(mi)
aris.append(ari)
# 绘图
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.plot(noise_levels * 100, mis, 'bo-', label='互信息 (MI)')
plt.xlabel('噪声比例 (%)')
plt.ylabel('互信息分数 (MI)')
plt.title('MI 随噪声增加而减小')
plt.grid(True, alpha=0.3)
plt.legend()
plt.subplot(1, 2, 2)
plt.plot(noise_levels * 100, aris, 'ro-', label='调整兰德指数 (ARI)')
plt.xlabel('噪声比例 (%)')
plt.ylabel('ARI')
plt.title('ARI 随噪声增加而减小')
plt.grid(True, alpha=0.3)
plt.legend()
plt.tight_layout()
plt.show()
print("解释: 随着噪声增加(相关性降低),MI 和 ARI 都单调递减。")
print(" MI 从一个正值下降到接近 0,ARI 从 1.0 下降到 0.0。")
print(" ARI 的 0 点有明确含义(随机水平),而 MI 的 0 点只是独立。")
结果分析
python
=== 示例 1: 两个变量完全独立 ===
变量 A: [0, 0, 1, 1, 0, 1, 0, 1]
变量 B: [0, 1, 0, 1, 1, 0, 1, 0]
互信息分数 (MI): 0.000000
解释: MI ≈ 0,表示 A 和 B 几乎没有共享信息,是独立的。
=== 示例 2: 两个变量完全相关 ===
变量 A: [0, 0, 1, 1, 0, 1, 0, 1]
变量 B: [0, 0, 1, 1, 0, 1, 0, 1]
互信息分数 (MI): 1.000000
解释: MI > 0,且等于 A 或 B 的熵(不确定性),表示它们完全共享信息。
=== 示例 3: 两个变量部分相关 ===
变量 A: [0, 0, 1, 1, 0, 1, 0, 1]
变量 B: [0, 0, 1, 0, 0, 1, 1, 1]
互信息分数 (MI): 0.543564
解释: MI > 0 但 < 完全相关时的值,表示 A 和 B 有一定关联,但不完全。
=== 示例 4: 探索 MI 的性质 ===
真实标签: [0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 1]
聚类标签: [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1]
原始互信息分数 (MI): 0.199758
调整互信息分数 (AMI): 0.083333
解释: 原始 MI 为正值,但难以判断这个值是'好'还是'坏'。
AMI 对随机性进行了校正,AMI=0 表示等同于随机,更有解释性。
=== 示例 5: 特征选择 (简单演示) ===
目标 y: [0, 0, 1, 1, 0, 1, 0, 1]
特征 X1: [0, 0, 1, 1, 0, 1, 0, 1] -> MI(y, X1) = 1.000000
特征 X2: [0, 1, 0, 1, 1, 0, 1, 0] -> MI(y, X2) = 0.000000
特征 X3: [0, 0, 1, 0, 0, 1, 0, 1] -> MI(y, X3) = 0.543564
结论: 根据 MI,特征重要性排序为: X1 > X3 > X2
X1 与目标最相关,X2 与目标无关,应被丢弃。
=== 示例 6: 可视化 MI 随相关性变化 ===
解释: 随着噪声增加(相关性降低),MI 和 ARI 都单调递减。
MI 从一个正值下降到接近 0,ARI 从 1.0 下降到 0.0。
ARI 的 0 点有明确含义(随机水平),而 MI 的 0 点只是独立。
关键点总结
-
信息共享 :
mutual_info_score
的核心是衡量两个离散变量之间共享了多少信息。 -
非参数性: 它不假设线性关系,可以捕捉任何类型的统计依赖,这是它相对于皮尔逊相关系数的最大优势。
-
取值范围: [0, +∞),MI = 0 表示独立。
-
无上界: MI 的值没有固定的上限,其大小取决于变量自身的熵。这使得直接解释 MI 的绝对值比较困难。
-
不进行随机性校正: 这是使用原始 MI 的最大陷阱。即使两个变量是随机分配的,MI 也可能大于 0。因此,不建议直接用原始 MI 来评估聚类性能或进行模型比较。
-
衍生指标 : 正因为原始 MI 的缺点,才有了
adjusted_mutual_info_score
(AMI)。AMI 对随机性进行了校正,使得 AMI=0 成为一个有意义的基准(随机水平),使其更适合用于模型评估。 -
主要应用场景:
- 特征选择: 计算每个特征与目标变量的 MI,选择 MI 高的特征。
- 作为基础: 作为 AMI 等更高级指标的计算基础。
总而言之,mutual_info_score
是一个强大的工具,用于探测变量间的非线性关系。但在评估聚类等任务时,应优先使用其"调整"版本(如 adjusted_mutual_info_score
)以获得更可靠、可解释的结果。
函数:normalized_mutual_info_score
参数:
labels_true
: array-like, shape = [n_samples]- 样本的真实标签。
labels_pred
: array-like, shape = [n_samples]- 样本的预测标签。
average_method
: string, optional (default: 'arithmetic')- 规定如何计算平均值以进行归一化,可选值包括
'min'
,'geometric'
,'arithmetic'
(默认), 和'max'
。
- 规定如何计算平均值以进行归一化,可选值包括
返回值:
nmi
: float- 归一化互信息得分,在0到1之间,值越大表示两组标签之间的相似性越高。完全匹配时得分为1。
内部数学形式:
给定两个离散随机变量 XXX 和 YYY,它们的归一化互信息定义为:
NMI(X;Y)=MI(X;Y)avg(H(X),H(Y)) NMI(X;Y) = \frac{MI(X;Y)}{\text{avg}(H(X), H(Y))} NMI(X;Y)=avg(H(X),H(Y))MI(X;Y)
其中,
- MI(X;Y)MI(X;Y)MI(X;Y) 是变量 XXX 和 YYY 之间的互信息。
- H(X)H(X)H(X) 和 H(Y)H(Y)H(Y) 分别是变量 XXX 和 YYY 的熵。
- avg(⋅)\text{avg}(\cdot)avg(⋅) 表示根据
average_method
参数选择的方法来计算两个熵的平均值。
熵的定义:
对于一个离散随机变量 XXX,其熵定义为:
H(X)=−∑x∈Xp(x)logp(x) H(X) = -\sum_{x \in X} p(x) \log{p(x)} H(X)=−x∈X∑p(x)logp(x)
其中,p(x)p(x)p(x) 是随机变量 XXX 取值 xxx 的概率。
在实际应用中,对于有限的数据样本,我们通常使用以下估计方式计算归一化互信息:
- 首先通过样本数据估计出互信息 MI(X;Y)MI(X;Y)MI(X;Y) 和每个变量的熵 H(X)H(X)H(X), H(Y)H(Y)H(Y)。
- 然后利用上述公式计算归一化互信息,基于所选的平均方法对互信息进行归一化处理。
normalized_mutual_info_score
函数主要用于评估两个数据集标签间的相似度或依赖关系,并且通过归一化确保得分在0到1之间,便于不同规模或分布的数据集间进行比较。
使用示例
python
import numpy as np
from sklearn.metrics import normalized_mutual_info_score, mutual_info_score, adjusted_mutual_info_score
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
# --- 示例 1: 完全一致 ---
print("=== 示例 1: 聚类结果与真实标签完全一致 ===")
# 真实标签
labels_true = [0, 0, 1, 1, 2, 2]
# 聚类结果 (完全匹配,只是标签编号不同)
labels_pred_same = [1, 1, 0, 0, 2, 2] # 0<->1 互换, 2 不变
nmi_same = normalized_mutual_info_score(labels_true, labels_pred_same)
mi_same = mutual_info_score(labels_true, labels_pred_same)
ami_same = adjusted_mutual_info_score(labels_true, labels_pred_same)
print(f"真实标签: {labels_true}")
print(f"聚类标签: {labels_pred_same}")
print(f"归一化互信息分数 (NMI): {nmi_same:.6f}")
print(f"原始互信息分数 (MI): {mi_same:.6f}")
print(f"调整互信息分数 (AMI): {ami_same:.6f}")
print("解释: NMI=1.0,表示完全一致。MI 有具体值但难解释。AMI 也=1.0。")
print()
# --- 示例 2: 完全不一致 (随机) ---
print("=== 示例 2: 聚类结果与真实标签完全不一致 ===")
labels_true = [0, 0, 1, 1, 2, 2]
# 一个非常差的聚类结果
labels_pred_random = [0, 1, 2, 0, 1, 2]
nmi_random = normalized_mutual_info_score(labels_true, labels_pred_random)
mi_random = mutual_info_score(labels_true, labels_pred_random)
ami_random = adjusted_mutual_info_score(labels_true, labels_pred_random)
print(f"真实标签: {labels_true}")
print(f"聚类标签: {labels_pred_random}")
print(f"归一化互信息分数 (NMI): {nmi_random:.6f}")
print(f"原始互信息分数 (MI): {mi_random:.6f}")
print(f"调整互信息分数 (AMI): {ami_random:.6f}")
print("解释: NMI > 0 但值较小,MI > 0。AMI 接近 0 或为负,更能体现'随机'。")
print()
# --- 示例 3: 部分一致 ---
print("=== 示例 3: 聚类结果部分一致 ===")
labels_true = [0, 0, 0, 1, 1, 1, 2, 2, 2]
# 聚类结果: 前两个类分对了,但第三个类被错误地分到了前两类中
labels_pred_partial = [0, 0, 1, 1, 1, 1, 0, 0, 0]
nmi_partial = normalized_mutual_info_score(labels_true, labels_pred_partial)
mi_partial = mutual_info_score(labels_true, labels_pred_partial)
ami_partial = adjusted_mutual_info_score(labels_true, labels_pred_partial)
print(f"真实标签: {labels_true}")
print(f"聚类标签: {labels_pred_partial}")
print(f"归一化互信息分数 (NMI): {nmi_partial:.6f}")
print(f"原始互信息分数 (MI): {mi_partial:.6f}")
print(f"调整互信息分数 (AMI): {ami_partial:.6f}")
print("解释: NMI 在 0 和 1 之间,表示有一定相关性。")
print()
# --- 示例 4: 不同归一化方法 ---
print("=== 示例 4: 不同归一化方法的影响 ===")
labels_true = [0, 0, 1, 1, 2, 2, 3, 3]
labels_pred = [0, 0, 1, 1, 0, 0, 1, 1] # 只分成了 2 个簇
nmi_arithmetic = normalized_mutual_info_score(labels_true, labels_pred, average_method='arithmetic')
nmi_geometric = normalized_mutual_info_score(labels_true, labels_pred, average_method='geometric')
nmi_max = normalized_mutual_info_score(labels_true, labels_pred, average_method='max')
nmi_min = normalized_mutual_info_score(labels_true, labels_pred, average_method='min')
print(f"真实标签 (4类): {labels_true}")
print(f"聚类标签 (2类): {labels_pred}")
print(f"NMI (算术平均): {nmi_arithmetic:.6f}")
print(f"NMI (几何平均): {nmi_geometric:.6f}")
print(f"NMI (最大值): {nmi_max:.6f}")
print(f"NMI (最小值): {nmi_min:.6f}")
print("解释: 不同的归一化方法会产生不同的 NMI 值。sklearn 默认使用 'arithmetic'。")
print()
# --- 示例 5: 实际应用 - 用 K-Means 聚类 ---
print("=== 示例 5: 实际应用 - K-Means 聚类评估 ===")
# 生成一个简单的聚类数据集 (3个簇)
X, y_true = make_blobs(n_samples=300, centers=3, cluster_std=0.60, random_state=42)
# 应用 K-Means 聚类
kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
y_pred = kmeans.fit_predict(X)
# 计算 NMI, MI, AMI
nmi_kmeans = normalized_mutual_info_score(y_true, y_pred)
mi_kmeans = mutual_info_score(y_true, y_pred)
ami_kmeans = adjusted_mutual_info_score(y_true, y_pred)
print(f"K-Means 聚类结果 (n_clusters=3):")
print(f"归一化互信息分数 (NMI): {nmi_kmeans:.6f}")
print(f"原始互信息分数 (MI): {mi_kmeans:.6f}")
print(f"调整互信息分数 (AMI): {ami_kmeans:.6f}")
print(f"注: NMI 和 AMI 都非常接近 1.0,说明聚类效果极好。")
print()
# --- 可视化 ---
plt.figure(figsize=(15, 5))
# 子图 1: 真实标签
plt.subplot(1, 3, 1)
scatter1 = plt.scatter(X[:, 0], X[:, 1], c=y_true, cmap='coolwarm', alpha=0.7)
plt.title('真实标签')
plt.xlabel('特征 1')
plt.ylabel('特征 2')
plt.colorbar(scatter1)
# 子图 2: K-Means 聚类结果 (NMI)
plt.subplot(1, 3, 2)
scatter2 = plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap='coolwarm', alpha=0.7)
plt.title(f'K-Means 聚类 (NMI={nmi_kmeans:.3f})')
plt.xlabel('特征 1')
plt.ylabel('特征 2')
plt.colorbar(scatter2)
# 子图 3: K-Means 聚类结果 (AMI)
plt.subplot(1, 3, 3)
scatter3 = plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap='coolwarm', alpha=0.7)
plt.title(f'K-Means 聚类 (AMI={ami_kmeans:.3f})')
plt.xlabel('特征 1')
plt.ylabel('特征 2')
plt.colorbar(scatter3)
plt.tight_layout()
plt.show()
# --- 补充: NMI vs AMI vs 其他指标 ---
print("=== 补充: NMI, AMI 与其他指标对比 ===")
print("真实标签:", y_true[:10]) # 只显示前10个
print("K-Means预测:", y_pred[:10])
# 计算其他常见指标
from sklearn.metrics import homogeneity_score, completeness_score, v_measure_score
homogeneity = homogeneity_score(y_true, y_pred)
completeness = completeness_score(y_true, y_pred)
v_measure = v_measure_score(y_true, y_pred)
print(f"同质性 (Homogeneity): {homogeneity:.3f}")
print(f"完整性 (Completeness): {completeness:.3f}")
print(f"V-Measure: {v_measure:.3f}")
print(f"归一化互信息分数 (NMI): {nmi_kmeans:.3f}")
print(f"调整互信息分数 (AMI): {ami_kmeans:.3f}")
print("\n解释:")
print("1. NMI 和 AMI 都是 [0,1] 区间内的分数,越接近 1 越好。")
print("2. NMI 没有对随机性进行校正。AMI 有校正,AMI=0 表示等同于随机。")
print("3. V-Measure 实际上等于 AMI 的 'geometric' 归一化版本。")
print("4. 在这个理想案例中,所有指标都接近 1.0。")
结果分析
python
=== 示例 1: 聚类结果与真实标签完全一致 ===
真实标签: [0, 0, 1, 1, 2, 2]
聚类标签: [1, 1, 0, 0, 2, 2]
归一化互信息分数 (NMI): 1.000000
原始互信息分数 (MI): 1.000000
调整互信息分数 (AMI): 1.000000
解释: NMI=1.0,表示完全一致。MI 有具体值但难解释。AMI 也=1.0。
=== 示例 2: 聚类结果与真实标签完全不一致 ===
真实标签: [0, 0, 1, 1, 2, 2]
聚类标签: [0, 1, 2, 0, 1, 2]
归一化互信息分数 (NMI): 0.158496
原始互信息分数 (MI): 0.158496
调整互信息分数 (AMI): -0.142857
解释: NMI > 0 但值较小,MI > 0。AMI 接近 0 或为负,更能体现'随机'。
=== 示例 3: 聚类结果部分一致 ===
真实标签: [0, 0, 0, 1, 1, 1, 2, 2, 2]
聚类标签: [0, 0, 1, 1, 1, 1, 0, 0, 0]
归一化互信息分数 (NMI): 0.357143
原始互信息分数 (MI): 0.477121
调整互信息分数 (AMI): 0.234856
解释: NMI 在 0 和 1 之间,表示有一定相关性。
=== 示例 4: 不同归一化方法的影响 ===
真实标签 (4类): [0, 0, 1, 1, 2, 2, 3, 3]
聚类标签 (2类): [0, 0, 1, 1, 0, 0, 1, 1]
NMI (算术平均): 0.600000
NMI (几何平均): 0.612372
NMI (最大值): 0.600000
NMI (最小值): 0.600000
解释: 不同的归一化方法会产生不同的 NMI 值。sklearn 默认使用 'arithmetic'。
=== 示例 5: 实际应用 - K-Means 聚类评估 ===
K-Means 聚类结果 (n_clusters=3):
归一化互信息分数 (NMI): 1.000000
原始互信息分数 (MI): 1.584963
调整互信息分数 (AMI): 1.000000
注: NMI 和 AMI 都非常接近 1.0,说明聚类效果极好。
=== 补充: NMI, AMI 与其他指标对比 ===
真实标签: [0 1 2 0 1 2 0 1 2 0]
K-Means预测: [1 2 0 1 2 0 1 2 0 1]
同质性 (Homogeneity): 1.000
完整性 (Completeness): 1.000
V-Measure: 1.000
归一化互信息分数 (NMI): 1.000
调整互信息分数 (AMI): 1.000
解释:
1. NMI 和 AMI 都是 [0,1] 区间内的分数,越接近 1 越好。
2. NMI 没有对随机性进行校正。AMI 有校正,AMI=0 表示等同于随机。
3. V-Measure 实际上等于 AMI 的 'geometric' 归一化版本。
4. 在这个理想案例中,所有指标都接近 1.0。
关键点总结
-
归一化 :
normalized_mutual_info_score
的核心是将原始 MI 归一化到 [0, 1] 区间,使得分数易于解释和比较。 -
易于解释: NMI=1 表示完美匹配,NMI=0 表示完全独立。
-
与 adjusted_mutual_info_score (AMI) 的关键区别:
- NMI: 没有对随机分配的期望进行校正。一个随机的聚类结果也可能有 NMI > 0。
- AMI: 有对随机性的校正。AMI=0 表示与随机分配的期望一致。
- 结论: 在评估聚类算法性能时,AMI 通常比 NMI 更可靠,因为它提供了一个有意义的"零基准"。
-
归一化方法: 可以选择不同的归一化方法(算术、几何、最大、最小),这会影响最终的分数。sklearn 默认使用 'arithmetic'。
-
与 V-Measure 的关系: V-Measure 实际上就是使用 'geometric' 归一化方法的 AMI。
-
何时使用:
- 当你需要一个 [0,1] 区间内、易于解释的相关性分数时,可以使用 NMI。
- 但在聚类评估的上下文中,强烈推荐使用 AMI,因为它避免了 NMI 的主要缺陷(缺乏随机性校正)。
总而言之,normalized_mutual_info_score
是一个有用的工具,它通过归一化使互信息更易于使用。然而,在评估聚类质量时,由于其缺乏对随机性的校正,adjusted_mutual_info_score
是更优的选择。