原文链接
\qquad 在sklearn中,BIRCH类(Balanced Iterative Reducing and Clustering Using Hierarchies 利用层次方法的平衡迭代规约和聚类)实现了基于特征树CF Tree的聚类。因此要使用BIRCH来聚类,关键是对CF Tree结构参数的处理。
\qquad 在CF Tree中,几个关键的参数为内部节点的最大CF数B,叶子节点的最大CF数L, 叶节点每个CF的最大样本半径阈值T。这三个参数定了,CF Tree的结构也基本确定了,最后的聚类效果也基本确定。可以说BIRCH的调参就是调试B,L和T。
\qquad 至于类别数K,此时反而是可选的,不输入K,则BIRCH会对CF Tree里各叶子节点CF中样本的情况自己决定类别数K值,如果输入K值,则BIRCH会CF Tree里各叶子节点CF进行合并,直到类别数为K。
\qquad 在sklearn中,BIRCH类的重要参数不多
\qquad 1) threshold:即叶节点每个CF的最大样本半径阈值T,它决定了每个CF里所有样本形成的超球体的半径阈值。一般来说threshold越小,则CF Tree的建立阶段的规模会越大,即BIRCH算法第一阶段所花的时间和内存会越多。但是选择多大以达到聚类效果则需要通过调参决定。默认值是0.5,如果样本的方差较大,则一般需要增大这个默认值。
\qquad 2) branching_factor:即CF Tree内部节点的最大CF数B,以及叶子节点的最大CF数L。这里sklearn对这两个参数进行了统一取值。也就是说,branching_factor决定了CF Tree里所有节点的最大CF数。默认是50。如果样本量非常大,比如大于10万,则一般需要增大这个默认值。选择多大的branching_factor以达到聚类效果则需要通过和threshold一起调参决定。
\qquad 3)n_clusters:即类别数K,在BIRCH算法是可选的,如果类别数非常多,我们也没有先验知识,则一般输入None,此时BIRCH算法第4阶段不会运行。但是如果我们有类别的先验知识,则推荐输入这个可选的类别值。默认是3,即最终聚为3类。
\qquad 4)compute_labels:布尔值,表示是否标示类别输出,默认是True。一般使用默认值挺好,这样可以看到聚类效果。
\qquad 在评估各个参数组合的聚类效果时,还是推荐使用Calinski-Harabasz Index,Calinski-Harabasz Index在sklearn中对应的方法是metrics.calinski_harabaz_score.
\qquad 首先,我们载入一些随机数据,并看看数据的分布图:
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
X, y = make_blobs(n_samples=1000, n_features=2, centers=[[-1, -1], [0, 0], [1, 1], [2, 2]],
cluster_std=[0.4, 0.3, 0.2, 0.2], random_state=9)
plt.scatter(X[:, 0], X[:, 1], marker='o')
plt.show()
\qquad 现在我们用BIRCH算法来聚类,首先我们选择不输入可选的类别数K,看看聚类效果和Calinski-Harabasz 分数。
from sklearn.cluster import Birch
model = Birch(n_clusters=None)
y_pred = model.fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.show()
# Calinski-Harabasz Score 3083.3028606957146
print("Calinski-Harabasz Score", metrics.calinski_harabaz_score(X, y_pred))
\qquad 由于我们知道数据是4个簇随机产生的,因此我们可以通过输入可选的类别数4来看看BIRCH聚类的输出。代码如下:
model = Birch(n_clusters=4)
y_pred = model.fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.show()
# Calinski-Harabasz Score 4556.393277478858
print("Calinski-Harabasz Score", metrics.calinski_harabaz_score(X, y_pred))
\qquad 可见如果我们不输入类别数的话,在某些时候BIRCH算法的聚类效果并不一定好,因此这个可选的类别数K一般还是需要调参的。
\qquad 对于threshold和branching_factor我们前面还没有去调参,使用了默认的threshold值0.5和默认的branching_factor值50。
\qquad 现在我们调节threshold,让BIRCH算法第一阶段的CF Tree规模发生变化,并观察Calinski-Harabasz 分数。
ts = [0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.]
for t in ts:
y_pred = Birch(n_clusters=4, threshold=t).fit_predict(X)
print("Calinski-Harabasz Score %s threshold %s" % (metrics.calinski_harabaz_score(X, y_pred), t))
"""
Calinski-Harabasz Score 4908.560711452722 threshold 0.0
Calinski-Harabasz Score 3866.764127185188 threshold 0.1
Calinski-Harabasz Score 4497.583240691895 threshold 0.2
Calinski-Harabasz Score 1875.7129014463785 threshold 0.3
Calinski-Harabasz Score 1831.9778847965379 threshold 0.4
Calinski-Harabasz Score 4556.393277478858 threshold 0.5
Calinski-Harabasz Score 4907.597354403774 threshold 0.6
Calinski-Harabasz Score 4968.690461352885 threshold 0.7
Calinski-Harabasz Score 4968.690461352885 threshold 0.8
Calinski-Harabasz Score 2969.9498853713444 threshold 0.9
Calinski-Harabasz Score 2731.6075259762533 threshold 1.0
"""
\qquad 也就是说threshold不是越小聚类效果越好,也不是越大效果越好。
\qquad 我们基于threshold为0.3的情况,调试下branching_factor,让BIRCH算法第一阶段的CF Tree规模发生变化。
bs = [10, 20, 30, 40, 50, 60, 70]
for b in bs:
y_pred = Birch(n_clusters=4, threshold=0.3, branching_factor=b).fit_predict(X)
print("Calinski-Harabasz Score %s branching_factor %s" % (metrics.calinski_harabaz_score(X, y_pred), b))
"""
Calinski-Harabasz Score 4344.120788813106 branching_factor 10
Calinski-Harabasz Score 1944.8399270400823 branching_factor 20
Calinski-Harabasz Score 1875.7129014463785 branching_factor 30
Calinski-Harabasz Score 1875.7129014463785 branching_factor 40
Calinski-Harabasz Score 1875.7129014463785 branching_factor 50
Calinski-Harabasz Score 1875.7129014463785 branching_factor 60
Calinski-Harabasz Score 1875.7129014463785 branching_factor 70
"""
\qquad 可见调试branching_factor也可以让聚类分数提高。那么和threshold类似,需要进行调参。