该文档涉及的组件

聚类评估 (EvalClusterBatchOp)

Java 类名:com.alibaba.alink.operator.batch.evaluation.EvalClusterBatchOp

Python 类名:EvalClusterBatchOp

功能介绍

对聚类算法的预测结果进行效果评估。

算法原理

在下面的指标中,用 $C_i$ 表示第 $i$ 个簇, $u_i$ 表示$C_i$ 的中心,$k$ 表示簇的总数。

Compactness(CP)

$\overline{CP_i}=\dfrac{1}{|C_i|}\sum_{x \in C_i}|x_i-u_i|$

$\overline{CP}=\dfrac{1}{k}\sum_{i=1}^{k}\overline{CP_k}$

CP越低意味着类内聚类距离越近。

Separation (SP)

$SP=\dfrac{2}{k^2-k}\sum_{i=1}^{k}\sum_{j=i+1}^{k}|u_i-u_j|$

SP越高意味类间聚类距离越远。

Davies-Bouldin Index (DB)

$DB=\dfrac{1}{k}\sum_{i=1}^{k}\max_{i \not=j}(\dfrac{\overline{CP_i}+\overline{CP_j}}{|u_i-u_j|})$

DB越小意味着类内距离越小,同时类间距离越大。

Calinski-Harabasz Index (Variance Ratio Criterion, VRC)

用 $u$ 表示数据集整体的中心点,

$SSB=\sum_{i=1}^{k}n_i|u_i-u|^2,$

$SSW=\sum_{i=1}^{k}\sum_{x \in C_i}|x_i-u_i|,$

$\mathrm{VRC}=\dfrac{SSB}{SSW}*\dfrac{N-k}{k-1}$

VRC越大意味着聚类质量越好。

另有一部分聚类评价指标称作外部指标(external criterion)。
这些指标在评估时除了有每个样本点所属的簇之外,还假设每个样本点有类别标签。

在下面的指标中,$N$表示簇的总数,用 $\omega_k$ 表示簇$k$所包含的样本点集合,$c_j$ 表示类别标签为 $j$ 的样本点集合。

Purity

$Purity(\Omega, C)=\dfrac{1}{N}\sum_{k}\max_{j}|\omega_k \cap c_j|$

取值在 $[0,1]$ 区间内,越接近1表示同一个簇内相同类别的数据点越多,聚类结果越好。

Normalized Mutual Information (NMI), NMI在[0,1]区间内, 越接近1表示聚类结果越好

$H(\Omega)=-\sum_{k}\dfrac{\omega_k}{N}log\dfrac{\omega_k}{N},$

$H(C)=-\sum_{j}\dfrac{c_j}{N}log\dfrac{c_j}{N},$

$I(\Omega, C)=\sum_k\sum_j\dfrac{|\omega_k \cap c_j|}{N}\log \dfrac{N|\omega_k \cap c_j|}{|\omega_k||c_j|},$

$\mathrm{NMI}=\dfrac{2 * I(\Omega, C)}{H(\Omega) + H(C)}$

取值在 $[0,1]$ 区间内, 越接近1表示聚类结果越好。

Rand Index (RI)

对于任意一对样本点:
- 如果标签相同并且属于相同的簇,则认为是 TP (True Positive);
- 如果标签不同并且属于不同的簇,则认为是 TN (True Negative);
- 如果标签相同并且属于不同的簇,则认为是 FN (False Negative);
- 如果标签不同并且属于相同的簇,则认为是 FP (False Positive)。

用 $TP, TN, FN, FP$ 分别表示属于各自类别的样本点对的个数,$N(k,j)$ 表示簇 $k$ 内类别为 $j$ 的样本点个数,那么有:

$TP+FP=\sum_{j}\binom{c_j}{2},$

$TP+FN=\sum_{k}\binom{\omega_k}{2},$

$TP=\sum_{k}\sum_{j}\binom{N(k,j)}{2},$

$TP+TN+FP+FN= \binom{N}{2},$

$RI=\dfrac{TP+TN}{TP+TN+FP+FN}$

取值在 $[0,1]$ 区间内,越接近1表示聚类结果越好。

Adjusted Rand Index(ARI), ARI在[-1,1]区间内,越接近1表示聚类结果越好

$\mathrm{Index}=TP,$

$\mathrm{ExpectedIndex}=\dfrac{(TP+FP)(TP+FN)}{TP+TN+FP+FN},$

