K-Means算法是无监督的聚类算法,它实现起来比较简单,聚类效果也不错,因此应用很广泛。

 K-Means算法的思想很简单,对于给定的样本集,按照样本之间的距离大小,将样本集划分为K个簇。让簇内的点尽量紧密的连在一起,而让簇间的距离尽量的大。

 样本:

 

pytorch 无监督学习模型_k-means

要求

通过客户消费频率与金额为客户群体分3类

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

第一步:

#读取样本,取需要的属性
data = pd.read_csv('company.csv', sep=',', encoding='gbk')
datas = data[['平均消费周期(天)', '平均每次消费金额']]

我们可以看一下原始分布

#绘制出分布
plt.figure()
plt.scatter(data['平均消费周期(天)'], data['平均每次消费金额'])
plt.title('original')
plt.show()

pytorch 无监督学习模型_k-means_02


x轴为消费频率,y为平均消费

第二步,实现分类函数:

#分类
def d(datas, a):  #datas是样本,a是自己随机选取的3个质心
    type = []
    dian = {}
    for i in range(datas.shape[0]):
        li = np.array([datas.loc[i, :][0], datas.loc[i, :][1]])   #遍历样本的每一行
        d = np.sum((a.iloc[:, :-1] - li) ** 2, axis=1) ** (1 / 2)   #每一行的样本与自己选取的质心,计算欧氏距离
        type.append(d.sort_values(axis=0).index[0])         #根据欧式距离升序排列,选取最小值,添加到type列表中
    datas['type'] = type    #为样本表添加上分好的类

    one = datas[datas['type'] == 'one']     #根据不同的类的位置总和平均值求出一个新的质心
    dian['one'] = [one[['平均消费周期(天)', '平均每次消费金额']].mean(axis=0)['平均消费周期(天)'],
                    one[['平均消费周期(天)', '平均每次消费金额']].mean(axis=0)['平均每次消费金额']
                    ]

    two = datas[datas['type'] == 'two']
    dian['two'] = [two[['平均消费周期(天)', '平均每次消费金额']].mean(axis=0)['平均消费周期(天)'],
                   two[['平均消费周期(天)', '平均每次消费金额']].mean(axis=0)['平均每次消费金额'],
                   ]

    three = datas[datas['type'] == 'three']
    dian['three'] = [three[['平均消费周期(天)', '平均每次消费金额']].mean(axis=0)['平均消费周期(天)'],
                   three[['平均消费周期(天)', '平均每次消费金额']].mean(axis=0)['平均每次消费金额'],
                   ]
    cen = pd.DataFrame(dian).T
    cen['type'] = ['one', 'two', 'three']
    return cen    #返回3类的质心

第三步:实现通过不同分类绘制散点图

##根据每一类绘制散点图
def denlei(datas, a):
    plt.figure()
    plt.rcParams['font.sans-serif'] = 'SimHei'
    plt.rcParams['axes.unicode_minus'] = False
    type = []
    for i in range(datas.shape[0]):
        li = np.array([datas.loc[i, :][0], datas.loc[i, :][1]])
        d = np.sum((a.iloc[:, :-1] - li) ** 2, axis=1) ** (1 / 2)
        type.append(d.sort_values(axis=0).index[0])
    datas['type'] = type
    plt.scatter(a.iloc[:, 0][0], a.iloc[:, 1][0], marker="*", color='r', edgecolors='k')
    plt.scatter(a.iloc[:, 0][1], a.iloc[:, 1][1], marker="^", color='b', edgecolors='k')
    plt.scatter(a.iloc[:, 0][2], a.iloc[:, 1][2], marker="s", color='c', edgecolors='k')
    plt.legend(['第一类', '第二类', '第三类'])

    one = datas[datas['type'] == 'one']
    x = one[['平均消费周期(天)', '平均每次消费金额']]['平均消费周期(天)']
    y = one[['平均消费周期(天)', '平均每次消费金额']]['平均每次消费金额']
    plt.scatter(x, y, marker='*', color='r')

    two = datas[datas['type'] == 'two']
    x = two[['平均消费周期(天)', '平均每次消费金额']]['平均消费周期(天)']
    y = two[['平均消费周期(天)', '平均每次消费金额']]['平均每次消费金额']
    plt.scatter(x, y, marker='^', color='b')

    three = datas[datas['type'] == 'three']
    x = three[['平均消费周期(天)', '平均每次消费金额']]['平均消费周期(天)']
    y = three[['平均消费周期(天)', '平均每次消费金额']]['平均每次消费金额']
    plt.scatter(x, y, marker='+', color='c')
    
    
    plt.xlabel('消费频率(天数)')
    plt.ylabel('消费金额(元)')
    plt.show()

第四步,执行函数:

#大致选出3类的质心,注意,选中的3类第一次分类后,3类必须都有值,否则重新选点
a = pd.DataFrame({'one': [2.0, 100.0],
                  'two': [40.0, 600.0],
                  'three': [80.0, 200.0]}).T
a['type'] = ['one', 'two', 'three']
#第一类,第二类,第三类

a = a
n = 0
while True:
    n += 1
    back = d(datas, a)
    if np.all(back == a):
        #结束条件,当最后一次循环和上一次循环返回的3个质心相同就跳出循环
        print(n)
        print('----', back)
        denlei(datas, back) #执行绘图函数
        break
    else:
        denlei(datas, a)   #否则传入上一次返回的3个质心继续执行分类
        a = back

结果:

函数总共执行了3次

第一次,根据我自己给的3个质心分类后的散点图

pytorch 无监督学习模型_pytorch 无监督学习模型_03

第二次:分类函数根据第一次分类选取3个质心重新分类

pytorch 无监督学习模型_k-means_04

第三次,最后的结果

3个质心

pytorch 无监督学习模型_pytorch 无监督学习模型_05


pytorch 无监督学习模型_用户分类_06

最后就完成对客户群体的分类