K 均值聚类是最基础的一种聚类方法。它是一种迭代求解的聚类分析算法。
给各个簇中心 μ 1 , … , μ c \mu_1,\dots,\mu_c μ1,…,μc 以适当的初值;
更新样本 x 1 , … , x n x_1,\dots,x_n x1,…,xn 对应的簇标签 y 1 , … , y n y_1,\dots,y_n y1,…,yn
y i ← a r g m i n y ∈ { 1 , … , c } ∣ ∣ x i − μ y ∣ ∣ 2 , i = 1 , … , n y_i\leftarrow argmin_{y\in \{1,\dots,c\}}||x_i-\mu_y||^2,\ \ \ i=1,\dots,n yi←argminy∈{1,…,c}∣∣xi−μy∣∣2, i=1,…,n
更新各个簇中心 μ 1 , … , μ c \mu_1,\dots,\mu_c μ1,…,μc
μ y ← 1 n y ∑ i : y i = y x i , y = 1 , … , c \mu_y\leftarrow \frac{1}{n_y}\sum_{i:y_i=y}x_i,\ \ \ y=1,\dots,c μy←ny1i:yi=y∑xi, y=1,…,c
其中, n y n_y ny 为属于簇 y y y 的类别总数
重复上述步骤2, 3,直到簇标签不再变化(变化足够小),达到收敛精度为止
优点
缺点
伪代码:
创建 k 个点作为起始质心 (随机选择):
当任意一个点的簇分配结果发生改变的时候:
对数据集中的每个数据点:
对每个质心:
计算质心与数据点之间的距离
将数据点分配到距其最近的簇
对每一个簇:
求出均值并将其更新为质心
Python实现:
import numpy as np
def kmeans(data, n_clusters, tolerence):
n_samples = data.shape[0]
sample_asign = np.zeros((n_samples, 2))
cluster_centers = data[: n_clusters, :]
isChanged = True
epoch_cnt = 0
while isChanged:
epoch_cnt += 1
isChanged = False
# 更新每个样本点所属于的类
for sample_index in range(n_samples):
min_dist = np.inf
min_index = 0
for cluster_index in range(n_clusters):
dist = np.linalg.norm(data[sample_index, :] - cluster_centers[cluster_index, :])
if dist < min_dist:
min_dist = dist
min_index = cluster_index
sample_asign[sample_index, :] = min_dist, min_index
# 更新每个聚类中心
for cluster_index in range(n_clusters):
new_cluster_samples = data[ sample_asign[:, 1] == cluster_index ]
new_center = np.mean(new_cluster_samples, axis=0)
cluster_center_diff = np.linalg.norm( new_center - cluster_centers[cluster_index, :] )
cluster_centers[cluster_index, :] = new_center
if cluster_center_diff > tolerence:
isChanged = True
print(f"epoch count: {epoch_cnt}")
return cluster_centers
if __name__ == '__main__':
n_samples = 512
data_dim = 3
n_clusters = 4
data = np.random.randn(n_samples, data_dim)
tol = 1e-12
centers = kmeans(data, n_clusters, tol)
print(centers)
kmeans 手写实现主要还是为了理解算法,在实际应用中,我们一般调 sklearn 的包就好了。
class sklearn.cluster.KMeans(n_clusters=8, init='k-means++', n_init=10, max_iter=300, tol=0.0001, verbose=0, random_state=None, copy_x=True, algorithm='lloyd')
函数签名 | 说明 |
---|---|
fit(X[, y, sample_weight]) | 计算 kmeans 聚类 |
fit_predict(X[, y, sample_weight]) | 计算 kmeans 聚类并预测每个样本的簇序号 |
fit_transform(X[, y, sample_weight]) | 计算 kmeans 聚类并将 X 转换到聚类距离空间 |
get_feature_names_out([input_features]) | 获取转换的输出特征名称 |
get_params([deep]) | 获取 estimator 的参数 |
predict(X[, sample_weight]) | 预测 X 中每个样本所属于的簇 |
score(X[, y, sample_weight]) | (看起来是评估模型的准确率) |
set_params(**params) | 设置 estimator 的参数 |
transform(X) | 将 X 转换到聚类距离空间 |
需要通过 joblib 来保存,安装:
pip install joblib
保存/加载模型
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
import joblib
x, y = make_blobs(n_samples=1000, n_features=4, centers=[[-1, -1], [0, 0], [1, 1], [2, 2]], cluster_std=[0.4, 0.2, 0.2, 0.4], random_state=42)
model = KMeans(n_clusters=6)
model.fit(x, y)
print(model.cluster_centers_)
# 保存模型
joblib.dump(model, 'kmeans_model.pkl')
# 加载模型
model = joblib.load('kmeans_model.pkl')
print(model.cluster_centers_)