2020-05-18 第九章 Logistic回归模型

第九章 Logistic回归模型

01 Logistic回归模型构建以及求解参数

背景知识

  • 在实际的数据挖掘中,站在预测类问题的角度来看,除了需要预测连续型的因变量,还需要预判离散型的因变量。
  • 对于连续型变量的预测,可以借助于多元线性回归模型、岭回归模型或LASSO回归模型来解决。
  • 而对于离散型变量的识别(尤其是二元问题),则可以通过Logistic回归模型解决。

Logistic回归模型的用途

  • 一个是寻找“危险”因素,例如,医学界通常使用模型中的优势比寻找影响某种疾病的“坏”因素。
  • 另一个用途是判别新样本所属的类别,例如根据手机设备的记录数据判断用户是处于行走状态还是跑步状态。

Logistic与线性回归的关系

image.png
  • 如果以0.5作为判别标准,左图呈现的回归模型对肿瘤的划分还是比较合理的,因为当肿瘤体积小于x_1时,都能够将良性肿瘤判断出来,反之亦然;
  • 再来看右图,当恶性肿瘤在x轴上相对分散时,得到的线性回归模型会导致结果的误判;
  • 根据图中信息可知,当线性回归模型的预测值越大(如果以0.5作为阈值),则肿瘤被判为恶性的可能性就越大,反之亦然;
  • 如果对线性回归模型做某种变换,能够使预测值被“压缩”在0~1之间,那么这个范围就可以理解为恶性肿瘤的概率。当预测值越大,转换后的概率值就越接近于1,从而得到肿瘤为恶性的概率也就越大,反之亦然;

Logit变换

image.png
  • 其中,z∈(−∞,+∞)。当z趋于正无穷大时,e^−z将趋于0,进而导致g(z)逼近于1;
  • 相反,当z趋于负无穷大时,e^−z会趋于正无穷大,最终导致g(z)逼近于0;
  • z=0时,e^−z=1,所以得到g(z)=0.5
  • Logistic回归模型,它是将线性回归模型的预测值经过非线性的Logit函数转换为[0,1]之间的概率值。

Logistic模型到线性回归模型的转变

优势(odds)或发生比,代表了某个事件发生与不发生的概率比值,它的范围落在(0, +∞)之间。

02 Logistic回归模型的参数解释

事件发生比

  • 假设影响是否患癌的因素有性别和肿瘤两个变量,通过建模可以得到对应的系数β_1和β_2,则Logistic回归模型可以按照事件发生比的形式改写为:odds=e^β_0×e^β_1Gender×e^β_2Volum
  • 分别以性别变量和肿瘤体积变量为例,解释系数β_1和β_2的含义。假设性别中男用1表示,女用0表示,则:性别变量的发生比率为e^β_1,表示男性患癌的发生比约为女性患癌发生比的e^β_1倍。
  • 对于连续型的自变量而言,参数解释类似,假设肿瘤体积为Volum_0,当肿瘤体积增加1个单位时,体积为Volum_0+1,则:在其他变量不变的情况下,肿瘤体积每增加一个单位,将会使患癌发生比变化e^β_2倍。

03 模型效果的评估的方法

混淆矩阵

image.png

A:表示正确预测负例的样本个数,用TN表示。
B:表示预测为负例但实际为正例的个数,用FN表示。
C:表示预测为正例但实际为负例的个数,用FP表示。
D:表示正确预测正例的样本个数,用TP表示。
A+B:表示预测负例的样本个数,用PN表示。
C+D:表示预测正例的样本个数,用PP表示。
A+C:表示实际负例的样本个数,用AN表示。
B+D:表示实际正例的样本个数,用AP表示。
准确率:表示正确预测的正负例样本数与所有样本数量的比值,即(A+D)/(A+B+C+D)。
正例覆盖率:表示正确预测的正例数在实际正例数中的比例,即D/(B+D) 。
负例覆盖率:表示正确预测的负例数在实际负例数中的比例,即A/(A+C)。
正例命中率:表示正确预测的正例数在预测正例数中的比例,即D/(C+D)。

