赞
踩
本案例来源乃是学习朋友常国珍老师的python数据科学书,内容非常实用!希望深入浅出学习机器学习的同学可学习北大博士常国珍建模实战课程系列常国珍录制的Python 数据科学机器学习教学视频,可以由浅入深的学习机器学习!
逻辑回归案例字段解释
#subscriberID="个人客户的ID"
#churn="是否流失:1=流失";
#Age="年龄"
#incomeCode="用户居住区域平均收入的代码"
#duration="在网时长"
#peakMinAv="统计期间内最高单月通话时长"
#peakMinDiff="统计期间结束月份与开始月份相比通话时长增加数量"
#posTrend="该用户通话时长是否呈现出上升态势:是=1"
#negTrend="该用户通话时长是否呈现出下降态势:是=1"
#nrProm="电话公司营销的数量"
#prom="最近一个月是否被营销过:是=1"
#curPlan="统计时间开始时套餐类型:1=最高通过200分钟;2=300分钟;3=350分钟;4=500分钟"
#avPlan="统计期间内平均套餐类型"
#planChange="统计结束时和开始时套餐的变化:正值代表套餐档次提升,负值代表下降,0代表不变"
#posPlanChange="统计期间是否提高套餐:1=是"
#negPlanChange="统计期间是否降低套餐:1=是"
#call_10086="拨打10086的次数"
- 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
-
- churn = pd.read_csv(r'telecom_churn.csv', skipinitialspace=True)
- churn.head()
- #1两变量分析:检验该用户通话时长是否呈现出上升态势(posTrend)对流失(churn) 是否有预测价值
- # ## 分类变量的相关关系
- #
- # 交叉表
-
- cross_table = pd.crosstab(churn.posTrend,
- churn.churn, margins=True)
- 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]))
- #2首先将原始数据拆分为训练和测试数据集,使用训练数据集建立在网时长对流失的逻辑回归,使用测试数据集制作混淆矩阵
- #(阈值为0.5),提供准确性、召回率指标,提供ROC曲线和AUC。
- # ## 逻辑回归
- # duration 在网时长 这是个连续变量 !
-
- churn.plot(x='duration', y='churn', kind='scatter')
- # •随机抽样,建立训练集与测试集
-
- # In[10]:
-
- train = churn.sample(frac=0.7, random_state=1234).copy()
- test = churn[~ churn.index.isin(train.index)].copy()
- print(' 训练集样本量: %i n 测试集样本量: %i' %(len(train), len(test)))
- # 在网时长与因变量用户流失进行建模
-
- lg = smf.glm('churn ~ duration', data=train,
- family=sm.families.Binomial(sm.families.links.logit)).fit()
- lg.summary()
- # 预测
-
- train['proba'] = lg.predict(train)
- test['proba'] = lg.predict(test)
-
- test['proba'].head()
- # ## 模型评估
- # 设定阈值来一波!
-
- # 以0.5为阈值建立混淆矩阵
-
- test['prediction'] = (test['proba'] > 0.5).astype('int')
混淆矩阵
- # 混淆矩阵
-
- pd.crosstab(test.churn, test.prediction, margins=True)
- # - 计算准确率
-
- acc = sum(test['prediction'] == test['churn']) /np.float(len(test))
- print('The accurancy is %.2f' %acc)
- """
- for i in np.arange(0.1, 0.9, 0.1):
- prediction = (test['proba'] > i).astype('int')
- confusion_matrix = pd.crosstab(prediction,test.churn,
- margins = True)
- precision = confusion_matrix.ix[0, 0] /confusion_matrix.ix['All', 0]
- recall = confusion_matrix.ix[0, 0] / confusion_matrix.ix[0, 'All']
- Specificity = confusion_matrix.ix[1, 1] /confusion_matrix.ix[1,'All']
- f1_score = 2 * (precision * recall) / (precision + recall)
- print('threshold: %s, precision: %.2f, recall:%.2f ,Specificity:%.2f , f1_score:%.2f'%(i, precision, recall, Specificity,f1_score))
- """
metrics包里有roc_curve函数来绘制ROC曲线
- # - 绘制ROC曲线
-
- import sklearn.metrics as metrics
-
- fpr_test, tpr_test, th_test = metrics.roc_curve(test.churn, test.proba)
- fpr_train, tpr_train, th_train = metrics.roc_curve(train.churn, train.proba)
-
- plt.figure(figsize=[3, 3])
- plt.plot(fpr_test, tpr_test, 'b--') #blue就是蓝色的意思
- plt.plot(fpr_train, tpr_train, 'r-')#red 就是train 的表现
- plt.title('ROC curve')
- plt.show()
train和test这两个线都是非常接近的,是不存在过度拟合的!
- # AUC是ROC曲线面积
-
- print('AUC = %.4f' %metrics.auc(fpr_test, tpr_test))
ROC曲线面积是0.8790,模型非常好了!
把所有的X都放入模型
使用向前逐步法从其它备选变量中选择变量,构建基于AIC的最优模型,绘制ROC曲线,同时检验模型的膨胀系数。
- #3使用向前逐步法从其它备选变量中选择变量,构建基于AIC的最优模型,绘制ROC曲线,同时检验模型的膨胀系数。
- # In[14]:
- #- 多元逻辑回归
- # 向前法
- 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)
逐步法(基于AIC)选择变量
- # 看看选出了哪些变量
-
- candidates = ['churn','duration','AGE','edu_class','posTrend','negTrend','nrProm','prom','curPlan','avgplan','planChange','incomeCode','feton','peakMinAv','peakMinDiff','call_10086']
- data_for_select = train[candidates]
- #调用向前法变量选择函数
- lg_m1 = forward_select(data=data_for_select, response='churn')
- lg_m1.summary()
这是选出的变量,并且选出的变量都是显著滴!
- # Seemingly wrong when using 'statsmmodels.stats.outliers_influence.variance_inflation_factor'
-
- # 来定义一个解决多重共线性问题的函数
-
- 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)
定义vif函数是因为我们还要解决变量之间多重共线性的问题!
- exog = train[candidates].drop(['churn'], axis=1)
-
- for i in exog.columns:
- print(i, 't', vif(df=exog, col_i=i))
看vif的话,一般大于10的是有共线性问题的!
posTrend,negTrend;curPlan,avgplan有明显的共线性问题,需要剔除后重新建模.
把'nrProm'和'avgplan'和posTrend 三个变量剔除!!!重新建模
- #把'nrProm'和'avgplan'和posTrend 三个变量剔除!!!重新建模
- candidates = ['churn','duration','AGE','edu_class','negTrend','prom','curPlan','planChange','incomeCode','feton','peakMinAv','peakMinDiff','call_10086']
- data_for_select = train[candidates]
-
- lg_m1 = forward_select(data=data_for_select, response='churn')
- lg_m1.summary()
-
- exog = train[candidates].drop(['churn'], axis=1)
-
- for i in exog.columns:
- print(i, 't', vif(df=exog, col_i=i))
现在多重共线性问题已经解决!
以上是传统建模方法!
下面开始机器学习的方法进行建模
- #%%
- #4)使用岭回归和Laso算法重建第三步中的模型,使用交叉验证法确定惩罚参数(C值)。并比较步骤四中Laso算法得到的模型和第三步得到的模型的差异
- 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']
- #data_for_select = churn[candidates]
- scaler = StandardScaler() # 标准化 中心标准化
- X = scaler.fit_transform(churn[candidates])
- y = churn['churn']
经过标准化的X是必须的步骤!
- #%%下面开始建模
- from sklearn import linear_model
- from sklearn.svm import l1_min_c
- cs = l1_min_c(X, y, loss='log') * np.logspace(0, 4)#在对数空间进行搜索
- cs
cs是一个搜索空间
惩罚是l1 Laso算法
- print("Computing regularization path ...")
- #start = datetime.now()
- #惩罚是l1 Laso算法,
- clf = linear_model.LogisticRegression(C=1.0, 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.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.cross_validation 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') #http://scikit-learn.org/stable/modules/model_evaluation.html
- 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('Mean ROC(Blue)')
- ax1.set_xlabel('log10(cs)')
- ax2 = ax1.twinx()
- ax2.plot(np.log10(data[0]), data[2],'r')
- ax2.set_ylabel('Std ROC Index(Red)')
蓝色是ROC曲线的均值,是X越高越好的趋势,C越高,模型越复杂
C大概是-1.9的位置是最好的
- #重新实现Laso算法
- 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']
- #data_for_select = churn[candidates]
- scaler = StandardScaler() # 标准化
- X = scaler.fit_transform(churn[candidates])
- y = churn['churn']
-
- #%%
- from sklearn import linear_model
-
- clf = linear_model.LogisticRegression(C=np.exp(-1.9), penalty='l1')
- clf.fit(X, y)
- clf.coef_
第一个变量是duration的参数,依次数过来,模型剔除了第9和第10个变量('avgplan','planChange')这两个变量被剔除了!
传统建模vif的方法刚刚剔除了把'nrProm'和'avgplan'和posTrend 三个变量剔除
机器学习方法和手工的传统建模vif的方法其实是差不多的!
往期精彩回顾
第一篇 | 深圳购房投资笔记(一)-楼市有泡沫吗?(上)
第二篇 |深圳购房投资笔记(二)-楼市有泡沫吗?(中)
第三篇|深圳购房笔记(三)-亲身经历货币棚改化(上)
第四篇|深圳购房投资笔记(四)-亲身经历货币化棚改(下)
第五篇|深圳购房投资笔记(五)-因为朋友,被杭州所迷惑
第六篇|深圳购房投资笔记(六)-为何放弃在杭州定居购房
第七篇|深圳购房投资笔记(七)-神奇的深圳人口?(下)
第八篇|深圳购房投资笔记(八)-为何选择在深圳定居购房?
第九篇|深圳购房投资笔记(九)-中国最大的炒房散户欧成效先生
第十篇|深圳购房投资笔记(十)-深圳楼市拐点已来临
第十一篇|深圳购房投资笔记(十一)-楼市谣言四处飞,我向人民说实话(上)
第十二篇|深圳购房投资笔记(十二)-楼市谣言四处飞,我想人民说实话(下)
第十三篇|深圳购房投资笔记(十三)-民间炒房高手财上团(上)
第十四篇|深圳购房笔记(十四)-2019年的这一切都是必然的
第十五篇|深圳购房投资笔记(十五)-2019年我们的处境
第十六篇|深圳购房投资笔记(十六)-从19年看李嘉诚为何资产
第十七篇|深圳购房投资笔记(十七)-2019年深圳楼市或将阴跌
第十八篇|深圳购房投资笔记(十八)-粤港澳湾区未来可期
第十九篇|深圳购房投资笔记(十九)-2019楼市倾向横盘利于刚需
深圳购房投资笔记(二十) 楼层的选择需慎重
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。