邏輯回歸的原理與實踐
1.學習目標
- 了解邏輯回歸的理論
- 掌握邏輯回歸的sklearn函數調用使用並將其運用到鳶尾花數據集預測
2.邏輯回歸的應用
邏輯回歸模型廣泛用於各個領域,包括機器學習,大多數醫學領域和社會科學。例如,最初由Boyd 等人開發的創傷和損傷嚴重度評分(TRISS)被廣泛用於預測受傷患者的死亡率,使用邏輯回歸 基於觀察到的患者特徵(年齡,性別,體重指數,各種血液檢查的結果等)分析預測發生特定疾病(例如糖尿病,冠心病)的風險。邏輯回歸模型也用於預測在給定的過程中,系統或產品的故障的可能性。還用於市場營銷應用程式,例如預測客戶購買產品或中止訂購的傾向等。在經濟學中它可以用來預測一個人選擇進入勞動力市場的可能性,而商業應用則可以用來預測房主拖欠抵押貸款的可能性。
邏輯回歸模型現在同樣是很多分類演算法的基礎組件,比如 分類任務中基於GBDT演算法+LR邏輯回歸實現的信用卡交易反欺詐,CTR(點擊通過率)預估等,其好處在於輸出值自然地落在0到1之間,並且有概率意義。模型清晰,有對應的概率學理論基礎。它擬合出來的參數就代表了每一個特徵(feature)對結果的影響。也是一個理解數據的好工具。但同時由於其本質上是一個線性的分類器,所以不能應對較為複雜的數據情況。很多時候我們也會拿邏輯回歸模型去做一些任務嘗試的基準線。
3.邏輯回歸原理簡介
邏輯回歸,該模型的輸出變數範圍始終在 0 和 1 之間。
邏輯回歸模型的假設是:
其中: X 代表特徵向量 g 代表邏輯函數(logistic function)是一個常用的邏輯函數為 S 形函數(Sigmoid function),公式為:
該函數的影像為:
的作用是,對於給定的輸入變數,根據選擇的參數計算輸出變數=1 的可能性(estimated probablity)即
例如,如果對於給定的?,通過已經確定的參數計算得出,則表示有 70%的幾率?為正向類,相應地?為負向類的幾率為 1-0.7=0.3。
在邏輯回歸中,我們預測:
當時,預測 y = 1。
當時,預測 y = 0 。
根據上面繪製出的 Sigmoid函數 影像,我們知道當
z = 0 時 g(z) = 0.5
z > 0 時 g(z) > 0.5
z < 0 時 g(z) < 0.5
又 ,即:
時,預測 y = 1
時,預測 y = 0
因為各個觀測樣本之間相互獨立,那麼它們的聯合分布為各邊緣分布的乘積。得到似然函數為
接下來我們的目的就是求解似然函數的最大值,對上式兩邊取對數,得到
所以,我們就可以構造Loss Functionl如下式
加上-1/m,求解的最小值,也就是求解似然函數的最大值,主要是為了方便後面的梯度下降法。所以使用梯度下降法求解,其更新函數為
而
4.Demo實踐
- Step1:庫函數導入
## 基礎函數庫
import numpy as np
## 導入畫圖庫
import matplotlib.pyplot as plt
import seaborn as sns
## 導入邏輯回歸模型函數
from sklearn.linear_model import LogisticRegression
- Step2:訓練模型
##Demo演示LogisticRegression分類
## 構造數據集
x_fearures = np.array([[-1, -2], [-2, -1], [-3, -2], [1, 3], [2, 1], [3, 2]])
y_label = np.array([0, 0, 0, 1, 1, 1])
## 調用邏輯回歸模型
lr_clf = LogisticRegression()
## 用邏輯回歸模型擬合構造的數據集
lr_clf = lr_clf.fit(x_fearures, y_label) #其擬合方程為 y=w0+w1*x1+w2*x2
- Step3:模型參數查看
##查看其對應模型的w
print('the weight of Logistic Regression:', lr_clf.coef_)
##查看其對應模型的w0
print('the intercept(w0) of Logistic Regression:', lr_clf.intercept_)
##the weight of Logistic Regression:[[0.73462087 0.6947908]]
##the intercept(w0) of Logistic Regression:[-0.03643213]
- Step4:數據和模型可視化
## 可視化構造的數據樣本點
plt.figure()
plt.scatter(x_fearures[:, 0], x_fearures[:, 1], c=y_label, s=50, cmap='viridis')
plt.title('Dataset')
plt.show()
# 可視化決策邊界
plt.figure()
plt.scatter(x_fearures[:, 0], x_fearures[:, 1], c=y_label, s=50, cmap='viridis')
plt.title('Dataset')
nx, ny = 200, 100
x_min, x_max = plt.xlim()
y_min, y_max = plt.ylim()
x_grid, y_grid = np.meshgrid(np.linspace(x_min, x_max, nx), np.linspace(y_min, y_max, ny))
z_proba = lr_clf.predict_proba(np.c_[x_grid.ravel(), y_grid.ravel()])
z_proba = z_proba[:, 1].reshape(x_grid.shape)
plt.contour(x_grid, y_grid, z_proba, [0.5], linewidths=2., colors='blue')
plt.show()
### 可視化預測新樣本
plt.figure()
## new point 1
x_fearures_new1 = np.array([[0, -1]])
plt.scatter(x_fearures_new1[:, 0], x_fearures_new1[:, 1], s=50, cmap='viridis')
plt.annotate(s='New point 1', xy=(0, -1), xytext=(-2, 0), color='blue', arrowprops=dict(arrowstyle='-|>', connectionstyle='arc3', color='red'))
## new point 2
x_fearures_new2 = np.array([[1, 2]])
plt.scatter(x_fearures_new2[:, 0], x_fearures_new2[:, 1], s=50, cmap='viridis')
plt.annotate(s='New point 2', xy=(1,2), xytext=(-1.5, 2.5), color='red', arrowprops=dict(arrowstyle='-|>', connectionstyle='arc3', color='red'))
## 訓練樣本
plt.scatter(x_fearures[:, 0], x_fearures[:, 1], c=y_label, s=50, cmap='viridis')
plt.title('Dataset')
# 可視化決策邊界
plt.contour(x_grid, y_grid, z_proba, [0.5], linewidths=2., colors='blue')
plt.show()
- Step5:模型預測
##在訓練集和測試集上分布利用訓練好的模型進行預測
y_label_new1_predict = lr_clf.predict(x_fearures_new1)
y_label_new2_predict = lr_clf.predict(x_fearures_new2)
print('The New point 1 predict class:\n', y_label_new1_predict)
print('The New point 2 predict class:\n', y_label_new2_predict)
##由於邏輯回歸模型是概率預測模型(前文介紹的p = p(y=1|x,\theta)),所有我們可以利用predict_proba函數預測其概率
y_label_new1_predict_proba = lr_clf.predict_proba(x_fearures_new1)
y_label_new2_predict_proba = lr_clf.predict_proba(x_fearures_new2)
print('The New point 1 predict Probability of each class:\n', y_label_new1_predict_proba)
print('The New point 2 predict Probability of each class:\n', y_label_new2_predict_proba)
##TheNewpoint1predictclass:
##[0]
##TheNewpoint2predictclass:
##[1]
##TheNewpoint1predictProbabilityofeachclass:
##[[0.695677240.30432276]]
##TheNewpoint2predictProbabilityofeachclass:
##[[0.119839360.88016064]]
可以發現訓練好的回歸模型將X_new1預測為了類別0(判別面左下側),X_new2預測為了類別1(判別面右上側)。其訓練得到的邏輯回歸模型的概率為0.5的判別面為上圖中藍色的線。
5.基於鳶尾花(iris)數據集的邏輯回歸分類實踐
在實踐的最開始,我們首先需要導入一些基礎的函數庫包括:numpy (Python進行科學計算的基礎軟體包),pandas(pandas是一種快速,強大,靈活且易於使用的開源數據分析和處理工具),matplotlib和seaborn繪圖。
- Step1:函數庫導入
## 基礎函數庫
import numpy as np
import pandas as pd
## 繪圖函數庫
import matplotlib.pyplot as plt
import seaborn as sns
本次我們選擇鳶花數據(iris)進行方法的嘗試訓練,該數據集一共包含5個變數,其中4個特徵變數,1個目標分類變數。共有150個樣本,目標變數為花的類別其都屬於鳶尾屬下的三個亞屬,分別是山鳶尾 (Iris-setosa),變色鳶尾(Iris-versicolor)和維吉尼亞鳶尾(Iris-virginica)。包含的三種鳶尾花的四個特徵,分別是花萼長度(cm)、花萼寬度(cm)、花瓣長度(cm)、花瓣寬度(cm),這些形態特徵在過去被用來識別物種。
變數 | 描述 |
---|---|
sepal length | 花萼長度(cm) |
sepal width | 花萼寬度(cm) |
petal length | 花瓣長度(cm) |
petal width | 花瓣寬度(cm) |
target | 鳶尾的三個亞屬類別,’setosa'(0), ‘versicolor'(1), ‘virginica'(2) |
- Step2:數據讀取/載入
##我們利用sklearn中自帶的iris數據作為數據載入,並利用Pandas轉化為DataFrame格式
from sklearn.datasets import load_iris
data = load_iris() #得到數據特徵
iris_target = data.target #得到數據對應的標籤
iris_features = pd.DataFrame(data=data.data, columns=data.feature_names) #利用Pandas轉化為DataFrame格式
- Step3:數據資訊簡單查看
##利用.info()查看數據的整體資訊
iris_features.info()
##<class'pandas.core.frame.DataFrame'>
##RangeIndex:150entries,0to149
##Datacolumns(total4columns):
###ColumnNon-NullCountDtype
##----------------------------
##0sepallength(cm)150non-nullfloat64
##1sepalwidth(cm)150non-nullfloat64
##2petallength(cm)150non-nullfloat64
##3petalwidth(cm)150non-nullfloat64
##dtypes:float64(4)
##memoryusage:4.8KB
##進行簡單的數據查看,我們可以利用.head()頭部.tail()尾部
iris_features.head()
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) |
---|---|---|---|
0 | 5.1 | 3.5 | 1.4 |
1 | 4.9 | 3.0 | 1.4 |
2 | 4.7 | 3.2 | 1.3 |
3 | 4.6 | 3.1 | 1.5 |
4 | 5.0 | 3.6 | 1.4 |
iris_features.tail()
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) |
---|---|---|---|
145 | 6.7 | 3.0 | 5.2 |
146 | 6.3 | 2.5 | 5.0 |
147 | 6.5 | 3.0 | 5.2 |
148 | 6.2 | 3.4 | 5.4 |
149 | 5.9 | 3.0 | 5.1 |
##其對應的類別標籤為,其中0,1,2分別代表'setosa','versicolor','virginica'三種不同花的類別
iris_target
##array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
##0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
##0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
##1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
##1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,
##2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
##2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2])
##利用value_counts函數查看每個類別數量
pd.Series(iris_target).value_counts()
##2 50
##1 50
##0 50
##dtype:int64
##對於特徵進行一些統計描述
iris_features.describe()
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) |
---|---|---|---|
count | 150.000000 | 150.000000 | 150.000000 |
mean | 5.843333 | 3.057333 | 3.758000 |
std | 0.828066 | 0.435866 | 1.765298 |
min | 4.300000 | 2.000000 | 1.000000 |
25% | 5.100000 | 2.800000 | 1.600000 |
50% | 5.800000 | 3.000000 | 4.350000 |
75% | 6.400000 | 3.300000 | 5.100000 |
max | 7.900000 | 4.400000 | 6.900000 |
從統計描述中我們可以看到不同數值特徵的變化範圍。
- **Step4:**可視化描述
## 合併標籤和特徵資訊
iris_all = iris_features.copy() ##進行淺拷貝,防止對於原始數據的修改
iris_all['target'] = iris_target
## 特徵與標籤組合的散點可視化
sns.pairplot(data=iris_all, diag_kind='hist', hue= 'target')
plt.show()
從上圖可以發現,在2D情況下不同的特徵組合對於不同類別的花的散點分布,以及大概的區分能力。
for col in iris_features.columns:
sns.boxplot(x='target', y=col, saturation=0.5, palette='pastel', data=iris_all)
plt.title(col)
plt.show()
利用箱型圖我們也可以得到不同類別在不同特徵上的分布差異情況。
# 選取其前三個特徵繪製三維散點圖
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
iris_all_class0 = iris_all[iris_all['target'] == 0].values
iris_all_class1 = iris_all[iris_all['target'] == 1].values
iris_all_class2 = iris_all[iris_all['target'] == 2].values
# 'setosa'(0), 'versicolor'(1), 'virginica'(2)
ax.scatter(iris_all_class0[:, 0], iris_all_class0[:, 1], iris_all_class0[:, 2], label='setosa')
ax.scatter(iris_all_class1[:, 0], iris_all_class1[:, 1], iris_all_class1[:, 2], label='versicolor')
ax.scatter(iris_all_class2[:, 0], iris_all_class2[:, 1], iris_all_class2[:, 2], label='virginica')
plt.legend()
plt.show()
- Step5:利用邏輯回歸模型在二分類上進行訓練和預測
##為了正確評估模型性能,將數據劃分為訓練集和測試集,並在訓練集上訓練模型,在測試集上驗證模型性能。
from sklearn.model_selection import train_test_split
##選擇其類別為0和1的樣本(不包括類別為2的樣本)
iris_features_part = iris_features.iloc[:100]
iris_target_part = iris_target[:100]
##測試集大小為20%,80%/20%分
x_train, x_test, y_train, y_test = train_test_split(iris_features_part, iris_target_part, test_size=0.2, random_state=2020)
##從sklearn中導入邏輯回歸模型
from sklearn.linear_model import LogisticRegression
##定義邏輯回歸模型
clf = LogisticRegression(random_state=0, solver='lbfgs')
##在訓練集上訓練邏輯回歸模型
clf.fit(x_train, y_train)
##查看其對應的w
print('the weight of Logistic Regression:', clf.coef_)
##查看其對應的w0
print('the intercept(w0) of Logistic Regression:', clf.intercept_)
##在訓練集和測試集上分別利用訓練好的模型進行預測
train_predict = clf.predict(x_train)
test_predict = clf.predict(x_test)
from sklearn import metrics
##利用accuracy(準確度)【預測正確的樣本數目佔總預測樣本數目的比例】評估模型效果
print('The accuracy of the Logistic Regression is:', metrics.accuracy_score(y_train, train_predict))
print('The accuracy of the Logistic Regression is:', metrics.accuracy_score(y_test, test_predict))
##查看混淆矩陣(預測值和真實值的各類情況統計矩陣)
confusion_matrix_result = metrics.confusion_matrix(test_predict, y_test)
print('The confusion matrix result:\n', confusion_matrix_result)
##利用熱力圖對於結果進行可視化
plt.figure(figsize=(8, 6))
sns.heatmap(confusion_matrix_result, annot=True, cmap='Blues')
plt.xlabel('Predictedlabels')
plt.ylabel('Truelabels')
plt.show()
##The accuracy of the Logistic Regressionis:1.0
##The accuracy of the Logistic Regressionis:1.0
##The confusion matrix result:
##[[9 0]
##[0 11]]
我們可以發現其準確度為1,代表所有的樣本都預測正確了。
- Step6:利用邏輯回歸模型在三分類(多分類)上進行訓練和預測
##測試集大小為20%,80%/20%分
x_train, x_test, y_train, y_test = train_test_split(iris_features, iris_target, test_size=0.2, random_state=2020)
##定義邏輯回歸模型
clf = LogisticRegression(random_state=0, solver='lbfgs')
##在訓練集上訓練邏輯回歸模型
clf.fit(x_train, y_train)
##查看其對應的w
print('the weight of Logistic Regression:\n', clf.coef_)
##查看其對應的w0
print('the intercept(w0) of Logistic Regression:\n', clf.intercept_)
##由於這個是3分類,所有我們這裡得到了三個邏輯回歸模型的參數,其三個邏輯回歸組合起來即可實現三分類
##在訓練集和測試集上分布利用訓練好的模型進行預測
train_predict = clf.predict(x_train)
test_predict = clf.predict(x_test)
##由於邏輯回歸模型是概率預測模型(前文介紹的p=p(y=1|x,\theta)),所有我們可以利用predict_proba函數預測其概率
train_predict_proba = clf.predict_proba(x_train)
test_predict_proba = clf.predict_proba(x_test)
print('The test predict Probability of each class:\n', test_predict_proba)
##其中第一列代表預測為0類的概率,第二列代表預測為1類的概率,第三列代表預測為2類的概率。
##利用accuracy(準確度)【預測正確的樣本數目佔總預測樣本數目的比例】評估模型效果
print('The accuracy of the Logistic Regression is:', metrics.accuracy_score(y_train, train_predict))
print('The accuracy of the Logistic Regression is:', metrics.accuracy_score(y_test, test_predict))
##查看混淆矩陣
confusion_matrix_result = metrics.confusion_matrix(test_predict, y_test)
print('The confusion matrix result:\n', confusion_matrix_result)
##利用熱力圖對於結果進行可視化
plt.figure(figsize=(8, 6))
sns.heatmap(confusion_matrix_result, annot=True, cmap='Blues')
plt.xlabel('Predicted labels')
plt.ylabel('True labels')
plt.show()
##The confusion matrix result:
##[[10 0 0]
##[0 8 2]
##[0 2 8]]