数据分析渣一枚,SQL语言写6了,python还在不断进阶阶段,结合已有的数据源+两年前看的一点python基础+网上参考的无数实例,试写一个K-means的聚类分析,请各位大神们疯狂鞭挞,各位小白们互相学习进步吖>o" />
选取2019年第四季度某产品用户数据,开始具体编写:
导入模块
#导入数据分析大家庭
import pandas as pd
import numpy as np
from sklearn.cluster import KMeans #聚类模块
import matplotlib.pyplot as plt #画图模块
from matplotlib.font_manager import FontProperties #字体模块
font = FontProperties(fname=r"C:\Windows\Fonts\simhei.ttf", size=14) #先在网上下载simhei.ttf,放到Windows文件夹的Fonts文件夹里
导入数据
#打开excel文件,header=None为列添加编号
data1 = pd.read_excel(r"D:\python实战\第四季度用户产品明细-聚类.xlsx",header=None)
#插入列名
data1.columns=['store_id','course_id','course_type','course','start_time','user_id','birthday','age','late_book_time','book_time','book_id','money']
清洗数据
#去重
data1.drop_duplicates()
#查看空值情况
data1.isnull().sum()
print(data1.isnull().sum())
birthday列的空值太多了,剔除。
#删除birthday列的空值
print('删除空值前:',data1.shape)
data1.dropna(subset=['birthday'],inplace=True)#True=不创建新的对象,直接对原始对象进行修改,默认是False,即创建新的对象进行修改,原对象不变。
print('删除空值后:',data1.shape)
#查看money列异常值
data1.describe()['money']
print(data1.describe()['money'])
money列存在极值和0,将money根据业务选定一个合理的范围。
data1=data1.loc[(data1['money'] > 10)]
data1=data1.loc[(data1['money'] <1000)]
规范数据类型
#查看数据类型
data1.info()
#late_book_time字段改为日期型,必须新增一列'late_time',无法在原始列上改类型
data1.loc[:,'late_time'] = pd.to_datetime(data1.loc[:,'late_book_time'],format='%Y-%m-%d',errors='coerce')
将出生日期改为年龄(源数据age列0值太多,选择出生日期作为年龄统计)
import datetime as dt
now_year = dt.datetime.today().year #算当前年份
data1.loc[:,'agenew'] = now_year - data1.loc[:,'birthday'].dt.year #新增年龄列,当前年份减去生日年份算年龄
聚类分析数据准备
需要用到年龄、消费次数、消费金额,顺便学一下merge函数了
#计算需要聚类的消费次数和消费总金额
buytimes = data1.groupby('user_id')['book_id'].count().reset_index().rename(columns={'book_id':'times'}) #以user_id分组,计数订单编号,建立一列索引后,重命名计数列列名
print(buytimes)
moneysum = data1.groupby('user_id')['money'].sum().reset_index().rename(columns={'money':'moneysum'})
print(moneysum)
agenew = data1.groupby('user_id')['agenew'].max().reset_index()
print(agenew)
#合并上面三个计算表
datauser1 = pd.merge(buytimes, moneysum,on = "user_id")
datauser2 = pd.merge(datauser1,agenew,on = "user_id")
print(datauser2)
开始聚类
选择聚类最佳选择分组数,使用肘部法。(轮廓系数没法看明白,以后补充)
肘部法,可以比较简单的理解为当聚类组数越多,误差平方和就会越小,逐渐趋于平稳,找到平稳前的那个点,就是我们要的组数。
SSE = [] #误差平方和
for i in range(1,11): #k取值1~11,做kmeans聚类,看不同k值对应的簇内误差平方和
km = KMeans(n_clusters=i) #init:初始值选择方式,可选值:'k-means++'(用均值)、'random'(随机)、an ndarray(指定一个数组),默认为'k-means++'。
km.fit(datauser2[['times','moneysum','agenew']])
SSE.append(km.inertia_) # inertia簇内误差平方和 append()在末尾添加一列
plt.plot(range(1, 11), SSE, marker='o') # marker添加折现上数值对应点
plt.xlabel(u'聚类组数', FontProperties=font)
plt.ylabel(u'误差平方和', FontProperties=font)
plt.show()
图中看到,当组数=5,是拐点。
#n_cluster = 5
kmodel = KMeans(n_clusters=5)
kmodel.fit(datauser2[['times','moneysum','agenew']]) #选择聚类的指标,进行聚类
查看聚类结果,先根据聚类提取相关指标
label = pd.Series(kmodel.labels_) #统计各个类别的数目#Series 是一维数组按列竖着排
print(label)
num = pd.Series(kmodel.labels_).value_counts() #统计各个类别内的数目
print(num)
center = pd.DataFrame(kmodel.cluster_centers_) #找出聚类中心,质心的值
print(center)
r = pd.concat([center, num], axis = 1) #横向连接(0是纵向), 得到聚类中心对应的类别下的数目
print(r)
r.columns = list(datauser2[['times','moneysum','agenew']].columns) + [u'类别数目'] #重命名表头
print(r)
结论
用户分层不明显,说明年龄、消费次数和金额这三个维度的用户非常相似。
“0类”的消费群体最为庞大。平均一个季度购买产品12次,等于一个月消费4次,一周一次的频率,相对年轻群体。可以通过刺激用户活跃度增加消费次数,通过发送周优惠券提升消费品率。
“2类”和“3类”消费次数平均一周消费3次-4次,频率高,但用户数量较少,可以成为重点保持用户,防止流失。保证产品质量的同时,通过活动、优惠等手段按频率刺激活跃度。
“1类”用户消费次数频繁且消费份额很高,可以考虑将其纳入vip体系,给予特权,重点维护。