K-means聚类算法也称k均值聚类算法,是集简单和经典于一身的基于距离的聚类算法。它采用距离作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大。该算法认为类簇是由距离靠近的对象组成的,因此把得到紧凑且独立的簇作为最终目标。
K-Means算法主要解决的问题如下图所示。我们可以看到,在图的左边有一些点,我们可以看出来有三个点群,但是我们怎么才能将三个点群分为图右边的三个集群,这就是k-means算法能够解决的问题。
K-means
聚类算法是一种迭代求解的聚类分析算法,其步骤是随机选取K个对象作为初始的聚类中心,然后计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心。聚类中心以及分配给它们的对象就代表一个聚类。每分配一个样本,聚类的聚类中心会根据聚类中现有的对象被重新计算。这个过程将不断重复直到满足某个终止条件。终止条件可以是没有(或最小数目)对象被重新分配给不同的聚类,没有(或最小数目)聚类中心再发生变化,误差平方和局部最小。
首先随机选择三个聚类中心;然后重复调整聚类中心位置;最终收敛,形成三个簇。
优点:
缺点:
make_blobs
函数是为聚类产生数据集,产生一个数据集和相应的标签sklearn.datasets.make_blobs(n_samples=100,n_features=2,centers=3, cluster_std=1.0,center_box=(-10.0,10.0),shuffle=True,random_state=None)
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
#参数:
# n_samples=100 样本数量
# n_features=2 特征数量
# centers=3 中心点
#返回值:
# X_train: 测试集
# y_train: 特征值
X_train,y_train = make_blobs(n_samples=100, n_features=2, centers=3)
plt.scatter(X_train[:,0],X_train[:,1],c=y_train)
plt.show()
#参数
# n_clusters 将预测结果分为几簇
kmeans = KMeans(n_clusters=3) # 获取模型
kmeans.fit(X_train) #这里不需要给他答案 只把要分类的数据给他 即可
predict_y = kmeans.predict(X_train)
plt.scatter(X_train[:,0],X_train[:,1],c=predict_y) #预测结果
plt.show()
from sklearn.cluster import KMeans
import pandas as pd
df = pd.read_excel('data.xlsx',sheet_name="人均消费(元)")
data = df.iloc[:,1:]
print(data)
数据显示:
食品 衣着 家庭设备 医疗 交通 娱乐 居住 杂项
0 2959.19 730.79 749.41 513.34 467.87 1141.82 478.42 457.64
1 2459.77 495.47 697.33 302.87 284.19 735.97 570.84 305.08
2 1495.63 515.90 362.37 285.32 272.95 540.58 364.91 188.63
3 1406.33 477.77 290.15 208.57 201.50 414.72 281.84 212.10
4 1303.97 524.29 254.83 192.17 249.81 463.09 287.87 192.96
5 1730.84 553.90 246.91 279.81 239.18 445.20 330.24 163.86
6 1561.86 492.42 200.49 218.36 220.69 459.62 360.48 147.76
7 1410.11 510.71 211.88 277.11 224.65 376.82 317.61 152.85
8 3712.31 550.74 893.37 346.93 527.00 1034.98 720.33 462.03
9 2207.58 449.37 572.40 211.92 302.09 585.23 429.77 252.54
10 2629.16 557.32 689.73 435.69 514.66 795.87 575.76 323.36
11 1844.78 430.29 271.28 126.33 250.56 513.18 314.00 151.39
12 2709.46 428.11 334.12 160.77 405.14 461.67 535.13 232.29
13 1563.78 303.65 233.81 107.90 209.70 393.99 509.39 160.12
14 1675.75 613.32 550.71 219.79 272.59 599.43 371.62 211.84
15 1427.65 431.79 288.55 208.14 217.00 337.76 421.31 165.32
16 1942.23 512.27 401.39 206.06 321.29 697.22 492.60 226.45
17 1783.43 511.88 282.84 201.01 237.60 617.74 523.52 182.52
18 3055.17 353.23 564.56 356.27 811.88 873.06 1082.82 420.81
19 2033.87 300.82 338.65 157.78 329.06 621.74 587.02 218.27
20 2057.86 186.44 202.72 171.79 329.65 477.17 312.93 279.19
21 2303.29 589.99 516.21 236.55 403.92 730.05 438.41 225.80
22 1974.28 507.76 344.79 203.21 240.24 575.10 430.36 223.46
23 1673.82 437.75 461.61 153.32 254.66 445.59 346.11 191.48
24 2194.25 537.01 369.07 249.54 290.84 561.91 407.70 330.95
25 2646.61 839.70 204.44 209.11 379.30 371.04 269.59 389.33
26 1472.95 390.89 447.95 259.51 230.61 490.90 469.10 191.34
27 1525.57 472.98 328.90 219.86 206.65 449.69 249.66 228.19
28 1654.69 437.77 258.78 303.00 244.93 479.53 288.56 236.51
29 1375.46 480.89 273.84 317.32 251.08 424.75 228.73 195.93
30 1608.82 536.05 432.46 235.82 250.28 541.30 344.85 214.40
k=3
model = KMeans(n_clusters= k,init='k-means++')
clf = model.fit(data)
predict_y = clf.predict(data)
print(df[predict_y==0]['省份'])
print(df[predict_y==1]['省份'])
print(df[predict_y==2]['省份'])
结果显示:
2 河北
3 山西
4 内蒙古
5 辽宁
6 吉林
7 黑龙江
11 安徽
13 江西
14 山东
15 河南
17 湖北
23 贵州
26 陕西
27 甘肃
28 青海
29 宁夏
30 新疆
Name: 省份, dtype: object
1 天津
9 江苏
10 浙江
12 福建
16 湖南
19 广西
20 海南
21 重庆
22 四川
24 云南
25 西藏
Name: 省份, dtype: object
0 北京
8 上海
18 广东
Name: 省份, dtype: object
各城市消费水平聚类
import random
import pandas as pd
import numpy as np
#%%
# 计算欧拉距离
def calcDis(dataSet, centroids, k):
clalist = []
for data in dataSet:
diff = np.tile(data, (k, 1)) - centroids
squaredDiff = diff ** 2 # 平方
squaredDist = np.sum(squaredDiff, axis=1) # 和 (axis=1表示行)
distance = squaredDist ** 0.5 # 开根号
clalist.append(distance)
clalist = np.array(clalist) # 返回一个每个点到质点的距离len(dateSet)*k的数组
return clalist
# 计算质心
def classify(dataSet, centroids, k):
# 计算样本到质心的距离
clalist = calcDis(dataSet, centroids, k)
# 分组并计算新的质心
minDistIndices = np.argmin(clalist, axis=1) # axis=1 表示求出每行的最小值的下标
newCentroids = pd.DataFrame(dataSet).groupby(
minDistIndices).mean() # DataFramte(dataSet)对DataSet分组,groupby(min)按照min进行统计分类,mean()对分类结果求均值
newCentroids = newCentroids.values
# 计算变化量
changed = newCentroids - centroids
return changed, newCentroids
# 使用k-means分类
def kmeans(dataSet, k):
# 随机取质心
# random.sample(list类型数据)
centroids = random.sample(list(dataSet), k)
# 更新质心 直到变化量全为0
changed, newCentroids = classify(dataSet, centroids, k)
while np.any(changed != 0):
changed, newCentroids = classify(dataSet, newCentroids, k)
centroids = sorted(newCentroids.tolist()) # tolist()将矩阵转换成列表 sorted()排序
# 根据质心计算每个集群
cluster = []
clalist = calcDis(dataSet, centroids, k) # 调用欧拉距离
minDistIndices = np.argmin(clalist, axis=1)
for i in range(k):
cluster.append([])
for i, j in enumerate(minDistIndices): # enymerate()可同时遍历索引和遍历元素
cluster[j].append(dataSet[i])
return centroids, cluster, minDistIndices
# 创建数据集
def createDataSet():
df = pd.read_excel(r"data.xlsx", sheet_name="人均消费(元)")
data = df.iloc[:, 1:]
return df,np.array(data)
if __name__ == '__main__':
df,dataSet = createDataSet()
centroids, cluster, minDist = kmeans(dataSet, 3)
print('质心为:%s' % centroids)
print('集群为:%s' % cluster)
print(df[minDist == 0]['省份'])
print(df[minDist == 1]['省份'])
print(df[minDist == 2]['省份'])
聚类结果:
2 河北
3 山西
4 内蒙古
5 辽宁
6 吉林
7 黑龙江
11 安徽
13 江西
14 山东
15 河南
17 湖北
23 贵州
26 陕西
27 甘肃
28 青海
29 宁夏
30 新疆
Name: 省份, dtype: object
1 天津
9 江苏
12 福建
16 湖南
19 广西
20 海南
21 重庆
22 四川
24 云南
25 西藏
Name: 省份, dtype: object
0 北京
8 上海
10 浙江
18 广东
Name: 省份, dtype: object
以下程序来源链接: K均值算法
cluster_std
不相同from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
# cluster_std 各个中心的标准差
X_train,y_train = make_blobs(n_samples=500, n_features=2, centers=3, cluster_std=[1.0,2.0,3.0])
#参数
# n_clusters 将预测结果分为几簇
kmeans = KMeans(n_clusters=3) # 获取模型
kmeans.fit(X_train)
predict_y = kmeans.predict(X_train)
plt.scatter(X_train[:,0],X_train[:,1],c=y_train) # 原结果
plt.show()
plt.scatter(X_train[:,0],X_train[:,1],c=predict_y) #预测结果
plt.show()
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
import numpy as np
# cluster_std 各个中心的标准差
X_train,y_train = make_blobs(n_samples=1500, n_features=2, centers=3)
# 创建训练集
X1 = X_train[y_train==0] # X1中的这些点 目标值都是0
X2 = X_train[y_train==1][:100] # X2中的这些点 目标值都是1
X3 = X_train[y_train==2][:10] # X3中的这些点 目标值都是2
# 将三个合为一个训练集
X_train = np.concatenate((X1,X2,X3))
# 创建结果集
# 前500个为0 再来100个1 再来10个2
y_train = [0]*500+[1]*100+[2]*10
plt.scatter(X_train[:,0],X_train[:,1],c=y_train) # 原结果
plt.show()
#参数
# n_clusters 将预测结果分为几簇
kmeans = KMeans(n_clusters=3) # 获取模型
kmeans.fit(X_train)
predict_y = kmeans.predict(X_train)
plt.scatter(X_train[:,0],X_train[:,1],c=predict_y) #预测结果
plt.show()
从 K m e a n s Kmeans Kmeans聚类算法的原理可知,在正式聚类之前首先需要完成的就是初始化 k k k个簇中心。使得收敛情况严重依赖于簇中心的初始化状况。如果在初始化过程中很不巧的将 k k k个(或大多数)簇中心都初始化了到同一个簇中,那么在这种情况下聚类算法很大程度上都不会收敛到全局最小值。也就是说,当簇中心初始化的位置不得当时,聚类结果将会出现严重的错误。
k-means++算法选择初始聚类中心的基本原则是:初始的聚类中心之间的相互距离要尽可能的远
。
算法描述如下:
(只对K-means算法“初始化K个聚类中心” 这一步进行了优化)
def get_cent(points, k):
'''
kmeans++的初始化聚类中心的方法
:param points: 样本
:param k: 聚类中心的个数
:return: 初始化后的聚类中心
'''
m, n = np.shape(points)
cluster_centers = np.mat(np.zeros((k, n)))
# 1、随机选择一个样本点作为第一个聚类中心
index = np.random.randint(0, m)
cluster_centers[0, ] = np.copy(points[index, ]) # 复制函数,修改cluster_centers,不会影响points
# 2、初始化一个距离序列
d = [0.0 for i in range(m)]
for i in range(1, k):
sum_all = 0
for j in range(m):
# 3、对每一个样本找到最近的聚类中心点
d[j] = nearest(points[j, ], cluster_centers[0:i, ])
# 4、将所有的最短距离相加
sum_all += d[j]
# 5、取得sum_all之间的随机值
sum_all *= random()
# 6、获得距离最远的样本点作为聚类中心点
for j, di in enumerate(d): # enumerate()函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同事列出数据和数据下标一般用在for循环中
sum_all -= di
if sum_all > 0:
continue
cluster_centers[i] = np.copy(points[j, ])
break
return cluster_centers
参考来源:数学建模清风老师课件
层次聚类的算法流程:
# 调包
import matplotlib.pyplot as plt
import pandas as pd
import scipy.cluster.hierarchy as shc # 层次聚类
# 防止中文乱码
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
# 加载数据
df = pd.read_excel('data.xlsx',sheet_name="人均消费(元)")
print(df.head())
# 绘图
plt.figure(figsize=(16,10),dpi=100)
plt.title('省份消费数据聚类树状图',fontsize=22)
dend = shc.dendrogram(shc.linkage(df[['食品','衣着','家庭设备','医疗','交通','娱乐','居住','杂项']],
method='ward'),labels=df['省份'].values,color_threshold=100)
plt.xticks(fontsize=12)
plt.savefig('树状图.png') # 保存图片
plt.show()
本文为学习过程记录,根据学习情况继续更新。