Kmeans 是一种动态聚类方法,其基本思想是:首先随机选取 K 个点作为初始凝聚点,按照距离最近原则划分为 K 类;然后重新计算 K 个类的重心作为新的凝聚点,再按照距离最近原则重新分类;重复这一过程,直到重心不再变化为止。
下面是一个简单利用 kmeans 聚类分析的例子,数据为某一年全国31个省市的居民消费支出数据:
食品 | 衣着 | 居住 | 家庭设备 | 交通通讯 | 文教娱乐 | 医疗保健 | 其他 | |
北京 | 4215.56 | 1184.14 | 852.18 | 1295.76 | 1943.48 | 2186.55 | 1039.78 | 526.76 |
天津 | 3542.90 | 698.91 | 524.20 | 996.35 | 998.01 | 1283.70 | 1291.60 | 317.58 |
河北 | 2315.76 | 787.33 | 414.49 | 642.71 | 772.34 | 795.43 | 762.08 | 209.51 |
山西 | 2056.79 | 933.03 | 359.44 | 538.70 | 604.35 | 932.53 | 727.91 | 189.88 |
内蒙古 | 2177.63 | 1047.91 | 394.37 | 533.36 | 755.51 | 968.81 | 722.62 | 328.39 |
辽宁 | 2860.98 | 740.83 | 304.80 | 751.16 | 744.02 | 849.53 | 792.75 | 325.18 |
吉林 | 2356.00 | 826.21 | 279.58 | 675.77 | 733.50 | 800.22 | 845.45 | 277.98 |
黑龙江 | 2071.62 | 877.96 | 282.78 | 613.15 | 596.97 | 802.49 | 695.23 | 237.81 |
上海 | 4940.06 | 940.45 | 800.30 | 796.82 | 1983.72 | 2272.76 | 1412.11 | 627.2 |
江苏 | 3205.79 | 804.23 | 586.84 | 579.32 | 1050.88 | 1287.90 | 794.94 | 311.92 |
浙江 | 4140.34 | 1264.06 | 609.18 | 831.79 | 2097.41 | 1849.73 | 1059.36 | 401.88 |
安徽 | 2781.50 | 763.54 | 290.88 | 400.34 | 676.86 | 666.42 | 590.27 | 197.87 |
福建 | 3595.20 | 708.79 | 455.36 | 478.41 | 1048.71 | 1106.95 | 1071.86 | 329.11 |
江西 | 2495.09 | 647.80 | 426.99 | 326.46 | 567.52 | 805.41 | 646.16 | 193.97 |
山东 | 2512.73 | 925.94 | 503.36 | 579.01 | 902.32 | 1039.99 | 751.69 | 242.29 |
河南 | 2067.51 | 806.39 | 376.27 | 472.31 | 636.57 | 805.08 | 651.98 | 221.91 |
湖北 | 2625.41 | 806.67 | 371.00 | 499.34 | 649.87 | 904.76 | 683.89 | 195.62 |
湖南 | 2689.39 | 790.70 | 450.97 | 601.34 | 801.27 | 1138.67 | 771.47 | 261.18 |
广东 | 4265.19 | 673.90 | 605.12 | 704.90 | 2333.05 | 1669.09 | 1181.42 | 377.2 |
广西 | 2906.73 | 519.96 | 420.66 | 466.04 | 703.39 | 998.87 | 769.77 | 247.38 |
海南 | 2819.96 | 309.45 | 304.05 | 351.06 | 728.29 | 652.03 | 585.40 | 178.55 |
重庆 | 3135.65 | 849.53 | 583.50 | 629.32 | 929.92 | 1391.11 | 882.41 | 221.85 |
四川 | 2709.69 | 640.91 | 422.73 | 442.83 | 827.66 | 909.03 | 705.43 | 232.99 |
贵州 | 2458.30 | 702.90 | 335.68 | 403.43 | 625.44 | 811.73 | 583.46 | 238.35 |
云南 | 2997.06 | 643.94 | 291.17 | 663.01 | 930.59 | 775.61 | 543.10 | 152.42 |
陕西 | 2401.52 | 673.07 | 371.81 | 605.31 | 630.16 | 1081.92 | 653.40 | 239.26 |
甘肃 | 2352.82 | 806.26 | 366.20 | 492.23 | 638.63 | 942.75 | 680.78 | 249.53 |
青海 | 2267.36 | 690.76 | 356.53 | 554.11 | 691.25 | 803.08 | 666.38 | 215.79 |
宁夏 | 2228.63 | 776.51 | 417.38 | 535.92 | 705.69 | 769.97 | 711.21 | 259 |
新疆 | 2257.44 | 825.98 | 309.97 | 499.16 | 757.09 | 741.35 | 571.72 | 244.8 |
对其采用 kmeans 聚类的代码为:
import pandas as pd
from sklearn.cluster import KMeans
import numpy as np
from sklearn.preprocessing import MinMaxScaler
# 将上述数据放到 excel 里,并用 pandas 读取
df = pd.read_excel(r'D:\Users\chen_\git\Statistics-book\datas\sta-data-cluster.xlsx', index_col=0)
scale_values = MinMaxScaler().fit_transform(df.values) # 数据预处理
kmeans = KMeans(n_clusters=3).fit(scale_values) # 分为 3 类
print(kmeans.labels_) # 输出判别结果列表
# 具体输出判别结果
cluster_1 = []
cluster_2 = []
cluster_3 = []
for i, j in enumerate(kmeans.labels_):
if j == 0:
cluster_1.append(df.index[i])
elif j == 1:
cluster_2.append(df.index[i])
else:
cluster_3.append(df.index[i])
print('类别1')
print(cluster_1)
print('类别2')
print(cluster_2)
print('类别3')
print(cluster_3)
# draw pictures by tsne, or pca, 利用主成分降维,并画图显示分类结果
#from sklearn.manifold import TSNE
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
#from mpl_toolkits.mplot3d import Axes3D
tsne = PCA(n_components = 2).fit_transform(scale_values)
df2 = pd.DataFrame(tsne)
df2['labels'] = kmeans.labels_
df_1 = df2[df2['labels'] == 0]
df_2 = df2[df2['labels'] == 1]
df_3 = df2[df2['labels'] == 2]
# 画图
plt.plot(df_1[0], df_1[1], 'bo', df_2[0], df_2[1], 'r*', df_3[0], df_3[1], 'gD',)
plt.show()
输出结果:
[1 2 0 0 0 0 0 0 1 2 1 0 2 0 0 0 0 0 1 0 0 2 0 0 0 0 0 0 0 0]
类别1
['河北', '山西', '内蒙古', '辽宁', '吉林', '黑龙江', '安徽', '江西', '山东', '河南', '湖北', '湖南', '广西', '海南', '四川', '贵州', '云南', '陕西', '甘肃', '青海', '宁夏', '新疆']
类别2
['北京', '上海', '浙江', '广东']
类别3
['天津', '江苏', '福建', '重庆']
对数据使用主成分降维后,显示分类结果如下图:
几点说明:
- kmeans 包默认的使用 k-means++的初始化方法,它的基本思想是:在每次选取质心时,除了第一次完全随机选外,其他次都是从所有样本中选,与最近原质心距离越大的样本,被选取为新质心的概率越大。
- 原始数据并不默认标准化,若对不同量纲的数据,需要自己再标准化
- kmeans 聚类为一种动态聚类方法,必须事先自定义分类个数,这一点与系统聚类不同
- 若样本量过大,例如大于 10000,可以调用 MiniBatchKMeans 方法聚类,它采用抽样计算质心的思想,减少计算量,效果一般只比标准 kmeans 聚类略差
- 官方详细说明文档:https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html
另外一个鸢尾花的例子,可以直接从 sklearn 里面调取数据:
from sklearn.cluster import KMeans
from sklearn import datasets
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
iris = datasets.load_iris() # 调用数据
X = iris.data
y = iris.target # y 为实际分类结果
kmeans = KMeans(n_clusters=3).fit(X) # 聚类
# 画图
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter3D(X[:, 3], X[:, 0], X[:, 2], c = kmeans.labels_) # 取了原始数据三列,画出 3d 散点图
plt.show()
图形分类结果为: