机器学习入门(三),KMeans聚类
-
KNN: 算点和点之间的距离(找邻居)。
-
K-Means: 算点和“质心(老大)”之间的距离(找组织)。
-
推荐系统: 算你和商品之间的距离(猜你喜欢)。
-
大模型(Transformer): 算词向量之间的距离(语义相似度)。
1. 算法核心思想
KMeans是一种无监督学习的聚类算法,通过迭代寻找K个簇的中心点,将数据划分到最近的簇中。不一定要找真正的中心点,是开数据关系盲盒。
2. 算法步骤
步骤1:初始化
随机选择K个点作为初始聚类中心(质心),或使用KMeans++算法:让初始中心点尽量分散开
步骤2:分配数据点
计算每个数据点到所有质心的距离(通常是欧氏距离),将每个数据点分配到最近的质心所属的簇
步骤3:更新质心
重新计算每个簇中所有点的平均值,将该平均值作为新的质心
步骤4:迭代
重复步骤2和3,直到:质心位置不再明显变化,达到最大迭代次数,簇的分配不再变化
3. 距离计算公式(欧氏距离)
对于两点 $p=(x_1, y_1)$ 和 $q=(x_2, y_2)$:
d(p,q)=(x1−x2)2+(y1−y2)2
4. 示例
假设我们有5个数据点,想分为2个簇(K=2):
| 点 | X坐标 | Y坐标 |
|---|---|---|
| A | 1.0 | 1.0 |
| B | 1.5 | 2.0 |
| C | 3.0 | 4.0 |
| D | 5.0 | 7.0 |
| E | 3.5 | 5.0 |
第1次迭代:初始化
随机选择初始质心(假设选A和C):
-
质心1:C1 = A(1.0, 1.0)
-
质心2:C2 = C(3.0, 4.0)
计算距离并分配簇:
点到C1(1.0,1.0)的距离:
-
A: √[(1-1)² + (1-1)²] = 0
-
B: √[(1.5-1)² + (2-1)²] = √(0.25+1) = √1.25 ≈ 1.12
-
C: √[(3-1)² + (4-1)²] = √(4+9) = √13 ≈ 3.61
-
D: √[(5-1)² + (7-1)²] = √(16+36) = √52 ≈ 7.21
-
E: √[(3.5-1)² + (5-1)²] = √(6.25+16) = √22.25 ≈ 4.72
点到C2(3.0,4.0)的距离:
-
A: √[(1-3)² + (1-4)²] = √(4+9) = √13 ≈ 3.61
-
B: √[(1.5-3)² + (2-4)²] = √(2.25+4) = √6.25 = 2.5
-
C: 0
-
D: √[(5-3)² + (7-4)²] = √(4+9) = √13 ≈ 3.61
-
E: √[(3.5-3)² + (5-4)²] = √(0.25+1) = √1.25 ≈ 1.12
分配结果:
-
A: 距离C1(0) < 距离C2(3.61) → 簇1
-
B: 距离C1(1.12) < 距离C2(2.5) → 簇1
-
C: 距离C1(3.61) > 距离C2(0) → 簇2
-
D: 距离C1(7.21) > 距离C2(3.61) → 簇2
-
E: 距离C1(4.72) > 距离C2(1.12) → 簇2
簇分配:
-
簇1:A(1.0,1.0), B(1.5,2.0)
-
簇2:C(3.0,4.0), D(5.0,7.0), E(3.5,5.0)
第2次迭代:更新质心
计算新质心:
-
新C1 = [(1.0+1.5)/2, (1.0+2.0)/2] = (1.25, 1.5)
-
新C2 = [(3.0+5.0+3.5)/3, (4.0+7.0+5.0)/3] = (11.5/3, 16/3) ≈ (3.83, 5.33)
重新计算距离并分配...
这个过程会持续迭代,直到质心位置稳定。
数据太多,是因为标准 K-Means 每一轮迭代都要算 所有点 到质心的距离。如果有 1 亿条数据,算一次就得累死。
工业界的解法: Mini-Batch K-Means(小批量 K-Means)
-
我不算 1 亿个点。
-
我每次随机抽 1000 个点(Batch)。
-
我只用这 1000 个点来更新质心。
-
多跑几轮,质心基本上就稳定了。
-
速度: 快了 100 倍甚至 1000 倍。
-
精度: 会稍微差一丢丢(因为是抽样),但在商业上完全够用。
实现代码
def dm01_kmeans():
# 1 导入依赖包
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
# make系列-自己构造数据集 fetch系列大数据-从网络加载 load系列小数据集-从本地数据集
from sklearn.metrics import calinski_harabasz_score # calinski_harabaz_score 废弃
# 2 创建数据集 1000个样本,每个样本2个特征 4个质心蔟数据标准差[0.4, 0.2, 0.2, 0.2]
x, _ = make_blobs(
n_samples=1000,
n_features=2,
centers=[[-1, -1], [0, 0], [1, 1], [2, 2]],
cluster_std=[0.4, 0.2, 0.2, 0.2],
random_state=22
)
print(f"x = {x}")
plt.figure()
plt.scatter(x[:, 0], x[:, 1], marker='o')
plt.show()
# 3 使用k-means进行聚类, 并使用CH方法评估
# 3-1 n_clusters=2 两个初始点
# init='k-means++', 智能初始化,避免局部最优,让初始中心尽量分散开,而不是随机乱选,分散得越开越好。这样分类效率最高,收敛最快,不容易出错。让n_clusters指定的那个两个初始点不要聚在一起
# n_init = 'auto', 自动选择尝试次数,平衡效果效率
# random_state = 22 可重复性,固定种子,保证每次运行结果一模一样
y_pred = KMeans(n_clusters=2, random_state=22, init='k-means++', n_init='auto').fit_predict(x)
plt.scatter(x[:, 0], x[:, 1], c=y_pred)
plt.show()
print('1-->', calinski_harabasz_score(x, y_pred))
# 3-2 n_clusters=3
y_pred = KMeans(n_clusters=3, random_state=22, n_init='auto').fit_predict(x)
plt.scatter(x[:, 0], x[:, 1], c=y_pred)
plt.show()
print('2-->', calinski_harabasz_score(x, y_pred))
# 3-3 n_clusters=4
# init='k-means++':聪明的初始化策略
estimator = KMeans(n_clusters=4, random_state=22, n_init='auto')
y_pred = estimator.fit_predict(x)
plt.scatter(x[:, 0], x[:, 1], c=y_pred)
plt.show()
# 4 模型评估
print('3-->', calinski_harabasz_score(x, y_pred))
if __name__ == '__main__':
dm01_kmeans()
更多推荐

所有评论(0)