多分类逻辑回归 MNLogit python

多分类逻辑回归MNLogit

引言

相比二分类Logistics回归的广泛应用与大量例子帖子,多分类Logistics回归的python实现的帖子则数量有限,特此记录一下。

本文介绍了多分类Logistics回归的统计方面的应用,更加关注于统计分析中的模型显著性、变量显著性、变量系数等问题,使用的是python的 statsmodels库中的 MNLogit函数。若更加注重预测的准确性,或构造更加良好的预测模型,建议尝试使用sklearn库中的相关函数。

实例及python实现

数据集

[数据集链接]
(https://download.csdn.net/download/weixin_45272208/86402859)

数据集基本情况如下:共5个特征变量(gre(考试成绩),gpa(平均成绩点),gender(性别),prestige(学校威望)),1个分类变量admit(是否录取)。其中admit有3种取值:2表示录取,1表示待考虑,0表示不录取。gender(性别)0代表女性,1代表男性。prestige(学校威望)取值共1、2、3、4,4种情况,值越大,表示学校声望越差。(zhihu上的数据集做了点小改动)

多分类逻辑回归 MNLogit python
import numpy as np
import pandas as pd
import os

import warnings
warnings.filterwarnings('ignore')
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = 'all'

os.chdir(r'D:\Work\data')
data = pd.read_csv('graduate.csv')

查看数据情况

data.info()
data.head()
data['admit'].value_counts()

多分类逻辑回归 MNLogit python
0、1、2三类分别有39、234、127个人

Logistics回归

X = data.drop(['admit'], axis=1, inplace=False)
X['intercept'] = 1.0
Y = data['admit']

from statsmodels.discrete.discrete_model import MNLogit
model_LR = MNLogit(Y,X,missing='drop').fit()
model_LR.summary()
model_LR.params
输出结果

多分类逻辑回归 MNLogit python
多分类逻辑回归 MNLogit python
Optimization terminated successfully.意味着迭代成功,若超过迭代次数失败,则可尝试在fit()中添加 maxiter = n ,n为最大迭代次数,从而迭代多次获得结果。

还可以用summary2()查看模型结果。

多分类逻辑回归 MNLogit python
LLR p-value即为模型的p值,可以看出模型显著。P>|z|为参数的p值,参数部分显著。

参数系数

多分类逻辑回归 MNLogit python

; 模型评价

Precision、Recall、f1_score
from sklearn.metrics import accuracy_score, roc_auc_score, roc_curve, precision_score, recall_score, f1_score, auc
from sklearn.preprocessing import label_binarize
from itertools import cycle

nb_classes = 3

y_pred = model_LR.predict()
y_pred_max = [np.argmax(y) for y in y_pred]
y_true = Y

y_pred_b = label_binarize(y_pred_max, classes=[i for i in range(nb_classes)])
y_true_b = label_binarize(y_true, classes=[i for i in range(nb_classes)])

precision = precision_score(y_true_b, y_pred_b, average='micro')
recall = recall_score(y_true_b, y_pred_b, average='micro')
f1_score = f1_score(y_true_b, y_pred_b, average='micro')

print("Precision_score:",precision)
print("Recall_score:",recall)
print("F1_score:",f1_score)

多分类逻辑回归 MNLogit python
因为是多分类,这里我用是micro方法求得整个模型的平均的Precision、Recall和fi_score。在多分类中,这三个值是相同的。
ROC曲线及AUC
import matplotlib.pyplot as plt

Y_valid = y_true_b
Y_pred = model_LR.predict()

fpr = dict()
tpr = dict()
roc_auc = dict()
for i in range(nb_classes):
    fpr[i], tpr[i], _ = roc_curve(Y_valid[:, i], Y_pred[:, i])
    roc_auc[i] = auc(fpr[i], tpr[i])

fpr["micro"], tpr["micro"], _ = roc_curve(Y_valid.ravel(), Y_pred.ravel())
roc_auc["micro"] = auc(fpr["micro"], tpr["micro"])

lw = 2
plt.figure()
plt.plot(fpr["micro"], tpr["micro"],
  label='micro-average ROC curve (area = {0:0.2f})'
  ''.format(roc_auc["micro"]),
  color='deeppink', linestyle=':', linewidth=4)

colors = cycle(['aqua', 'darkorange', 'cornflowerblue'])
for i, color in zip(range(nb_classes), colors):
    plt.plot(fpr[i], tpr[i], color=color, lw=lw,
    label='ROC curve of class {0} (area = {1:0.2f})'
    ''.format(i, roc_auc[i]))

plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('FPR')
plt.ylabel('TPR')
plt.title('ROC曲线')
plt.legend(loc="lower right")

plt.show()

多分类逻辑回归 MNLogit python

虚线为平均的ROC曲线,其余三条分别为0、1、2三类各自的ROC曲线。

混淆矩阵
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['font.family']='sans-serif'
plt.rcParams['axes.unicode_minus'] = False

classes = ['不录取','待考虑','录取']

confusion_matrix = model_LR.pred_table()

plt.figure(figsize=(6, 4), dpi=90)

plt.imshow(confusion_matrix, interpolation='nearest', cmap=plt.cm.Oranges)
plt.title('混淆矩阵')
plt.colorbar()

tick_marks = np.arange(3)
plt.xticks(tick_marks, classes)
plt.yticks(tick_marks, classes, rotation=90,verticalalignment='center')

for x in range(len(confusion_matrix)):
    for y in range(len(confusion_matrix)):
        plt.annotate(confusion_matrix[y,x], xy = (x,y), horizontalalignment = 'center', verticalalignment = 'center')

plt.ylabel('Ground Truth')
plt.xlabel('Prediction')
plt.tight_layout()

多分类逻辑回归 MNLogit python
(此例子的结果准确性确实比较差,主要是记录分享代码和流程,准确性还请忽略)

筛选协变量

根据AIC准则,使用前进后退法对协变量进行筛选,得到最优模型。(zhihu大佬的代码,亲测可用,我修改成了MNLogit,多加了几个输出结果)


def stepwise_select_MNLogit(data,label,cols_all,method='forward'):
    '''
    args:
        data:数据源,df
        label:标签,str
        cols_all:逐步回归的全部字段
        methrod:方法,forward:向前,backward:向后,both:双向
    return:
        select_col:最终保留的字段列表,list
        summary:模型参数
        AIC:aic
    '''
    import statsmodels.api as sm

    if method == 'forward':
        add_col = []
        AIC_None_value = np.inf
        while cols_all:

            AIC = {}
            for col in cols_all:
                print(col)
                X_col = add_col.copy()
                X_col.append(col)
                X = sm.add_constant(data[X_col])
                y = data[label]
                LR = sm.MNLogit(y, X).fit()
                AIC[col] = LR.aic
            AIC_min_value = min(AIC.values())
            AIC_min_key = min(AIC,key=AIC.get)

            if AIC_min_value < AIC_None_value:
                cols_all.remove(AIC_min_key)
                add_col.append(AIC_min_key)
                AIC_None_value = AIC_min_value
            else:
                break
        select_col = add_col

    elif method == 'backward':
        p = True

        X_col = cols_all.copy()
        X = sm.add_constant(data[X_col])
        y = data[label]
        LR = sm.MNLogit(y, X).fit()
        AIC_None_value = LR.aic
        while p:

            AIC = {}
            for col in cols_all:
                print(col)
                X_col = [i for i in cols_all if i!=col]
                X = sm.add_constant(data[X_col])
                LR = sm.MNLogit(y, X).fit()
                AIC[col] = LR.aic
            AIC_min_value = min(AIC.values())
            AIC_min_key = min(AIC, key=AIC.get)

            if AIC_min_value < AIC_None_value:
                cols_all.remove(AIC_min_key)
                AIC_None_value = AIC_min_value
                p = True
            else:
                break
        select_col = cols_all

    elif method == 'both':
        p = True
        add_col = []

        X_col = cols_all.copy()
        X = sm.add_constant(data[X_col])
        y = data[label]
        LR = sm.MNLogit(y, X).fit()
        AIC_None_value = LR.aic
        while p:

            AIC={}
            for col in cols_all:
                print(col)
                X_col = [i for i in cols_all if i!=col]
                X = sm.add_constant(data[X_col])
                LR = sm.MNLogit(y, X).fit()
                AIC[col] = LR.aic
            AIC_min_value = min(AIC.values())
            AIC_min_key = min(AIC, key=AIC.get)
            if len(add_col) == 0:
                if AIC_min_value < AIC_None_value:
                    cols_all.remove(AIC_min_key)
                    add_col.append(AIC_min_key)
                    AIC_None_value = AIC_min_value
                    p = True
                else:
                    break
            else:

                for col in add_col:
                    print(col)
                    X_col = cols_all.copy()
                    X_col.append(col)
                    X = sm.add_constant(data[X_col])
                    LR = sm.MNLogit(y, X).fit()
                    AIC[col] = LR.aic
                AIC_min_value = min(AIC.values())
                AIC_min_key = min(AIC, key=AIC.get)
                if AIC_min_value < AIC_None_value:

                    if AIC_min_key in add_col:
                        cols_all.append(AIC_min_key)
                        add_col = list(set(add_col)-set(AIC_min_key))
                        p = True
                    else:
                        cols_all.remove(AIC_min_key)
                        add_col.append(AIC_min_key)
                        p = True
                    AIC_None_value = AIC_min_value
                else:
                    break
        select_col = cols_all

    X = sm.add_constant(data[select_col])
    LR = sm.MNLogit(y, X).fit()
    summary = LR.summary()
    summary2 = LR.summary2()
    AIC = LR.aic
    return select_col,summary,summary2,AIC,LR

逐步回归

cols_all = X.drop(['intercept'],axis=1,inplace=False).columns
cols_all = list(cols_all)
cols ,summary ,summary2 ,AIC, model = stepwise_select_MNLogit(data,'admit',cols_all,method='both')

查看结果

summary2()

多分类逻辑回归 MNLogit python
可以看到,age变量被剔除。(很合理,这列年龄是我自己使用随机数添加的,就是为了使用一下逐步回归法hhh)

部分代码实在不记得或找不到是从哪里偷师来的了,漏加引用实属抱歉。

Original: https://blog.csdn.net/weixin_45272208/article/details/126386412
Author: CRLBJ
Title: 多分类逻辑回归 MNLogit python

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/662916/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球