第三次作业-电信流失预测

浏览: 1091

2.1.3 

答:统计学习算法中的超参数可以理解为非算法本身的参数,

而是辅助训练出算法的最优模型使用到的参数,不是从数据本身

可以学习到的参数。

线性回归和逻辑回归中未涉及到超参数。

岭回归和Lasso算法中的超参数是正则化系数(惩罚系数),

为了防止模型过拟合。

统计学习算法中可以使用交叉验证的方法来确定最优超参数的值,

有一个超参数的list,使用list中的每个数值作为超参数来训练,

以某个指标为标准,比如mse,找出rmse最小的模型对应的超参数。

2.1.4

答:

统计分析方法寻找最优模型思路:

1、 对解释变量、被解释变量做描述性统计分析

2、 分析解释变量和被解释变量的关系,使用交叉表、两样本T检验、

方差分析、相关分析等找出和被解释变量相关的解释变量。

3、 使用筛选出来的解释变量及交互项建模

4、 根据指标评估模型的好坏,残差分析、召回率、ROC曲线、VIF等

来调整解释变量及交互项,最终找到最优模型。

统计学习方法寻找最优模型思路:

1、对特征进行分析,属于数值型、类别型,对数值型特征进行缩放,

保证处于同一个数量级,对类别型特征做独热向量编码。

2、使用处理后的特征建模,根据评估指标(比如mse,logloss),

网格搜索交叉验证来确定超参数。使用超参数建模,得到模型。

3、对使用的特征进行筛选,LASSO具有特征筛选的作用,也可以使用

向前逐步法和向后逐步法暴力筛选变量,得到新的特征变量。

4、反复进行2、3步骤,最终的到最优模型

感觉两种方法在回归模型的训练上大同小异,自己思路不是很清晰。

2.1.5

答:

二分类评估模型的决策类指标:

建立混淆矩阵,得出A(True Positive)、B(False Negative)、

C(False Positive)、D(True Negative)

1、正确率=(A+D)/(A+B+C+D)

2、灵敏度(召回率)=A/(A+B)

3、命中率(PV+)=A/(A+C)

4、特异度(负例的召回率)=D(C+D)

5、负命中率(PV-)=D/(B+D)

排序类指标:

1、ROC曲线

2、K-S曲线

3、累积提升曲线

4、洛伦兹曲线


2.2 案例解答

#%%

import pandas as pd

import numpy as np

import matplotlib

import matplotlib.pyplot as plt

import seaborn as sns

import statsmodels.api as sm

import statsmodels.formula.api as smf

import os

os.chdir(r'D:\give_me_five\DataAnalysis\Case4')

matplotlib.rcParams['axes.unicode_minus'] = False # 解决画图时负号显示为方框问题

plt.rcParams['font.sans-serif'] = ['SimHei'] #指定默认字符集

#%%
# 读入数据
dat0 = pd.read_csv('./dataset/telecom_churn.csv')

dat0.head()

#%%

# 2.2.1 两变量分析

# 检测该用户通话时长是否呈现上升态势(posTrend)对流失(churn)是否有侧价值

# posTrend 变量取值

print(dat0.posTrend.unique())

# churn 变量取值

print(dat0.churn.unique())

# 两个类别型变量 使用交叉表分析

dat1 = pd.crosstab(dat0.churn,dat0.posTrend)

# 在流失客户中,通话时长呈上升趋势和非上升趋势的比例 35.5% : 64.5%

# 在非流失客户中,通话时长呈上升趋势和非上升趋势的比例 43% :57%

print(dat1.div(dat1.sum(1),axis=0))

# 在呈上升趋势客户中,流失和非流失比例是 33%:67%

# 在呈非上升趋势客户中,流失和费流失比例 是 54.4% : 45.6%

print(dat1.div(dat1.sum(0),axis=1))

# 最终得出结论,通话时长是否呈上升态势对流失有影响

dat1.plot(kind='bar')

#%%

# 2.2.2 逻辑回归模型

# 在网时长 duration 数值型变量

# 单变量分析,描述性统计分析

# 最大值73 最小值2 中位数小于平均值 右偏

print(dat0.duration.agg(['mean','median','std','min','max']))

print(dat0.duration.describe().T)

fig = plt.figure(figsize=(8,6))

dat0.duration.hist(bins=20)

# 流失客户平均在网时长,明显小于非流失客户, 7:20

dat2 = dat0.groupby(['churn'])['duration'].mean()

fig = plt.figure(figsize=(8,6))

dat2.plot(kind='bar')

plt.xlabel('是否流失')

plt.ylabel('平均入网时长')

plt.title('流失客户和非流失客户的平均在网时长')

#%%

from sklearn.model_selection import train_test_split

from sklearn.linear_model import LogisticRegression

from sklearn.metrics import auc,roc_auc_score,roc_curve

from sklearn.metrics import accuracy_score,recall_score,confusion_matrix

dat2x = dat0.duration

dat2y = dat0.churn

# 拆分数据集,分为训练集和测试集

X_train,X_test,y_train,y_test = train_test_split(dat2x,dat2y,test_size=0.3)

#%%

# 训练模型

lr = LogisticRegression()

lr.fit(X_train.values.reshape(-1,1),y_train)

# 预测概率

y_test_proba = lr.predict_proba(X_test.values.reshape(-1,1))

# 预测流失 阈值为0.5

y_test_s = pd.Series(y_test_proba[:,1])

y_test_s = y_test_s.map(lambda x: 1 if x >= 0.5 else 0)

# 准确率

print('accuracy score: ' , round(accuracy_score(y_test,y_test_s.values),3))

# 召回率

print('recall score: %.3f' % recall_score(y_test,y_test_s.values))

# 混淆矩阵

confusion_matrix(y_test,y_test_s)

# 衡量指标

fpr,tpr,thresholds = roc_curve(y_test,y_test_proba[:,-1])

# auc 0.864 是不是有点高了?

print('auc : %.3f' % auc(fpr,tpr))

# ROC 曲线

fig = plt.figure(figsize=(8,6))

plt.plot(fpr,tpr,'k--',label='ROC (area = %.3f)' % auc(fpr,tpr))

plt.xlabel('False Positive Rate')

plt.ylabel('True Positive Rate')

plt.title(' Roc Curve')

plt.legend()

plt.show()

#%%

# 2.2.3

dat3 = dat0.drop(['subscriberID'],axis=1).copy()

#%%

# 处理数值型变量, 保持数值范围在同一个数量级

from sklearn.preprocessing import MinMaxScaler

mmScaler = MinMaxScaler()

numerical_cols = ['AGE','edu_class','incomeCode','duration',

'peakMinAv','peakMinDiff','nrProm','curPlan',

'avgplan','planChange']

for col in numerical_cols:

dat3[col] = mmScaler.fit_transform(dat3[col].values.reshape(-1,1))

#%%

# 向前逐步回归选择变量

'''forward select'''

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:

aic = smf.Logit(data[response],data[selected+[candidate]]).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

return selected

selected_cols = forward_select(dat3,'churn')

dat4 = dat3[selected_cols + ['churn']]

#%%

# 检查模型的膨胀系数

from statsmodels.stats.outliers_influence import variance_inflation_factor

def FuncVif(df):

vif = pd.DataFrame({'features':df.columns})

vif['vifValue'] = [variance_inflation_factor(df.values,i) for i in range(df.shape[1])]

vif = vif.sort_values(by='vifValue',ascending=False)

return vif

FuncVif(dat4)

#%%

# 删除vif值最高的planChange

dat4 = dat4.drop(['planChange'],axis=1)

FuncVif(dat4)

#%%

# 继续删除 peakMinDiff

dat4 = dat4.drop(['peakMinDiff'],axis=1)

FuncVif(dat4)

#%%

# 继续删除 nrProm

dat4 = dat4.drop(['nrProm'],axis=1)

FuncVif(dat4)

# 此时vif都小于10

#%%

# 训练模型

def FuncScore(y_true,y_score):



y_pred = y_score.map(lambda x: 1 if x >= 0.5 else 0)

# 准确率

print('accuracy score: ' , round(accuracy_score(y_true,y_pred.values),3))

# 召回率

print('recall score: %.3f' % recall_score(y_true,y_pred.values))

# 混淆矩阵

confusion_matrix(y_true,y_pred)

# 衡量指标

fpr,tpr,thresholds = roc_curve(y_true,y_score)

# auc

print('auc : %.3f' % auc(fpr,tpr))

# ROC 曲线

plt.plot(fpr,tpr,'k--',label='ROC (area = %.3f)' % auc(fpr,tpr))

plt.xlabel('False Positive Rate')

plt.ylabel('True Positive Rate')

plt.title(' Roc Curve')

plt.legend()

plt.show()



dat4x = dat4.drop(['churn'],axis=1)

dat4y = dat4.churn

X_train,X_test,y_train,y_test = train_test_split(dat4x,dat4y,test_size=0.3)

model4 = smf.Logit(y_train,X_train).fit()

y_test_proba_4 = model4.predict(X_test)

# auc 面积高达0.913 是不是有问题?

FuncScore(y_test,y_test_proba_4)

#%%

# 2.2.4 使用LASSO 和Ridge

# 查看下样本比例,4:3 ,接近1:1

print(dat3.churn.value_counts())

# 使用网格搜索交叉验证

# 训练集 、 测试集拆分

from sklearn.model_selection import GridSearchCV

dat5x = dat3.drop(['churn'],axis=1)

dat5y = dat3.churn

X_train,X_test,y_train,y_test = train_test_split(dat5x,dat5y,test_size=0.3,random_state=1024)

param_grid = {'C':[0.10,0.15,0.5,0.7,1.0,1.2,1.5,1.8,2.0]}

#%%

# LASSO

clf = LogisticRegression(penalty='l1')

# 三折交叉验证

grid_search = GridSearchCV(clf,param_grid,cv=5,scoring='roc_auc')

grid_search.fit(X_train,y_train)

print(grid_search.best_estimator_)

# 使用最优惩罚系数建立模型

lasso = LogisticRegression(penalty='l1',solver='liblinear',C=2.0)

lasso.fit(X_train,y_train)

y_test_proba_l = lasso.predict_proba(X_test)

y_test_proba_l = pd.Series(y_test_proba_l[:,1])

# 查看准确率,召回率 准确率0.828,召回率0.8,roc0.92 有点高,不太靠谱吧?

FuncScore(y_test,y_test_proba_l)

# 查看每一个特征的系数

coef = pd.DataFrame()

coef['feature'] = X_test.columns

coef['value'] = lasso.coef_.ravel()

# 查看膨胀系数

cols = coef[coef.value != 0 ]['feature']

FuncVif(dat3[cols])

#%%

# Ridge 逻辑回归默认使用L2正则化

clf = LogisticRegression()

grid_search = GridSearchCV(clf,param_grid,cv=5,scoring='roc_auc')

grid_search.fit(X_train,y_train)

print(grid_search.best_estimator_)

# 使用最优惩罚系数建立模型

ridge = LogisticRegression(penalty='l2',C=2.0)

ridge.fit(X_train,y_train)

y_test_proba_r = ridge.predict_proba(X_test)

y_test_proba_r = pd.Series(y_test_proba_r[:,1])

FuncScore(y_test,y_test_proba_r)

# 查看每一个特征的系数

coef = pd.DataFrame()

coef['feature'] = X_test.columns

coef['value'] = ridge.coef_.ravel()

# 查看膨胀系数

cols = coef[coef.value != 0 ]['feature']

FuncVif(dat3[cols])

#%%



LASSO训练出来的模型和步骤3训练出来的模型差异

答:LASSO 使用所有变量建模,使用交叉验证,以roc_auc的值

为标准,得出超参数的值。使用最优超参数建模,训练模型,得出特征的系数,

系数中avgplan和planChange的系数为0,这是LASSO的优点,

可以做特征筛选,最终使用16个特征建模。

步骤3 训练模型使用向前逐步法,以AIC为标准,筛选出多个

特征变量,再以模型的膨胀系数来筛选特征,最终使用13个特征建模。

推荐 0
本文由 keikeiML 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册