ROC曲线

image.png

图中的红色线为参考线,即在不使用模型的情况下,Sensitivity1-Specificity 之比恒等于 1。通常绘制ROC曲线,不仅仅是得到左侧的图形,更重要的是计算折线下的面积,即图中的阴影部分,这个面积称为AUC。在做模型评估时,希望AUC的值越大越好,通常情况下,当AUC在0.8以上时,模型就基本可以接受了。

KS曲线

image.png

图中的两条折线分别代表各分位点下的正例覆盖率和1-负例覆盖率,通过两条曲线很难对模型的好坏做评估,一般会选用最大的KS值作为衡量指标。KS的计算公式为:KS= Sensitivity-(1- Specificity)= Sensitivity+ Specificity-1。对于KS值而言,也是希望越大越好,通常情况下,当KS值大于0.4时,模型基本可以接受

04 Logistic回归模型的实战

函数解释

LogisticRegression(penalty='l2', dual=False, tol=0.0001, C=1.0, fit_intercept=True, intercept_scaling=1, 
                               class_weight=None, random_state=None, solver= 'liblinear',max_iter=100, 
                               multi_class='ovr', verbose=0, warm_start=False, n_jobs=1)

penalty:为Logistic回归模型的目标函数添加正则化惩罚项,与线性回归模型类似,默认为l2正则
dual:bool类型参数,是否求解对偶形式,默认为False,只有当penalty参数为'l2'、solver参数为'liblinear'时,才可使用对偶形式
tol:用于指定模型跌倒收敛的阈值
C:用于指定惩罚项系数Lambda的倒数,值越小,正则化项越大
fit_intercept:bool类型参数,是否拟合模型的截距项,默认为True
intercept_scaling:当solver参数为'liblinear'时该参数有效,主要是为了降低X矩阵中人为设定的常数列1的影响
class_weight:用于指定因变量类别的权重,如果为字典,则通过字典的形式{class_label:weight}传递每个类别的权重;如果为字符串'balanced',则每个分类的权重与实际样本中的比例成反比,当各分类存在严重不平衡时,设置为'balanced'会比较好;如果为None,则表示每个分类的权重相等
random_state:用于指定随机数生成器的种子
solver:用于指定求解目标函数最优化的算法,默认为'liblinear',还有其他选项,如牛顿法'newton-cg'、L-BFGS拟牛顿法'lbfgs'
max_iter:指定模型求解过程中的最大迭代次数, 默认为100
multi_class:如果因变量不止两个分类,可以通过该参数指定多分类问题的解决办法,默认采用'ovr',即one-vs-rest方法,还可以指定'multinomial',表示直接使用多分类逻辑回归模型(Softmax分类)
verbose:bool类型参数,是否输出模型迭代过程的信息,默认为0,表示不输出
warm_start:bool类型参数,是否基于上一次的训练结果继续训练模型,默认为False,表示每次迭代都是从头开始
n_jobs:指定模型运算时使用的CPU数量,默认为1,如果为-1,表示使用所有可用的CPU

核心代码应用示例

自定义绘制ks曲线的函数
20200522订正

