找回密码
 立即注册
查看: 343|回复: 0

十大机器学习算法(三)—— 无监督 聚类算法 KMeans

[复制链接]
发表于 2022-4-14 22:38 | 显示全部楼层 |阅读模式
KMeans

KMeans属于无监督(即无标签)聚类算法,在不知道数据没有具体的划分标准时,通过物以类聚的方法,将相似数据放在一起。
一、源码流程

(一)首先随机生成一堆数据                               [                      x                      ,                      y                      ]                          [x,y]               [x,y],尝试将这些数据进行聚类
  1. import random
  2. import matplotlib.pyplot as plt
  3. points_num =100
  4. random_x =[random.randint(-100,100)for _ inrange(points_num)]
  5. random_y =[random.randint(-100,100)for _ inrange(points_num)]
  6. random_poinsts =[(x, y)for x, y inzip(random_x, random_y)]
  7. plt.scatter(random_x, random_y)
复制代码


(二) 随机生成五个点作为分类的初始点

(初始点的选择不影响最后的分类结果,只影响迭代次数)
  1. #随机初始点defgenerate_random_point(min_, max_):return random.randint(min_, max_), random.randint(min_, max_)#随机生成五个点
  2. generate_random_point(-100,100)
  3. K =5#初始中心点
  4. pervious_kernels =[generate_random_point(-100,100)for _ inrange(K)]print(pervious_kernels)#将五个点在图中画出
  5. plt.scatter([pervious_kernels[0][0]],[pervious_kernels[0][1]], color='red', s=100)
  6. plt.scatter([pervious_kernels[1][0]],[pervious_kernels[1][1]], color='green', s=100)
  7. plt.scatter([pervious_kernels[2][0]],[pervious_kernels[2][1]], color='yellow', s=100)
  8. plt.scatter([pervious_kernels[3][0]],[pervious_kernels[3][1]], color='blue', s=100)
  9. plt.scatter([pervious_kernels[4][0]],[pervious_kernels[4][1]], color='purple', s=100)#画出随机的点[x,y]
  10. plt.scatter(random_x, random_y)
复制代码


(三)根据距离函数对所有点进行分类

距离函数:欧氏距离
  1. import numpy as np
  2. #欧氏距离defdis(x, y):return np.sqrt((x[0]- y[0])**2+(x[1]- y[1])**2)       
  3. kernel_colors =['red','green','yellow','blue','purple']#存放迭代更新后的中心点
  4. new_kernels =[]#存放与相应的中心点为一类的点
  5. groups =[[]for _ inrange(K)]#对所有点与现在的中心点求距离,并将其与最小距离的点归为同一类for p in random_poinsts:
  6.     distances =[dis(p, k)for k in previous_kernels]
  7.     min_index = np.argmin(distances)
  8.     groups[min_index].append(p)#画出当前的中心的点与其集合中的点    for i, p inenumerate(previous_kernels):
  9.     plt.scatter([p[0]],[p[1]], color=kernel_colors[i], s=100)#plt.scatter([previous_kernels[1][0]], [previous_kernels[1][1]], color=kernel_colors[1], s=100)#plt.scatter([previous_kernels[2][0]], [previous_kernels[2][1]], color=kernel_colors[2], s=100)
复制代码


(四)更新中心点
  1. #当前点不一定是最终的中心点,对其进行更新#根据所有点的均值求出其更新后的中心点for i, g inenumerate(groups):
  2.     g_x =[_x for _x, _y in g]
  3.     g_y =[_y for _x, _y in g]
  4.    
  5.     n_k_x, n_k_y = np.mean(g_x), np.mean(g_y)
  6.     new_kernels.append((n_k_x, n_k_y))print(kernel_colors[i])
  7.     plt.scatter(g_x, g_y, color=kernel_colors[i])
  8.     plt.scatter([n_k_x],[n_k_y], color=kernel_colors[i], alpha=0.5, s=200)print('根据新的Group获得的kernal和之前的kernel的距离是: {}'.format(dis((n_k_x, n_k_y), previous_kernels[i])))#plt.scatter(random_x, random_y, s=10)#更新中心点
  9. previous_kernels = new_kernels
复制代码



(五)持续迭代即可得到最终的中心点



二、KMeans的应用

(一)最优 K 值的选取:手肘法

手肘法
(二)使用KMeans对商场客户进行聚类

matplotlib.pyplot 绘制双 y 轴图像
seaborn 绘制数据分布图
数据内容如下:


  1. #商场顾客分类import pandas as pd
  2. import numpy as np
  3. import matplotlib
  4. import matplotlib.pyplot as plt
  5. import seaborn as sns
  6. from sklearn.cluster import KMeans
  7. from sklearn import preprocessing
  8. from sklearn.preprocessing import Normalizer
  9. #加载数据
  10. data = pd.read_csv("Mall_Customers.csv")# data = pd.DataFrame(data)# print(data.describe(), data.info())#取出需要分类的数据
  11. train_x = data.iloc[:,1:5]#标签编码, LabelEncoderfrom sklearn.preprocessing import LabelEncoder
  12. le = LabelEncoder()
  13. train_x['Gender']= le.fit_transform(train_x['Gender'])# col = train_x.columns.to_list()#如何取列名:https://www.cnblogs.com/wqbin/p/11845042.html# 规范化到 [0,1] 空间
  14. min_max_scaler = preprocessing.MinMaxScaler()
  15. train_x1 = min_max_scaler.fit_transform(train_x)
  16. pd.DataFrame(train_x1, columns =train_x.columns).to_csv('temp.csv', index=False)# print(train_x2))#正态分布的规范化# normalizer = Normalizer()# train_x1 = normalizer.fit_transform(train_x)# print(train_x1)#使用KMeans聚类
  17. kmeans = KMeans(n_clusters =3)
  18. kmeans.fit(train_x)
  19. pre_y = kmeans.predict(train_x)#将数据与源数据拼接
  20. results = pd.concat((train_x, pd.DataFrame(pre_y, columns =['Group'])), axis =1)
  21. results.to_csv('Customers_Group.csv', index =False)
  22. results.head(20)