$\mathrm{MaxIndex}=\dfrac{TP+FP+TP+FN}{2},$

$ARI=\dfrac{\mathrm{Index} - \mathrm{ExpectedIndex}}{\mathrm{MaxIndex} - \mathrm{ExpectedIndex}}$
E
取值在 $[-1,1]$ 区间内,越接近1表示聚类结果越好。

使用方式

该组件通常接聚类算法的输出端。

使用时,需要通过 predictionCol 指定预测结果类。 通常还需要通过 vectorCol 指定样本点的坐标,这样才能计算评估指标。否则,只能输出样本点所属簇等基本信息。
另外,可以根据需要指定标签列 labelCol,这样可以计算外部指标。

参数说明

名称 中文名称 描述 类型 是否必须? 取值范围 默认值
predictionCol 预测结果列名 预测结果列名 String ✓
distanceType 距离度量方式 距离类型 String “EUCLIDEAN”, “COSINE”, “CITYBLOCK” “EUCLIDEAN”
labelCol 标签列名 输入表中的标签列名 String null
vectorCol 向量列名 输入表中的向量列名 String 所选列类型为 [DENSE_VECTOR, SPARSE_VECTOR, STRING, VECTOR] null

代码示例

Python 代码

from pyalink.alink import *

import pandas as pd

useLocalEnv(1)

df = pd.DataFrame([
    [0, "0 0 0"],
    [0, "0.1,0.1,0.1"],
    [0, "0.2,0.2,0.2"],
    [1, "9 9 9"],
    [1, "9.1 9.1 9.1"],
    [1, "9.2 9.2 9.2"]
])

inOp = BatchOperator.fromDataframe(df, schemaStr='id int, vec string')

metrics = EvalClusterBatchOp().setVectorCol("vec").setPredictionCol("id").linkFrom(inOp).collectMetrics()

print("Total Samples Number:", metrics.getCount())
print("Cluster Number:", metrics.getK())
print("Cluster Array:", metrics.getClusterArray())
print("Cluster Count Array:", metrics.getCountArray())
print("CP:", metrics.getCp())
print("DB:", metrics.getDb())
print("SP:", metrics.getSp())
print("SSB:", metrics.getSsb())
print("SSW:", metrics.getSsw())
print("CH:", metrics.getVrc())

Java 代码

import org.apache.flink.types.Row;

import com.alibaba.alink.operator.batch.BatchOperator;
import com.alibaba.alink.operator.batch.evaluation.EvalClusterBatchOp;
import com.alibaba.alink.operator.batch.source.MemSourceBatchOp;
import com.alibaba.alink.operator.common.evaluation.ClusterMetrics;
import org.junit.Test;

import java.util.Arrays;
import java.util.List;

public class EvalClusterBatchOpTest {
	@Test
	public void testEvalClusterBatchOp() throws Exception {
		List <Row> df = Arrays.asList(
			Row.of(0, "0 0 0"),
			Row.of(0, "0.1,0.1,0.1"),
			Row.of(0, "0.2,0.2,0.2"),
			Row.of(1, "9 9 9"),
			Row.of(1, "9.1 9.1 9.1"),
			Row.of(1, "9.2 9.2 9.2")
		);
		BatchOperator <?> inOp = new MemSourceBatchOp(df, "id int, vec string");
		ClusterMetrics metrics = new EvalClusterBatchOp().setVectorCol("vec").setPredictionCol("id").linkFrom(inOp)
			.collectMetrics();
		System.out.println("Total Samples Number:" + metrics.getCount());
		System.out.println("Cluster Number:" + metrics.getK());
		System.out.println("Cluster Array:" + Arrays.toString(metrics.getClusterArray()));
		System.out.println("Cluster Count Array:" + Arrays.toString(metrics.getCountArray()));
		System.out.println("CP:" + metrics.getCp());
		System.out.println("DB:" + metrics.getDb());
		System.out.println("SP:" + metrics.getSp());
		System.out.println("SSB:" + metrics.getSsb());
		System.out.println("SSW:" + metrics.getSsw());
		System.out.println("CH:" + metrics.getVrc());
	}
}

运行结果

Total Samples Number: 6
Cluster Number: 2
Cluster Array: ['0', '1']
Cluster Count Array: [3.0, 3.0]
CP: 0.11547005383792497
DB: 0.014814814814814791
SP: 15.588457268119896
SSB: 364.5
SSW: 0.1199999999999996
CH: 12150.000000000042