# 自定义绘制ks曲线的函数
def plot_ks(y_test, y_score, positive_flag):
    # 对y_test,y_score重新设置索引
    y_test.index = np.arange(len(y_test))
    #y_score.index = np.arange(len(y_score))
    # 构建目标数据集
    target_data = pd.DataFrame({'y_test':y_test, 'y_score':y_score})
    # 按y_score降序排列
    target_data.sort_values(by = 'y_score', ascending = False, inplace = True)
    # 自定义分位点
    cuts = np.arange(0.1,1,0.1)
    # 计算各分位点对应的Score值
    index = len(target_data.y_score)*cuts
    scores = target_data.y_score.iloc[index.astype('int')]
    # 根据不同的Score值,计算Sensitivity和Specificity
    Sensitivity = []
    Specificity = []
    for score in scores:
        # 正例覆盖样本数量与实际正例样本量
        positive_recall = target_data.loc[(target_data.y_test == positive_flag) & (target_data.y_score>score),:].shape[0]
        positive = sum(target_data.y_test == positive_flag)
        # 负例覆盖样本数量与实际负例样本量
        negative_recall = target_data.loc[(target_data.y_test != positive_flag) & (target_data.y_score<=score),:].shape[0]
        negative = sum(target_data.y_test != positive_flag)
        Sensitivity.append(positive_recall/positive)
        Specificity.append(negative_recall/negative)
    # 构建绘图数据
    plot_data = pd.DataFrame({'cuts':cuts,'y1':1-np.array(Specificity),'y2':np.array(Sensitivity), 
                              'ks':np.array(Sensitivity)-(1-np.array(Specificity))})
    # 寻找Sensitivity和1-Specificity之差的最大值索引
    max_ks_index = np.argmax(plot_data.ks)
    plt.plot([0]+cuts.tolist()+[1], [0]+plot_data.y1.tolist()+[1], label = '1-Specificity')
    plt.plot([0]+cuts.tolist()+[1], [0]+plot_data.y2.tolist()+[1], label = 'Sensitivity')
    # 添加参考线
    plt.vlines(plot_data.cuts[max_ks_index], ymin = plot_data.y1[max_ks_index], 
               ymax = plot_data.y2[max_ks_index], linestyles = '--')
    # 添加文本信息
    plt.text(x = plot_data.cuts[max_ks_index]+0.01,
             y = plot_data.y1[max_ks_index]+plot_data.ks[max_ks_index]/2,
             s = 'KS= %.2f' %plot_data.ks[max_ks_index])
    # 显示图例
    plt.legend()
    # 显示图形
    plt.show()

image.png

绘图

# 导入第三方包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 导入虚拟数据
virtual_data = pd.read_excel('./virtual_data.xlsx')
# 应用自定义函数绘制k-s曲线
plot_ks(y_test = virtual_data.Class, y_score = virtual_data.Score,positive_flag = 'P')  
Figure_1.png

Lasso回归模型的应用

# 导入第三方模块
import pandas as pd
import numpy as np
from sklearn import linear_model
from sklearn import model_selection

# 读取数据
sports = pd.read_csv('./Run or Walk.csv')
# 提取出所有自变量名称
predictors = sports.columns[4:]
# 构建自变量矩阵
X = sports.loc[:,predictors]
# 提取y变量值
y = sports.activity
# 将数据集拆分为训练集和测试集
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size = 0.25, random_state = 1234)

# 利用训练集建模
sklearn_logistic = linear_model.LogisticRegression()
sklearn_logistic.fit(X_train, y_train)
# 返回模型的各个参数
print(sklearn_logistic.intercept_, sklearn_logistic.coef_)

输出结果为:[4.36637441] [[ 0.48695898 6.87517973 -2.44872468 -0.01385936 -0.16085022 0.13389695]]
模型预测结果统计

# 模型预测
sklearn_predict = sklearn_logistic.predict(X_test)
# 预测结果统计
pd.Series(sklearn_predict).value_counts()

结果为:

Out[5]:
0    12119
1    10028
dtype: int64

模型评估--混淆矩阵

# 导入第三方模块
from sklearn import metrics
# 混淆矩阵
cm = metrics.confusion_matrix(y_test, sklearn_predict, labels = [0,1])
cm

结果为:

Out[6]:
array([[9969, 1122],
       [2150, 8906]])
Accuracy = metrics.accuracy_score(y_test, sklearn_predict)
Sensitivity = metrics.recall_score(y_test, sklearn_predict)
Specificity = metrics.recall_score(y_test, sklearn_predict, pos_label=0)
print('模型准确率为%.2f%%:' %(Accuracy*100))
print('正例覆盖率为%.2f%%' %(Sensitivity*100))
print('负例覆盖率为%.2f%%' %(Specificity*100))

输出结果为:

模型准确率为85.23%:
正例覆盖率为80.55%
负例覆盖率为89.88%

混淆矩阵的可视化

# 混淆矩阵的可视化
# 导入第三方模块
import seaborn as sns
import matplotlib.pyplot as plt
# 绘制热力图
sns.heatmap(cm, annot = True, fmt = '.2e',cmap = 'GnBu')
# 图形显示
plt.show()
Figure_1.png

模型评估--ROC曲线

# y得分为模型预测正例的概率
y_score = sklearn_logistic.predict_proba(X_test)[:,1]
# 计算不同阈值下,fpr和tpr的组合值,其中fpr表示1-Specificity,tpr表示Sensitivity
fpr,tpr,threshold = metrics.roc_curve(y_test, y_score)
# 计算AUC的值
roc_auc = metrics.auc(fpr,tpr)

# 绘制面积图
plt.stackplot(fpr, tpr, color='steelblue', alpha = 0.5, edgecolor = 'black')
# 添加边际线
plt.plot(fpr, tpr, color='black', lw = 1)
# 添加对角线
plt.plot([0,1],[0,1], color = 'red', linestyle = '--')
# 添加文本信息
plt.text(0.5,0.3,'ROC curve (area = %0.2f)' % roc_auc)
# 添加x轴与y轴标签
plt.xlabel('1-Specificity')
plt.ylabel('Sensitivity')
# 显示图形
plt.show()
Figure_1.png

调用自定义函数,绘制K-S曲线

# 调用自定义函数,绘制K-S曲线
plot_ks(y_test = y_test, y_score = y_score, positive_flag = 1)
Figure_1.png

总结代码如下:

# -----------------------第一步 建模 ----------------------- #
# 导入第三方模块
import statsmodels.api as sm
# 将数据集拆分为训练集和测试集
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size = 0.25, random_state = 1234)
# 为训练集和测试集的X矩阵添加常数列1
X_train2 = sm.add_constant(X_train)
X_test2 = sm.add_constant(X_test)
# 拟合Logistic模型
sm_logistic = sm.formula.logit(y_train, X_train2).fit()
# 返回模型的参数
sm_logistic.params


# -----------------------第二步 预测构建混淆矩阵 ----------------------- #
# 模型在测试集上的预测
sm_y_probability = sm_logistic.predict(X_test2)
# 根据概率值,将观测进行分类,以0.5作为阈值
sm_pred_y = np.where(sm_y_probability >= 0.5, 1, 0)
# 混淆矩阵
cm = metrics.confusion_matrix(y_test, sm_pred_y, labels = [0,1])
cm


# -----------------------第三步 绘制ROC曲线 ----------------------- #
# 计算真正率和假正率 
fpr,tpr,threshold = metrics.roc_curve(y_test, sm_y_probability)
# 计算auc的值  
roc_auc = metrics.auc(fpr,tpr)
# 绘制面积图
plt.stackplot(fpr, tpr, color='steelblue', alpha = 0.5, edgecolor = 'black')
# 添加边际线
plt.plot(fpr, tpr, color='black', lw = 1)
# 添加对角线
plt.plot([0,1],[0,1], color = 'red', linestyle = '--')
# 添加文本信息
plt.text(0.5,0.3,'ROC curve (area = %0.2f)' % roc_auc)
# 添加x轴与y轴标签
plt.xlabel('1-Specificity')
plt.ylabel('Sensitivity')
# 显示图形
plt.show()


# -----------------------第四步 绘制K-S曲线 ----------------------- #
# 调用自定义函数,绘制K-S曲线
sm_y_probability.index = np.arange(len(sm_y_probability))
plot_ks(y_test = y_test, y_score = sm_y_probability, positive_flag = 1)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355