1. 程式人生 > >機器學習邏輯迴歸模型總結——從原理到sklearn實踐

機器學習邏輯迴歸模型總結——從原理到sklearn實踐

0x00 基本原理

邏輯迴歸演算法,從名字上看似乎是個迴歸問題,但實際上邏輯迴歸是個典型的分類演算法。
對於分類問題,一般都是一些離散變數,且y的取值如下:

y{0,1,2,3,...,n},顯然不能使用線性迴歸擬合。
以二元分類問題開始討論,y的取值為“類別1,類別2”,為了表示清楚,這裡使用0和1來表示二元分類中的兩個類別,即y的取值為:y{0,1}
和線性迴歸問題一樣,我們規定假設函式為:hθ(x),設定取值範圍:0hθ(x)1,因為我們希望演算法得出的結果取值非0即1,所以還要設定一個閾值,如果得出的概率大於這個閾值,則假設函式輸出1,否則輸出0。
在邏輯迴歸中,實際上對於假設函式,使用了一種邏輯函式的概念,函式如下:
h
θ
(x)=11+eθTx

稱為S型函式,或者邏輯函式。取值範圍為(0,1),符合我們上面對假設函式的要求。通常,設定閾值為0.5,如果訓練樣本輸入到假設函式中,得到的值大於0.5,則認為分類為1,否則分類為0:
P(y=0|x;θ)+P(y=1|x;θ)=1
相應的,我們的損失函式(Cost Function)為:
J(θ)=1mi=1m12(hθ(x(i))y(i))2
如果這裡計算折損的形式還是和線性迴歸一樣平方損失函式:mi=112(hθ(x(i))y(i))2,實際上,在求minJ的時候,對於J函式,我們很可能得出的不是凸函式的形式,這樣再使用梯度下降演算法時,會陷入至區域性最優解中,很難找到全域性最優解。
所以在計算折損值的時候,邏輯迴歸中使用了對數損失函式來獲得一個凸函式的J,整理得到的最終損失函式形式如下,其中省略了若干數學推導:

我們再次使用梯度下降演算法來求出最優的引數向量,梯度下降在邏輯迴歸中表現如下:

可能有人發現,這不和線性擬合問題中的梯度下降公式一樣嗎?實際上,由於邏輯迴歸模型中採用了邏輯函式來表示假設函式,所以這兩種模型中的梯度下降表達式是完全不同的兩回事兒。
有了梯度下降演算法,我們就可以使用訓練集來求出最優的引數向量。邏輯迴歸中,為了消除過度擬合問題,有正則化方法,這裡就不再贅述。

0x01 演算法實現

根據Andrew Ng所提供的資料,我們依舊選擇Octave來實現邏輯迴歸演算法。
首先是sigmoid函式(邏輯函式)的表達:

function g = sigmoid(z)
g = zeros
(size(z)); g = 1 ./ (1+exp(-z)); end

Cost Function的實現:

function [J, grad] = costFunction(theta, X, y)
% 初始化
m = length(y);
J = 0;
grad = zeros(size(theta));

% 損失函式的計算
temp = sigmoid(X*theta);
temp = temp(:,size(temp, 2));
J = (1/m) * sum((-y.*log(temp))-((1-y).*log(1-temp))) ;

% 損失函式的導數計算
for i=1:size(theta,1),
  grad(i) = (1/m) * sum((temp - y).*X(:,i));
end;
end

由於資料中所給的不是直接使用梯度下降演算法,而是使用了Octave中的優化方法來求最優引數向量,所以只需要返回損失函式J和各個損失函式的導數grad。實際上,如果改成直接使用梯度下降的話,只需要在求grad的過程中,同步更新我們各個引數即可。
預測函式如下,這裡一般選擇閾值為0.5,所以大於0.5的假設函式返回值,我們就判斷類別為1。

function p = predict(theta, X)
m = size(X, 1); 
p = zeros(m, 1);

% 計算類別,使用p向量返回
for i=1:m,
  prop = sigmoid(X(i,:)*theta) ;
  if prop >= 0.5,
    p(i) = 1;
  end;
end;
end;

0x02 演算法執行

執行演算法,可以看到視覺化的決策邊界:

0x03 sklearn庫實踐

清楚了邏輯迴歸模型的原理,我們使用python進行機器學習演練,使用sklearn機器學習庫,可以很方便地進行實踐。
資料集為學生的兩次考試成績以及是否通過大學申請,我們用邏輯迴歸進行分類,以後給出一個樣本,輸出成功通過大學申請的概率。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.cross_validation import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report 
from sklearn.metrics import precision_recall_curve, roc_curve, auc 

data = pd.read_csv('ex2data1.txt', sep=',', \
    skiprows=[2], names=['score1','score2','result'])
score_data = data.loc[:,['score1','score2']]
result_data = data.result

p = 0
for i in xrange(10):
    x_train, x_test, y_train, y_test = \
        train_test_split(score_data, result_data, test_size = 0.2)
    model = LogisticRegression(C=1e9)
    model.fit(x_train, y_train)
    predict_y = model.predict(x_test)
    p += np.mean(predict_y == y_test)

# 繪製圖像
pos_data = data[data.result == 1].loc[:,['score1','score2']]
neg_data = data[data.result == 0].loc[:,['score1','score2']]

h = 0.02
x_min, x_max = score_data.loc[:, ['score1']].min() - .5, score_data.loc[:, ['score1']].max() + .5
y_min, y_max = score_data.loc[:, ['score2']].min() - .5, score_data.loc[:, ['score2']].max() + .5
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])

# 繪製邊界和散點
Z = Z.reshape(xx.shape)
plt.pcolormesh(xx, yy, Z, cmap=plt.cm.Paired)
plt.scatter(x=pos_data.score1, y=pos_data.score2, color='black', marker='o')
plt.scatter(x=neg_data.score1, y=neg_data.score2, color='red', marker='*')

plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.show()

# 模型表現
answer = model.predict_proba(x_test)[:,1]  
precision, recall, thresholds = precision_recall_curve(y_test, answer)      
report = answer > 0.5  
print(classification_report(y_test, report, target_names = ['neg', 'pos']))  
print("average precision:", p/100)  

執行結果如下:

畫出了決策邊界之後,就可以看到我們最後的分類結果。
當然也可以使用precision_call_curve方法自動計算召回率精度等資料:

               precision    recall  f1-score   support

        neg       0.88      0.88      0.88         8
        pos       0.92      0.92      0.92        12

avg / total       0.90      0.90      0.90        20
('average precision:', 0.089999999999999997)

精度達到了90%,模型效果還不錯。

0x04 總結

邏輯迴歸模型實際上是一個典型的監督學習分類演算法,配合sklearn庫可以很方便的進行邏輯迴歸處理。前提是要真正理解邏輯迴歸模型的原理和推導過程。
實戰中,機器學習和資訊保安結合越來越緊密了,所以這也是我為啥開始學習機器學習的原因,就邏輯迴歸而言,完全可以用在防爬檢測,掃描器檢測,惡意URL提取的應用上,實戰的前提是瞭解原理:)