K-Means
from sklearn.cluster import KMeans
k = 5
kmeans = KMeans(n_clusters=k)
y_pred = kmeans.predict(X)
# 算法的k个中心点
kmeans.cluster_centers_
# 每个实例到中心点距离 (软聚类)
kmeans.transform(X)
# 训练实例的标签副本
kmeans.labels_
中心点初始化方法
如果事先知道了中心点位置, 可以将超参数init设置为中心点列表的NumPy数组
good_init = np.array([[-3, 3], [-3, 2], [-3, 1], [-1, 2], [0, 2]])
kmeans = KMeans(n_clusters=5, init=good_init, n_init=1)
另一种方案:使用不同的随机化运行多次算法, 保留最优解。 随机初始化的数量由超参数n_init控制:默认情况为10。 性能的指标称为模型的惯性, 为每个实例与其最近的中心点的均方距离。 可以通过kmeans.inertia访问, score()返回负惯性。
加速的K-Means和小批量K-Means
加速的K-Means 默认使用, 通过三角不等式并跟踪实例和中心点之间上下限距离来实现。
小批量K-Means, 速度更快, 但惯性更差一些
from sklearn.cluster import MiniBatchKMeans
minibatch_kmeans = MiniBatchKMeans(n_clusters=5)
minibatch_kmeans.fit(X)
寻找最佳聚类数
粗糙方案:绘制惯性作为集群k的函数曲线, 曲线通常包含一个称为“肘”的拐点, 可以将其作为聚类数的选择。
更精确的方案:轮廓分数(所有实例的平均轮廓系数)
实例的轮廓系数: (b-a)/ max(a, b)
a : 集群内平均距离, 即与同一集群中其他实例的平均距离
b : 平均最近集群距离, 即到下一个最近集群的平均距离, 定义b是最小的那个,不包括实例自身的集群
轮廓系数 ∈ [-1,+1]
接近+1的系数表示该实例很好的位于自身的集群中, 并且远离其他集群
接近 0的系数表示该实例接近一个集群的边界
接近-1的系数表示该实例可能已经分配给了错误的集群
# 计算轮廓分数
from sklearn.metrics import silhouette_score
silhouette_score(X, kmeans.labels_)
使用聚类进行图像分割
# 加载图像
from matplotlib.image import imread
image = imread(os.path.join("image", "unsuperised_learning", "ladybug.png"))
# 将颜色聚类
X = image.reshape(-1, 3)
kmeans = KMeans(n_clusters=8).fit(X)
segmented_img = kmeans.cluster_centers_[kmeans.labels_]
segmented_img = segmented_img.reshape(image.shape)
使用聚类进行预处理
# 例子:处理数字数据集
# 加载数据集
from sklearn.datasets import load_digits
X_digits, y_digits = load_digits(return_X_y=True)
# 分为训练集和测试集
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X_digits, y_digits)、
# 拟合逻辑回归模型
from sklearn.linear_model import LogisticRegression
log_reg = LogisticRegression()
log_reg.fit(X_train, y_train)
# 测试集上评估精度
>>> log_reg.score(X_test, y_test)
0.96 # 以此为基准
# 用kmeans作为预处理
from sklearn.pipeline import Pipeline
from sklearn.cluster import KMeans
pipeline = Pipeline([
("kmeans", KMeans(n_clusters=50)),
("log_reg", LogisticRegression())
])
pipeline.fit(X_train, y_train)
>>> pipeline.score(X_test, y_test)
0.9622222222222222
# 网格搜索k最优解, 及此时的性能
from sklearn.model_selection import GridSearchCV
param_grid = dict(kmeans__n_clusters=range(2, 100))
grid_clf = GridSearchCV(pipeline, param_grid, cv=3, verbose=2)
grid_clf.fit(X_train, y_train)
>>> grid_clf.best_params_
{'kmeans__n_clusters': 86}
>>> grid_clf.score(X_test, y_test)
0.9644444444444444
使用聚类进行半监督学习
DBSCAN
工作原理:
# 对于每个实例, 计算距它一小段距离epsilon内有多少实例。该区域称为实例的epsilon-邻域
# 如果一个实例在其epsilon邻域中至少包含min_samples个实例(包括自身), 则该实例视为核心实例
# 核心邻域的所有实例都属于同一集群。 这个邻域可能包含其他核心实例, 因此, 一长串相邻的核心实例形成一个集群。
# 任何不是核心实例且邻居中没有实例的实例都被视为异常
from sklearn.cluster import DBSCAN
from sklearn.datasets import make_moons
X, y = make_moons(n_samples=1000, noise=0.05)
dbscan = DBSCAN(eps=0.05, min_samples=5)
dbscan.fit(X)
>>>dbscan.labels_
array([ 0, 1, 2, -1, 1, 3, 4, 0, 1, 1], dtype=int64)
# 集群索引为-1的实例视为异常
# 核心实例的索引
>>>dbscan.core_sample_indices_
array([ 0, 1, 2, 4, 997, 998, 999], dtype=int64)
# 核心实例本身
>>> dbscan.components_
array([[-0.61335521, 0.75630075],
[ 0.18891419, 0.96079214],
[ 1.71429492, -0.282264 ],
...,
[-0.65099898, 0.64982719],
[ 1.02107467, 0.13306044],
[-0.33691843, 0.9684963 ]])
DBSCAN有fit_predict()方法, 但不具有predict()方法, 由用户选择分类算法
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=50)
knn.fit(dbscan.components_, dbscan.labels_[dbscan.core_sample_indices_])
import numpy as np
X_new = np.array([[-0.5, 0], [0, 0.5], [1, -0.1], [2, 1]])
>>> knn.predict(X_new)
array([7, 4, 1, 9], dtype=int64)
>>> knn.predict_proba(X_new)
array([[0. , 0. , 0. , 0. , 0.08, 0.06, 0. , 0.64, 0.22, 0. , 0. ],
[0. , 0. , 0. , 0. , 1. , 0. , 0. , 0. , 0. , 0. , 0. ],
[0. , 0.76, 0. , 0. , 0. , 0. , 0.24, 0. , 0. , 0. , 0. ],
[0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 1. , 0. ]])