分類變量回歸——Probit和Logit
爲什麼不是普通線性迴歸?
使用普通線性迴歸技術,我們必須確保迴歸技術對於研究問題的適用性,才能相信迴歸結果是可靠的。識別迴歸技術的適用性,我們需要對迴歸分析進行診斷,診斷內容是線性迴歸最基本的六個假設是否成立,即
- 誤差項是一個期望爲0的隨機變量;
- 對於解釋變量的所有觀測值,隨機誤差項有相同的方差;
- 隨機誤差項彼此不相關;
- 解釋變量是確定性變量,不是隨機變量,與隨機誤差項彼此之間相互獨立;
- 解釋變量之間不存在精確的(完全的)線性關係,即解釋變量的樣本觀測值矩陣是滿秩矩陣;
- 隨機誤差項服從正態分佈。
那麼,當我們遇到被解釋變量爲分類變量這一特殊的情境時,如果能夠使用普通線性迴歸技術,就必須要滿足以上所提到的六個基本假設,我們來進行一個簡單的模擬。
我使用一個火箭發射成功與否的數據集來進行接下來的測試,首先我們讀取數據集。
import numpy as np
import pandas as pd
data = pd.read_csv("challenger.csv")
data.drop(columns=['Unnamed: 0'], inplace=True)
數據集如下:
num_at_risk distress launch_temp leak_check_pressure order
0 6 1 70 50 2
1 6 0 69 50 3
2 6 0 68 50 4
3 6 0 67 50 5
4 6 0 72 50 6
5 6 0 73 100 7
6 6 0 70 100 8
7 6 1 57 200 9
8 6 1 63 200 10
9 6 1 70 200 11
10 6 0 78 200 12
11 6 0 67 200 13
13 6 0 67 200 15
14 6 0 75 200 16
15 6 0 70 200 17
16 6 0 81 200 18
17 6 0 76 200 19
18 6 0 79 200 20
19 6 0 75 200 21
20 6 0 76 200 22
21 6 1 58 200 23
我們使用statsmodels提供的線性迴歸分析API來完成迴歸,然後進行簡單的可視化
import statsmodels.formula.api as smf
model = smf.ols('distress ~ num_at_risk + launch_temp + leak_check_pressure + order', data = data)
result = model.fit()
# result.summary()
import matplotlib.pyplot as plt
plt.figure(figsize = (10, 8), dpi = 80)
plt.scatter(result.fittedvalues, result.resid)
plt.plot([-0.3, 1.3], [0, 0], color = "black")
plt.show()
通過觀察圖像,我們不難看出,在使用普通線性迴歸技術來完成離散型變量回歸時,上文提到的第一個和第二個假設都被打破了,即
- 誤差項期望值不爲0;
- 隨機誤差項方差隨解釋變量觀測值的變化而變化。
因此,使用普通線性迴歸似乎在分類變量回歸的情景下就不再是一個很合適的方法了,因此我們使用Link函數構建了適用於分類變量的迴歸技術。
什麼是Link函數?
考慮一個最簡單的二分類問題,我們如果使用普通線性迴歸技術來進行一個二分類問題的迴歸,結果就會像上面那張圖一樣,得到的預測值不是類別標籤,而是一條線上任意的一個點,這顯然不是我們想要的結果。
爲了解決這個問題,我們引入了Link function的概念。什麼是Link finction呢?其實它就是一個對於普通線性迴歸結果的非線性變化,目的是將現象迴歸的結果縮放成0到1之間的一個值。如果有了這個變化,迴歸後的擬合值就有了意義,因爲這個數可以被視作分至指定類別的概率,可以支撐我們做類別預測的判斷了。
最流行的Link函數有兩種,一個是Probit,一個是Logit(即我們常說的Logistic迴歸),它們的函數表達式分別是:
對應的圖像爲:
其實兩者差距不大,Probit相對而言更加陡峭,Logit的轉化則更柔和一些。
如何實現(statsmodels&sklearn)?
接下來我介紹兩種在Python中進行分類變量回歸的技術,先引入必要的工具和數據
import pandas as pd
import numpy as np
from sklearn import svm
from sklearn.metrics import roc_curve, auc
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import label_binarize
from sklearn.metrics import confusion_matrix, classification_report
from sklearn.neural_network import MLPClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
import statsmodels.api as sm
from statsmodels.discrete.discrete_model import Logit, Probit, MNLogit
from pylab import mpl
import plotly.graph_objects as go
import warnings
import matplotlib as mpl
warnings.filterwarnings('ignore')
#設置風格、尺度
sns.set_style('whitegrid')
sns.set_context('paper')
wine = pd.read_csv('winequality-red.csv')
數據可在下方鏈接下載:
紅酒質量數據集下載
statsmodels(統計學分析場景推薦)
先把問題簡化爲一個二分類問題
X = wine.iloc[:, :-1]
Y = wine['quality']
binary_Y = []
for i in range(len(Y)):
if Y[i] <=5:
binary_Y.append(0)
else:
binary_Y.append(1)
Probit
probit_model = Probit(binary_Y, sm.add_constant(X))
result = probit_model.fit()
result.summary()
Logit
logist_model = Logit(binary_Y, sm.add_constant(X))
result = logist_model.fit()
result.summary()
MNLogit(Multinormal)
MNLogit就是當分類變量非二分類,而是多分類時的Logistic迴歸方法,具體實現很簡單。(輸出表很長,就不展示了)
mnLogit_model = MNLogit(Y, sm.add_constant(X))
result = mnLogit_model.fit()
result.summary()
sklearn(機器學習場景推薦)
sklearn也封裝有Logistic迴歸的方法,也可以實現statsmodels類似的功能,但是可視化表格卻非常的差勁,因此在統計學分析(Inference)裏面我們一般不太使用sklearn。但是如果把迴歸技術用於預測目的的話,我們也是可以選擇sklearn的。以下展示使用sklearn進行多變量Logistic迴歸的模型訓練效果。
logit_model = LogisticRegression(multi_class='multinomial', penalty = 'l2')
logit_model.fit(X, Y)
predict = logit_model.predict(X)
y_one_hot = label_binarize(Y, np.arange(3, 9))
predict_proba = logit_model.predict_proba(X)
fpr, tpr, threshold = roc_curve(y_one_hot.ravel(), predict_proba.ravel()) ###計算真正率和假正率
roc_auc = auc(fpr,tpr) ###計算auc的值
mpl.rcParams['font.family'] = 'sans-serif'
mpl.rcParams['font.sans-serif'] = 'NSimSun,Times New Roman'
font = {'family': 'sans-serif',
'color': 'k',
'weight': 'bold',
'size': 20,}
plt.figure()
plt.figure(figsize=(12,10), dpi=80)
plt.plot(fpr, tpr, color='darkorange',
lw=5, label='ROC curve (area = %0.3f)' % roc_auc) ###假正率爲橫座標,真正率爲縱座標做曲線
plt.plot([0, 1], [0, 1], color='navy', lw=3, linestyle='--')
plt.xlim([-0.01, 1.01])
plt.ylim([-0.01, 1.01])
plt.xticks(fontsize=12)
plt.yticks(fontsize=12)
plt.xlabel('False Positive Rate', fontsize=15)
plt.ylabel('True Positive Rate', fontsize=15)
plt.title('Sklearn Calculated ROC Curve', fontsize=18)
plt.legend(loc="lower right", fontsize=15)
plt.show()