Customer_ID:用户编号
Gender:性别
Age:年龄
L_O_S:在网时长
Tariff:话费类型/话费方案
Handset:手机品牌
Peak_calls:高峰时期电话数
Peak_mins:高峰时期电话时长
OffPeak_calls:低谷时期电话数
OffPeak_mins:低谷时期电话时长
Weekend_calls:周末电话数
Weekend_mins:周末电话时长
International_mins:国际电话时长
Nat_call_cost:国内电话费用
month:月份
运营商能够将客户很好地进行分层是为客户推出差异化的服务的基础,好的用户分析也是提升用户体验的前提。本文通过分析电信客户的相关数据(客户信息与客户通话数据),以期(1)了解客户特征,(2)并通过Kmeans聚类分析对客户进行聚类。
import pandas as pd
# 导入数据
# 用户电话情况
custcall = pd.read_csv('C:\\Users\\lin\\Desktop\\custcall.csv',sep = ',')
# 用户信息
custinfo = pd.read_csv('C:\\Users\\lin\\Desktop\\custinfo.csv',sep = ',')
print(custcall.shape)
custcall.head()
print(custinfo.shape)
custinfo.head()
# 求每个用户各指标的平均值
custcall_avg = custcall.groupby(by = ['Customer_ID']).mean()
# month 的均值为同一值,故剔除 ‘month’
del custcall_avg['month']
# 合并数据集
cust = pd.merge(custinfo,custcall_avg,left_on = 'Customer_ID',right_index = True,how = 'inner')
# 查看Customer_ID是否有重复值
print(cust['Customer_ID'].duplicated().sum())
# 将Customer_ID设为索引
cust = cust.set_index(keys = ['Customer_ID'])
cust.head()
# 查看cust的形状并将其导出
print(cust.shape)
print(cust.columns.to_list())
cust.to_excel('C:\\Users\\林\\Desktop\\cust.xlsx')
将cust导入到Tableau中,分别绘制手机品牌、性别以及套餐的分布情况
从上图可知:
# 查看连续变量的分布
import matplotlib.pyplot as plt
import seaborn as sns
for i in cust.columns:
if i not in ['Gender','Tariff','Handset','Peak_mins_bin','Peak_calls_bin']:
plt.figure()
sns.distplot(cust[i],bins=10,hist_kws=dict(edgecolor='k'),kde=True)
plt.show()
这一部分分别绘制了:
(1)使用各套餐用户的平均年龄、平均高峰电话数通话时间长、平均低谷电话数及通话时长、平均国际通话时长以及平均国内话费数;
(2)使用某套餐、某品牌手机的用户数;
(3)使用某套餐的性别分布。
由上图可以得出这样的一些结论:
在2.3节的分析中,猜想国际通话时长、高峰期电话数以及国内电话费用之间可能正相关,为验证这一猜想,这一部分将高峰时期电话次数与国际电话时长分桶,计算这两个维度上的每一个区间的平均国内电话费用,并利用Tableau进行可视化,得到如下图结果(下图上半部分);在这一部分还绘制了手机品牌、套餐与电话费用之间的气泡图。
#数据分桶的代码
# 计算高峰时期电话数与平均国内电话费用,并将数据导出
cust['Peak_calls_bin'] = pd.cut(cust['Peak_calls'],bins = 50)
test = cust.groupby('Peak_calls_bin')['Nat_call_cost'].mean().reset_index()
test.to_excel('C:\\Users\\lin\\Desktop\\Peak_calls_bin.xlsx')
# 计算国际电话时长与平均国内电话费用,并将数据导出
cust['International_mins_bin'] = pd.cut(cust['International_mins'],bins = 50)
test1 = cust.groupby('International_mins_bin')['Nat_call_cost'].mean().reset_index()
test1.to_excel('C:\\Users\\lin\\Desktop\\International_mins_bin.xlsx')
2.4节中关于手机品牌、套餐与国内电话费用之间的分析得到这样的结论:(1)手机品牌为ASAD90 与ASAD170以及S50的用户相较于其他品牌手机的用户为电信带来更多的收入;(2)采用套餐CAT200 和CAT100的用户为电信带来了更多的收入。为了判断这两个结论是否稳健,这一部分对手机品牌与套餐进行了矩阵分析。
# 计算低谷时期电话数与平均国内电话费用,并将数据导出
cust['OffPeak_calls_bin'] = pd.cut(cust['OffPeak_calls'],bins = 50)
test3 = cust.groupby('OffPeak_calls_bin')['Nat_call_cost'].mean().reset_index()
test3.to_excel('C:\\Users\\lin\\Desktop\\OffPeak_calls_bin.xlsx')
# 计算周末电话数与平均国内电话费用,并将数据导出
cust['Weekend_calls_bin'] = pd.cut(cust['Weekend_calls'],bins = 50)
test4 = cust.groupby('Weekend_calls_bin')['Nat_call_cost'].mean().reset_index()
test4.to_excel('C:\\Users\\lin\\Desktop\\Weekend_calls_bin.xlsx')
由上图可知,用户低谷期与周末的通话数、通话时长与电话费用之间没有明确的正相关关系;
下图左半部分按高峰时期与低谷时期两个维度分类:高峰时期与低谷时期都活跃的用户(称为A类)、高峰时期活跃而低谷时期不活跃的用户(称为B类)、低谷时期活跃高峰时期不活跃的用户(称为C类)和两个时期都不活跃的用户(称为D类)。
右半部分选择高峰时期与周末两个维度,与左半部分类似。
计算每一种用户的平均电话费用,并用颜色的深浅表示平均电话费用的大小。
由上图可知:
#将类别变量转为虚拟变量,gender为二值型,get_dummies处理后还是一列
dummies=pd.get_dummies(cust[["Gender",'Tariff','Handset']])
# 合并数据集,将虚拟变量加入到数据集中
train = pd.merge(cust,dummies,left_index = True,right_index = True,indicator = True)
# 删除不需要的变量
for i in ['Gender_x','Tariff','Handset']:
del train[i]
train.head()
# 查看数据集的列
# 查看数据集的列
del train['_merge']
train.columns.to_list()
# 导入所需库
from sklearn.cluster import KMeans
from sklearn.preprocessing import Normalizer
# 数据预处理
norm = Normalizer()
norm.fit(train)
norm_train = norm.transform(train)
# 聚类
norm_cluser = KMeans(n_clusters = 4)
norm_cluser.fit(norm_train)
# 为用户数据集cust加一列用户标签,标签为聚类模型的分类结果
cust['class'] = norm_cluser.predict(norm_train)
# 查看用户分类分布
cust['class'].value_counts()
# 降低纬度
from sklearn import manifold
tsne = manifold.TSNE()
tsne_data = tsne.fit_transform(norm_train)
# 将降维后的数据与用户标签合并为一个数据集
tsne_df = pd.DataFrame(tsne_data,columns=['col1','col2'])
tsne_df.loc[:,"class"] = norm_cluser.predict(norm_train)
# 对降维后的数据集绘图,观察类与类之间是否分明
import seaborn as sns
import matplotlib.pyplot as plt
plt.figure(figsize = (10,8),dpi = 80)
sns.scatterplot(x = 'col1',y = 'col2',hue = 'class',data = tsne_df)
plt.show()
返回结果:
上图显示聚类结果比较好,类与类之间界限比较明晰。
将聚类后的用户数据导入到Tableau中进行可视化:
cust.to_excel('C:\\Users\\lin\\Desktop\\cust_new.xlsx')