赞
踩
1. 项目背景
在电信用户运营中如何有效预测用户流失,了解潜在流失用户的流失概率,对潜在流失客户做特征分析和流失原因分析,将有助于运营童鞋发现改善用户体验的抓手,和确定挽留目标用户并制定有效方案
2. 提出问题
1、哪些用户可能会流失?
2、流失概率更高的用户有什么共同特征?
根据提出的问题可以对用户数据做如下分析,本文只进行用户流失预测模型
3. 理解数据
以下是数据指标的内容和含义
4. 数据清洗
4.1 导入数据并查看数据
python金融风控评分卡模型和数据分析(加强版) 入口1(推荐) https://ke.qq.com/course/package/43071 入口2 https://study.163.com/series/1202915601.htm?share=2&shareId=400000000398149 import warnings #忽略警告提示 warnings.filterwarnings('ignore') import os import numpy as np from scipy import stats import pandas as pd import statsmodels.api as sm import statsmodels.formula.api as smf import matplotlib.pyplot as plt # 导入数据和查看数据 os.chdir(r'……\数据分析案例') churn=pd.read_csv(r'telecom_churn.csv') print(churn.head(),'\n) print(churn.shape)
打印结果
打印结果
从数据查看的结果了解到:
数据一共有3463个样本,20个数据指标,且没有缺失数据
4.2 选取部分字段进行卡方检验
# 检验该用户通话时长是否呈现出上升态势(posTrend)对流失(churn) 是否有预测价值
# 分类变量的相关关系
cross_table=pd.crosstab(churn.posTrend,churn.churn,margins=True)
print(cross_table)
# 列联表
def percConvert(ser):
return ser/float(ser[-1])
cross_table.apply(percConvert,axis=1)
# 卡方检验
print('''chisq=%6.4f
p_value=%6.4f
dof=%i
expected_freq=%s'''%stats.chi2_contingency(cross_table.iloc[:2,:2]))
打印结果
卡方检验的H0假设为:用户通话时长趋势与用户流失无关,从p值的结果为0,因此拒绝H0假
5. 构建模型
流失预测模型
建立训练数据集和测试数据集
# 随机抽样,建立训练集与测试集
train=churn.sample(frac=0.75,random_state=1234).copy()
test=churn[~churn.index.isin(train.index)].copy()
print(' 训练集样本量: %i \n 测试集样本量: %i' %(len(train), len(test)))
打印结果
5.1 模型一
# 相关性矩阵
corrDf = churn.corr(method='pearson')
corrDf
# 查看各个特征与生存情况的相关系数
corrDf['churn'].sort_values(ascending =False)
# 使用广义线性回归模型建模
lg=smf.glm('churn~duration',data=train,
family=sm.families.Binomial(sm.families.links.logit)).fit()
print(lg.summary())
从各自变量和因变量的相关系数看,只有duration自变量和churn因变量中度相关。
使用duration自变量对churn因变量建立回归模型,回归系数P值均通过检验
5.2 模型二
检验模型的膨胀系数,再使用向前逐步法从其它备选变量中选择变量,构建基于AIC的最优模型
# 计算膨胀因子 candidates=['churn','duration','AGE','edu_class','posTrend', 'negTrend','nrProm','prom','curPlan','avgplan', 'planChange','incomeCode','feton','peakMinAv', 'peakMinDiff','call_10086'] def vif(df,col_i): from statsmodels.formula.api import ols cols=list(df.columns) cols.remove(col_i) cols_noti=cols formula=col_i+'~'+'+'.join(cols_noti) r2=ols(formula,df).fit().rsquared return 1/(1-r2) exog=train[candidates].drop(['churn'],axis=1) for i in exog.columns: print(i,'\t',vif(df=exog,col_i=i))
从膨胀因子VIF看,posTrend,negTrend;nrProm,prom;curPlan,avgplan有明显的共线性问题,剔除其中三个变量后再建模
# 向前逐步法 def forward_select(data,response): remaining=set(data.columns) remaining.remove(response) selected=[] current_score,best_new_score=float('inf'),float('inf') while remaining: aic_with_candidates=[] for candidate in remaining: formula='{}~{}'.format( response,'+'.join(selected+[candidate])) aic=smf.glm( formula=formula,data=data, family=sm.families.Binomial(sm.families.links.logit) ).fit().aic aic_with_candidates.append((aic,candidate)) aic_with_candidates.sort(reverse=True) best_new_score,best_candidate=aic_with_candidates.pop() if current_score>best_new_score: remaining.remove(best_candidate) selected.append(best_candidate) current_score=best_new_score print('aic is {},continuing!'.format(current_score)) else: print('forward selection over!') break formula='{}~{}'.format(response,'+'.join(selected)) print('final formula is {}'.format(formula)) model=smf.glm( formula=formula,data=data, family=sm.families.Binomial(sm.families.links.logit) ).fit() return(model) # 建模 candidates=['churn','duration','AGE','edu_class','posTrend', 'prom','curPlan','planChange','incomeCode','feton', 'peakMinAv','peakMinDiff','call_10086'] data_for_select=train[candidates] lg_m2=forward_select(data=data_for_select,response='churn') print(lg_m2.summary())
系数的P值均通过检验
5.3 模型三
使用lasso回归建立模型,lasso回归使用L1正则化,并使用交叉验证法确定惩罚参数(C值),
from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import StandardScaler candidates=['duration','AGE','edu_class','posTrend', 'negTrend','nrProm','prom','curPlan','avgplan', 'planChange','incomeCode','feton','peakMinAv', 'peakMinDiff','call_10086'] scaler=StandardScaler()# 标准化 X=scaler.fit_transform(churn[candidates]) y=churn['churn'] # 正则化 from sklearn import linear_model from sklearn.svm import l1_min_c import datetime cs=l1_min_c(X,y,loss='log')*np.logspace(0,4) print('Computing regularization path …') start = datetime.datetime.now() clf=linear_model.LogisticRegression(C=1, penalty='l1',tol=1e-6) coefs_=[] for c in cs: clf.set_params(C=c) clf.fit(X,y) coefs_.append(clf.coef_.ravel().copy()) print("This took ", datetime.datetime.now() - start) # 绘图 coefs_=np.array(coefs_) plt.plot(np.log10(cs),coefs_) ymin, ymax = plt.ylim() plt.xlabel('log(C)') plt.ylabel('Coefficients') plt.title('Logistic Regression Path') plt.axis('tight') plt.show() # 交叉验证参数 cs=l1_min_c(X,y,loss='log')*np.logspace(0,4) import matplotlib.pyplot as plt from sklearn.model_selection import cross_val_score # K折交叉验证 k_scores=[] clf=linear_model.LogisticRegression(penalty='l1') # 由迭代的方式来计算不同参数对模型的影响,并返回交叉验证后的平均准确率 for c in cs: clf.set_params(C=c) scores=cross_val_score(clf,X,y,cv=10,scoring='roc_auc') k_scores.append([c,scores.mean(),scores.std()]) # 可视化 data=pd.DataFrame(k_scores) # 将字典转换成为数据框 fig=plt.figure() ax1=fig.add_subplot(111) ax1.plot(np.log10(data[0]),data[1],'b') ax1.set_ylabel('log10(cs)') ax2=ax1.twinx() ax2.plot(np.log10(data[0]),data[2],'r') ax2.set_ylabel('Std ROC Index(Red)')
从方差曲线看,C值在-1.9左右方差最小,因此确定-1.9做为C值的最佳选择
# 实现Lasso算法
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
candidates=['duration','AGE','edu_class','posTrend','negTrend',
'nrProm','prom','curPlan','avgplan','planChange',
'incomeCode','feton','peakMinAv','peakMinDiff','call_10086']
scaler=StandardScaler() # 标准化
X=scaler.fit_transform(train[candidates])
y=train['churn']
from sklearn import linear_model
clf=linear_model.LogisticRegression(C=np.exp(-1.9),penalty='l1')
clf.fit(X,y)
print(clf.coef_)
自变量系数
使用L1正则化,得到2个变量的系数为0
5.4 模型评估
from sklearn import metrics # lg模型预测 train['lg_proba']=lg.predict(train) test['lg_proba']=lg.predict(test) # lg_m2模型预测 train['lg_m2_proba']=lg_m2.predict(train) test['lg_m2_proba']=lg_m2.predict(test) # clf模型预测 X1=scaler.fit_transform(test[candidates]) y1=test['churn'] train['clf_proba']=clf.predict(X) test['clf_proba']=clf.predict(X1) # 计算准确率 lg_acc=sum(test['lg_prediction']==test['churn'])/np.float(len(test)) lg_m2_acc=sum(test['lg_m2_prediction']==test['churn'])/np.float(len(test)) clf_acc=sum(test['clf_prediction']==test['churn'])/np.float(len(test)) print('The accurancy of lg is %.2f'%lg_acc,'\n') print('The accurancy of lg_m2 is %.2f'%lg_m2_acc,'\n') print('The accurancy of clf is %.2f'%clf_acc,'\n') i=0.5 # 设定阈值 lg_prediction=(test['lg_proba']>i).astype('int') lg_m2_prediction=(test['lg_m2_proba']>i).astype('int') clf_prediction=(test['clf_proba']>i).astype('int') # 混淆矩阵 lg_confusion_matrix=pd.crosstab(lg_prediction,test.churn,margins=True) lg_m2_confusion_matrix=pd.crosstab(lg_m2_prediction,test.churn,margins=True) clf_confusion_matrix=pd.crosstab(clf_prediction,test.churn,margins=True) # 计算评估指标 print('lg评估指标','\n',metrics.classification_report(test.churn, lg_prediction)) print('lg_m2评估指标','\n',metrics.classification_report(test.churn, lg_m2_prediction)) print('clf评估指标','\n',metrics.classification_report(test.churn, clf_prediction)) # 绘制Roc曲线 import sklearn.metrics as metrics lg_fpr_test,lg_tpr_test,lg_th_test=metrics.roc_curve(test.churn,test.lg_proba) lg_fpr_train,lg_tpr_train,lg_th_train=metrics.roc_curve(train.churn,train.lg_proba) lg_m2_fpr_test,lg_m2_tpr_test,lg_m2_th_test=metrics.roc_curve(test.churn,test.lg_m2_proba) lg_m2_fpr_train,lg_m2_tpr_train,lg_m2_th_train=metrics.roc_curve(train.churn,train.lg_m2_proba) clf_fpr_test,clf_tpr_test,clf_th_test=metrics.roc_curve(test.churn,test.clf_proba) clf_fpr_train,clf_tpr_train,clf_th_train=metrics.roc_curve(train.churn,train.clf_proba) plt.subplots_adjust(hspace=0.3,wspace=0.3) plt.subplot(221) plt.plot(lg_fpr_test,lg_tpr_test,'b--',label='test') plt.plot(lg_fpr_train,lg_tpr_train,'r--',label='train') plt.title('lg_ROC curve') plt.legend(loc='best') plt.subplot(222) plt.plot(lg_m2_fpr_test,lg_m2_tpr_test,'b--',label='test') plt.plot(lg_m2_fpr_train,lg_m2_tpr_train,'r--',label='train') plt.title('lg_m2_ROC curve') plt.legend(loc='best') plt.subplot(223) plt.plot(clf_fpr_test,clf_tpr_test,'b--',label='test') plt.plot(clf_fpr_train,clf_tpr_train,'r--',label='train') plt.title('clf_ROC curve') plt.legend(loc='best') plt.subplot(224) plt.plot(lg_fpr_test,lg_tpr_test,'b--',label='lg') plt.plot(lg_m2_fpr_test,lg_m2_tpr_test,'r--',label='lg_m2') plt.plot(clf_fpr_test,clf_tpr_test,'g--',label='cfl') plt.title('ROC_test curve') plt.legend(loc='best') plt.subplots_adjust(hspace=0.5,wspace=0.3) plt.show() print('lg_AUC=%.4f'%metrics.auc(lg_fpr_test,lg_tpr_test)) print('lg_m2_AUC=%.4f'%metrics.auc(lg_m2_fpr_test,lg_m2_tpr_test)) print('clf_AUC=%.4f'%metrics.auc(clf_fpr_test,clf_tpr_test))
lg_m2模型和clf模型的正确率较高,正确率达到80%,且这两个模型的精确率和召回率差不多。
三个模型训练数据和测试数据曲线趋于重合,不存在过拟合的情况。
从三个模型的测试数据的ROC曲线和AUC值看,lg_m2模型优于其他模型。
转载https://zhuanlan.zhihu.com/p/58193546
总结:此文章对机器学习建模流程有一个清晰解读,建议大家学习。从细节角度看,很多微观地方处理过于机械,针对不同算法有不同处理方法,大家不要生硬模仿。欢迎同学关注《python金融风控评分卡模型和数据分析(加强版)》学习专业建模知识。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。