复制代码

结果分析:
  1. #得到数据可视化内容
  2. group = pd.DataFrame()
  3. group_list =[group, group, group]for i inrange(3):
  4.     group = pd.DataFrame(results.iloc[results[results["Group"]== i].index])
  5.     group.columns =['gender','age','income','spending','group']
  6.     group_list[i]= group.describe()#得到描述统计的列表    print(group_list)
  7. group_attr ={}for i inrange(3):
  8.     group_attr[i]=[]
  9.     group_attr[i]+=[group_list[i].spending['mean'], group_list[i].income['mean'], group_list[i].age['count']]
  10. group_attr = pd.DataFrame(group_attr.values(), index = group_attr.keys(), columns =['spending','income','count'])
  11. group_attr
复制代码
对各群体的特性进行分析:



spending、income 在各群体中的均值,各群体中顾客的数量 count 如表所示。
对其进行可视化分析:
  1. #Group特征分析#新建画布可视化分析
  2. fig = plt.figure(figsize =[18,18])
  3. plt.rcParams['font.sans-serif']=['SimHei']#用来正常显示中文标签
  4. plt.rcParams['axes.unicode_minus']=False# 解决保存图像是负号'-'显示为方块的问题
  5. plt.suptitle('商场顾客分类:KMeans聚类', fontsize=30)#绘制第一张图:各群体的spending, income, count特征#添加标题
  6. ax1 = plt.subplot(311)
  7. ax2 = ax1.twinx()
  8. plt.title('各群体的spending, income, count特征',  size=20)#设置参数
  9. bar_width =0.2
  10. bar_1 = group_attr.index.tolist()
  11. bar_2 =[i+bar_width for i in bar_1]
  12. bar_3 =[i+bar_width for i in bar_2]#导入数据,绘制条形图
  13. ax1.bar(bar_1, group_attr['spending'], width=bar_width, label='spending', alpha =0.3)
  14. ax1.bar(bar_2, group_attr['income'], width=bar_width, label='income', alpha =0.3)
  15. ax2.bar(bar_3, group_attr['count'], width=bar_width, label='count',color ='green', alpha =0.3)#添加xy轴# ax1.set_xlabel('Group',size = 20)
  16. ax1.set_ylabel('元', size =20)
  17. ax2.set_ylabel('数量', size =20)#x轴刻度
  18. ax1.set_xticks(bar_2)
  19. ax1.set_xticklabels(['group1','group2','group3'], size =15)# 图例
  20. handles1, labels1 = ax1.get_legend_handles_labels()
  21. handles2, labels2 = ax2.get_legend_handles_labels()
  22. plt.legend(handles1+handles2, labels1+labels2, loc='upper right')#网格
  23. ax1.grid(alpha =0.1)#绘制第二张图:各群体的年龄分布# # plt.subplot(3,3,4)# sns.set(font='SimHei',font_scale=1.5)  # 解决Seaborn中文显示问题并调整字体大小# fig1, axes = plt.subplots(1,3, figsize=(18, 7))# sns.set(color_codes=True, font_scale = 1.25)# # sns.distplot(results.Age[[result.Group == 0].index], ax=axes[0])# sns.distplot(results[results.Group == 0]['Age'].tolist(), rug_kws={"color": "g"}, kde_kws={ 'alpha' : 0.5, "lw":4, "label": "kde", 'color': 'g'}, hist_kws={"label" : 'hist'}, axlabel = 'group1:年龄分布', ax = axes[0])# # plt.subplot(3,3,5)# sns.distplot(results[results.Group == 1]['Age'].tolist(), rug_kws={"color": "g"}, kde_kws={ 'alpha' : 0.5, "lw":4, "label": "kde", 'color': 'g'}, hist_kws={"label" : 'hist'}, axlabel = 'group2:年龄分布', ax = axes[1])# # plt.subplot(3,3,6)# sns.distplot(results[results.Group == 2]['Age'].tolist(), rug_kws={"color": "g"}, kde_kws={ 'alpha' : 0.5, "lw":4, "label": "kde", 'color': 'g'}, hist_kws={"label" : 'hist'}, axlabel = 'group3:年龄分布', ax = axes[2])for i inrange(3):
  24.     plt.subplot(3,3, i +4)
  25.     plt.title('group'+str(i +1)+':年龄分布特性', size =20)
  26.     sns.distplot(results[results.Group == i]['Age'].tolist(), rug_kws={"color":"g"}, kde_kws={'alpha':0.5,"lw":4,"label":"kde",'color':'g'}, hist_kws={"label":'hist'}, axlabel ='')
复制代码

由于数据量小,分类仅分为三类。粗略分析可以发现:
group1:群体数量相对较少,相对年龄最小,消费能力最强,收入相对较高,但均用于消费;
group2:相对年龄跨度最大,属于普遍状态,但收入较低,消费能力强于收入能力,超前消费较多;
group3:稳健型消费者,收入高且收入大于消费,年龄在20 ~ 50岁之间,数量与 group1 数量基本相当,有剩余资金可以进行消费。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2025-5-30 13:48 , Processed in 1.263846 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表