飞机客户数据分析预测与电信客户流失分析预测
第一部分——飞机客户数据分析预测
1、读取数据并探索
#对数据进行基本的探索 #返回缺失值个数以及最大、最小值 import numpy as np datafile ='../data/air_data.csv' #航空原始数据,第一行属性标签 resultfile='../tmp/explore.csv' #数据探索结果表 #读取原始数据,指定编码UTF-8 data = pd.read_csv(datafile, encoding="utf-8") print(data.head())
#包括对数据的基本描述,percentiles参数是指定计算多少的分为数表(如1/4分位数、中位数等) explore = data.describe(percentiles = [], include = 'all').T #describe()函数自动计算非空值数,需要手动计算空值数 explore['null'] = len(data) - explore['count'] explore = explore[['null', 'max', 'min']] explore.columns = [u'空值数', u'最大值', u'最小值'] #表头重命名 print(explore) explore.to_csv(resultfile)
2.探索客户的基本信息分布情况
#客户信息类别 #提取会员入会年份 from datetime import datetime ffp = data['FFP_DATE'].apply(lambda x:datetime.strptime(x, '%Y/%m/%d')) ffp_year = ffp.map(lambda x : x.year) print(ffp_year) #绘制各年份会员入会人数直方图 fig = plt.figure(figsize=(8, 5)) #设置画布大小 plt.rcParams['font.sans-serif'] = ['SimHei'] #用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号 plt.hist(ffp_year, bins='auto', color='#0504aa') plt.xlabel('年份') plt.ylabel('入会人数') plt.title('各年份会员入会人数(3144)') plt.show() plt.close()
#提取会员不同性别人数 male = pd.value_counts(data['GENDER'])['男'] female = pd.value_counts(data['GENDER'])['女'] #绘制会员性别比例饼图 fig = plt.figure(figsize=(7, 4)) #设置画布大小 plt.pie([male, female], labels=['男', '女'], colors=['lightskyblue', 'lightcoral'], autopct='%1.1f%%') plt.title('会员性别比例') plt.show() plt.close()
#提取不同级别会员的人数 lv_four = pd.value_counts(data['FFP_TIER'])[4] lv_five = pd.value_counts(data['FFP_TIER'])[5] lv_six = pd.value_counts(data['FFP_TIER'])[6] #绘制会员各级别人数条形图 fig = plt.figure(figsize=(8,5)) #设置画布大小 plt.bar(range(3), [lv_four, lv_five, lv_six], width=0.4, alpha=0.8, color='skyblue') #left:x轴的位置序列,一般采用arange函数产生一个序列; #height:y轴的数值序列,也就是柱形图的高度,一般就是我们需要展示的数据; #alpha:透明度 #width:为柱形图的宽度,一般这是为0.8即可; #color或facecolor:柱形图填充的颜色; plt.xticks([index for index in range(3)], ['4', '5', '6']) plt.xlabel('会员等级') plt.ylabel('会员人数') plt.title('会员各级别人数(3144)') plt.show() plt.close()
#提取会员年龄 age = data['AGE'].dropna() age = age.astype('int64') #绘制会员年龄分布箱型图 fig = plt.figure(figsize=(5,10)) plt.boxplot(age, patch_artist=True, labels=['会员年龄'], boxprops={'facecolor': 'lightblue'}) #设置填充颜色 plt.title('会员年龄分布箱型图(3144)') #显示y坐标轴的底线 plt.grid(axis='y') plt.show() plt.close()
3.探索客户乘机信息分布情况
lte = data['LAST_TO_END'] fc = data['FLIGHT_COUNT'] sks = data['SEG_KM_SUM'] #绘制最后乘机至结束时长箱型图 fig = plt.figure(figsize=(5,8)) plt.boxplot(lte, patch_artist=True, labels=['时长'], boxprops={'facecolor':'lightblue'}) plt.title('会员最后乘机至结束时长分布箱型图(3144)') plt.grid(axis='y') plt.show() plt.close()
#绘制客户飞行次数箱型图 fig = plt.figure(figsize=(5,8)) plt.boxplot(fc, patch_artist=True, labels=['飞行次数'], boxprops={'facecolor':'lightblue'}) plt.title('会员飞行次数分布箱型图(3144)') plt.grid(axis='y') plt.show() plt.close()
#客户总飞行公里箱型图 fig = plt.figure(figsize=(5,8)) plt.boxplot(sks, patch_artist=True, labels=['总飞行公里数'], boxprops={'facecolor':'lightblue'}) plt.title('会员最后乘机至结束时长分布箱型图(3144)') plt.grid(axis='y') plt.show() plt.close()
4、会员积分兑换情况
#积分信息类别 #提取会员积分换次数 ec = data['EXCHANGE_COUNT'] #提取会员换积分次数直方图 fig = plt.figure(figsize=(8,5)) plt.hist(ec,bins=5,color='#0504aa') plt.xlabel('兑换次数') plt.ylabel('会员人数') plt.title('会员兑换积分次数分布直方图(3130)') plt.show() plt.close()
#提取积分总累计积分 ps = data['Points_Sum'] #绘制会员总累计积分箱型图 fig = plt.figure(figsize=(5, 8)) plt.boxplot(ps, patch_artist=True, labels=['总累积积分'], boxprops={'facecolor': 'lightblue'})#设置填充颜色 plt.title('客户总累计积分箱型图(3144)') plt.grid(axis='y') plt.show() plt.close()
5.相关性分析
#提取属性并合并为新的数据集 data_corr = data.loc[:,['FFP_TIER', 'FLIGHT_COUNT', 'LAST_TO_END', 'SEG_KM_SUM', 'EXCHANGE_COUNT', 'Points_Sum']] age1 = data['AGE'].fillna(0) data_corr['AGE'] = age1.astype('int64') data_corr['ffp_year'] = ffp_year #计算相关性矩阵 dt_corr = data_corr.corr(method='pearson') print('相关性矩阵为(3144):\n', dt_corr)
#绘制热力图 plt.subplots(figsize=(10, 10)) #设置画面大小 ## data:数据 square:是否是正方形 vmax:最大值 vmin:最小值 robust:排除极端值影响 sns.heatmap(dt_corr, annot=True, vmax=1, square=True, cmap='Blues') plt.show() plt.close()
6.数据预处理
#清洗空值与异常值 import numpy as np import pandas as pd datafile = '../data/air_data.csv' cleanedfile = '../tmp/data_cleaned.csv'#保存 #读取数据 airline_data = pd.read_csv(datafile,encoding='utf-8') print('原始数据的形状:\n',airline_data.shape) #去除票价为空的记录 airline_notnull = airline_data.loc[airline_data['SUM_YR_1'].notnull()&airline_data['SUM_YR_2'].notnull(),:] print('删除缺失记录后的数据形状:',airline_notnull.shape) #只保留票价非零的,或者平均折扣率不为0且总飞行公里数大于0的记录 index1 = airline_notnull['SUM_YR_1'] !=0 index2 = airline_notnull['SUM_YR_2'] !=0 index3 = (airline_notnull['SEG_KM_SUM']>0)&(airline_notnull['avg_discount'] !=0) index4 = airline_notnull['AGE']>100 #去除年龄大于100的记录 airline=airline_notnull[(index1|index2)&index3 & ~index4] print('数据清洗后的形状:\n',airline.shape) airline.to_csv(cleanedfile)
#属性选择 #读取数据清洗后的数据 cleanfile='../tmp/data_cleaned.csv' #数据清洗后保存的文件路径 airline=pd.read_csv(cleanfile,encoding='utf-8') #选取需求属性 airline_selection = airline[['FFP_DATE', 'LOAD_TIME', 'LAST_TO_END', 'FLIGHT_COUNT', 'SEG_KM_SUM', 'avg_discount']] print('筛选的属性前5行为:\n', airline_selection.head())
#属性构造与数据标准化 #构造属性L L = pd.to_datetime(data_selection['LOAD_TIME']) - pd.to_datetime(data_selection['FFP_DATE']) L = L.astype('str').str.split().str[0] L = L.astype('int')/30 #合并属性 airline_features = pd.concat([L, data_selection.iloc[:,2:]], axis=1) print('构建的LRFMC属性前5行为3144:\n', data_features.head()) #数据标准化 from sklearn.preprocessing import StandardScaler data = StandardScaler().fit_transform(airline_features) np.savez('../tmp/airline_scale.npz',data) print('标准化后LRFMC 5个属性为:\n', data[:5,:])
7.模型构建
import numpy as np import pandas as pd from sklearn.cluster import KMeans airline_scale = np.load('../tmp/airline_scale.npz')['arr_0'] k = 5 kmeans_model = KMeans(n_clusters=k,n_init=4,random_state=123) fit_kmeans = kmeans_model.fit(airline_scale) kmeans_cc = kmeans_model.cluster_centers_ print('各类聚类中心为:\n',kmeans_cc) kmeans_labels = kmeans_model.labels_ print('各样本的类别标签为:\n',kmeans_labels) r1 = pd.Series(kmeans_model.labels_).value_counts() print('最终每个类别的数目为:\n',r1) cluster_center = pd.DataFrame(kmeans_model.cluster_centers_,\ columns=['ZL','ZR','ZF','ZM','ZC']) cluster_center.index = pd.DataFrame(kmeans_model.labels_).\ drop_duplicates().iloc[:,0] print(cluster_center)
%matplotlib inline labels = ['ZL','ZR','ZF','ZM','ZC'] legen = ['客户群' + str(i + 1) for i in cluster_center.index] lstype = ['-','--',(0,(3,5,1,5,1,5)),':','-.'] kinds = list(cluster_center.iloc[:,0]) cluster_center = pd.concat([cluster_center,cluster_center[['ZL']]],axis=1) centers = np.array(cluster_center.iloc[:,0:]) n = len(labels) angle = np.linspace(0,2 * np.pi,n,endpoint=False) angle = np.concatenate((angle,[angle[0]])) fig = plt.figure(figsize=(8,6)) ax = fig.add_subplot(111,polar=True) for i in range(len(kinds)): ax.plot(angle,centers[i],linestyle=lstype[i],linewidth=2,label=kinds[i]) ax.set_thetagrids(angle[:-1] * 180 / np.pi,labels) plt.title('客户特征分析雷达图3144') plt.legend(legen) plt.show() plt.close()
第二部分 电信客户流失分析预测
1、读取并简单分析数据
import matplotlib.pyplot as plt import numpy as np import pandas as pd import seaborn as sns plt.rc("font",family="SimHei",size="12") #解决中文无法显示的问题 data = pd.read_csv('../data/Customer.csv') # 导入数据 data.shape # 查看数据大小 data.head() data.describe() #描述性统计信息
2、客户流失数据分析
data['Churn'].value_counts() #查找缺失值
数据集中有5174名用户没流失,有1869名客户流失,数据集不均衡。
data.dtypes #查看数据类型 #TotalCharges表示总费用,这里为对象类型,需要转换为float类型 data['TotalCharges']=data['TotalCharges'].apply(pd.to_numeric, errors="ignore") data['TotalCharges'].describe()
#数据归一化处理 #对Churn列中的YES和No分别用1和0替换,方便后续处理 data['Churn'].replace(to_replace='Yes',value=1,inplace=True) data['Churn'].replace(to_replace='No',value=0,inplace=True) data['Churn'].describe()
data.info() #数据预览
在数据预览过后,我们发现不存在缺失值,并且许多特征维度的数据类型均为python默认的object对象类型。
3、绘制电信客户性别饼图和绘制客户流失情况饼图
plt.rcParams['font.sans-serif']='SimHei' plt.rcParams['axes.unicode_minus']='False' #提取会员不同性别人数 male=pd.value_counts(data['gender'])['Female'] female=pd.value_counts(data['gender'])['Male'] #绘制会员性别比例饼图 fig=plt.figure(figsize=(10,6)) plt.pie([male,female],labels=['男','女'],colors=['lightskyblue','lightcoral'],autopct='%1.1f%%') plt.title('电信用户性别比例3144',fontsize=15) plt.show() plt.close() churnvalue=data[ "Churn" ].value_counts() labels=data["Churn"].value_counts().index plt.figure(figsize=(6,6)) plt.pie(churnvalue,labels=labels,colors=["blue","yellow"],explode=(0.1,0),autopct='%1.1f', shadow=True) plt.title('客户流失情况饼图3144',fontsize=15) plt.show()
由图中结果可以看出,流失客户占整体客户的26.5%。
4、客户流失影响直方图
#性别、老年人、配偶、亲属对流客户流失率的影响 import seaborn as sns plt.figure(figsize=(10,10)) plt.subplot(2,2,1) gender=sns.countplot(x='gender',hue='Churn',data=data,palette='Set2') #palette参数表示设置颜色,设置为主颜色paste12 plt.xlabel('性别') plt.title('不同性别客户流失直方图3144',fontsize=15) plt.subplot(2,2,2) seniorcitizen=sns.countplot(x='SeniorCitizen',hue='Churn',data=data,palette='Set2') plt.xlabel('老年人') plt.title('老年人客户流失直方图3144',fontsize=15) plt.subplot(2,2,3) partner=sns.countplot(x='Partner',hue='Churn',data=data,palette='Set2') plt.xlabel('配偶') plt.title('是否有配偶客户流失直方图3144',fontsize=15) plt.subplot(2,2,4) dependents=sns.countplot(x='Dependents',hue='Churn',data=data,palette='Set2') plt.xlabel('亲属') plt.title('亲属客户流失直方图3144',fontsize=15) plt.show()
可以看出,男性与女性用户之间的流失情况基本没有差异,而在老年用户中流失占比明显比非老年用户更高,在所有数据中未婚与已婚人数基本持平,但未婚中流失人数比已婚中的流失人数高出了快一倍,从经济独立情况来看,经济未独立的用户流失率要远远高于经济独立的用户。
5、提取特征值
#提取特征 charges=data.iloc[:,1:20] #对特征进行编码 corrdf=charges.apply(lambda x:pd.factorize(x)[0]) corrdf.head()
#构建相关矩阵 corr = corrdf.corr()
6、热力图
''' heatmap 使用热力图展示系数矩阵情况 linewidths 热力图矩阵之间的间隔大小 annot 设定是否显示每个色块系数值 ''' plt.figure(figsize=(30,20)) ax=sns.heatmap(corr,xticklabels=corr.columns,yticklabels=corr.columns,linewidths=0.2,cmap='YlGnBu',annot=True) plt.title('相关系数热力图3144',fontsize=15) plt.show()
从上图可以看出,互联网服务、网络安全服务、在线备份业务、设备保护业务、技术支持服务、网络电视和网络电影之间存在较强的相关性,多线业务和电话服务之间也有很强的相关性,并且都呈强正相关关系。
7、电信用户是否流失与各变量之间的相关性
tel_dummies=pd.get_dummies(data.iloc[:,1:21]) tel_dummies.head() plt.figure(figsize=(15,8)) tel_dummies.corr()['Churn'].sort_values(ascending=False).plot(kind='bar') plt.title('电信用户是否流失与各变量之间的相关性图3144',fontsize=15) plt.show()
由图上可以看出,变量gender 和 PhoneService 处于图形中间,其值接近于 0 ,这两个变量对电信客户流失预测影响非常小,可以直接舍弃。
8、网络安全服务、在线备份业务、设备保护业务、技术支持服务、网络电视、网络电影和无互联网服务对客户流失率的影响
网络安全服务、在线备份业务、设备保护业务、技术支持服务、网络电视、网络电影和无互联网服务对客户流失率的影响 covariable=['OnlineSecurity','OnlineBackup','DeviceProtection','TechSupport','StreamingTV','StreamingMovies'] plt.figure(figsize=(17,10)) for i,item in enumerate(covariable): plt.subplot(2,3,(i+1)) ax=sns.countplot(x=item,hue='Churn',data=data,palette='Set2',order=['Yes','No','No internet service']) plt.xlabel(str(item)) plt.title(str(item)+'对客户流失的影响3144',fontsize=15) i=i+1 plt.show()
由上图可以看出,在网络安全服务、在线备份业务、设备保护业务、技术支持服务、网络电视和网络电影六个变量中,没有互联网服务的客户流失率值是相同的,都是相对较低。
#这可能是因为以上六个因素只有在客户使用互联网服务时才会影响客户的决策,这六个因素不会对不使用互联网服务的客户决定是否流失产生推论效应。
9、绘制签订合同方式对客户流失率的影响直方图和绘制付款方式对客户流失率的影响直方图
ax=sns.barplot(x='Contract',y='Churn',data=data,palette='Set2',order=['Month-to-month','One year','Two year']) plt.title('签订合同方式对客户流失率的影响3125',fontsize=15) plt.show() #由图可以看出,签订合同方式对客户流失率影响为:按月签订 > 按一年签订 > 按两年签订,这可能表明,设定长期合同对留住现有客户更有效。 #付款方式对客户流失率的影响 plt.figure(figsize=(10,5)) ax=sns.barplot(x='PaymentMethod',y='Churn',data=data,palette='Set2', order=['Bank transfer (automatic)','Credit card (automatic)','Electronic check','Mailed check']) plt.title('付款方式对客户流失率的影响3144',fontsize=15) plt.show()
通过上述分析,我们可以大致勾勒出容易流失的用户特征:
老年用户与未婚且经济未独立的青少年用户更容易流失。
电话服务对用户的流失没有直接的影响。
提供的各项网络服务项目能够降低用户的流失率。
签订合同越久,用户的留存率越高。
采用electronic check支付的用户更易流失。
针对上述诊断结果,可有针对性的对此提出建议:
推荐老年用户与青少年用户采用数字网络,且签订2年期合同(可以各种辅助优惠等营销手段来提高2年期合同的签订率),
若能开通相关网络服务可增加用户粘性,因此可增加这块业务的推广,同时考虑改善电子账单支付的用户体验。