本節介紹
邏輯斯迴歸模型(Logistic regression),
過度適合(overfitting)與
正規化(regularization)。邏輯斯迴歸模型(Logistic regression)能處裡線性和二元分類的問題,要注意的是這裡所要說的邏輯斯迴歸模型(Logistic regression)是分類模型而無關於"迴歸"。
邏輯斯迴歸模型(Logistic regression):
首先來看一下邏輯斯迴歸模型(Logistic regression),如下圖跟前一章所介紹的
適應線性神經元模型類似,但是其所使用的啟動函數不同,成本函數也不同。
<圖一>邏輯斯迴歸模型(Logistic regression)
邏輯斯迴歸模型(Logistic regression)使用啟動函數稱之為sigmoid函數:
z為淨輸入:
其sigmoid函數圖型看似為S形狀。淨輸入z當作sigmoid函數的輸入後,會被轉成0.0~1.0的實數分布,如果截距給定0.5,那我們可以利用二元量化器,如果Φ(z)>=0.5 便分為正類,反之分為負類。sigmoid函數的輸出可以解釋為"某特定樣本,給定特徵x與加權w,當參數時屬於類別1的機率":
例如以之前的鳶尾花樣本為分類範例,如果計算出某特定樣本Φ(z)=0.8,而分類1假設為樣本Iris
-Versicolor,那麼意味著該特定樣本有80%的機率是屬於Iris-Versicolor分類:而屬於另一樣本(假設為Iris-Setosa)的機率為20%。可以底下公式算出:
接著,便可以使用一量化器,將預測機率轉換成二元分類的結果:
其等價於如下,z為淨輸入:
原因是當輸入z為趨近於正無限大,那麼Φ(z)輸出會趨近於1.0,輸入z為趨近於負無限大,那麼Φ(z)輸出會趨近於0.0。
<圖二>sigmoid函數
邏輯斯迴歸模型(Logistic regression)的成本函數:
為了解釋如何推導邏輯斯迴歸模型的成本函數,我們先定義"概似"L(likelihood),我們期望L最大,也就是我們期望"某特定樣本屬於某一特定分類的機率最大"。假設我們數據集中的各個樣本是互相獨立的,那麼計算L的公式如下:
要對上述公式求取最大化,可以對這個公式套用自然對數函數,這就是所謂的"對數概似函數"(log-likelihood function):
現在可以使用最佳化演算法,如梯度上升法來最大化這個概似函數,在此我們也可以把這個概似函數寫為成本函數,也就是取負,讓函數開口變上,那麼就可以反過來使用之前所說的梯度下降法(GD)來最小化這個成本函數J(w):
為了更理解這個成本函數,讓我們來看看單一實例的成本如何計算:
觀上述方程式如果y=0,那麼第一項為0,如果y=1,那麼第二項為0,如下所示:
我們以下圖示來表示:
可以看到如果正確的預測一個樣本屬於1這類,那麼成本會接近0(實心線),同樣的,如果
正確的預測樣本y=0這類(虛線),其成本也是接近0。反之,如果分類錯誤,成本會變無窮大。
我們視一個極大的成本,當做是分類錯誤。
<圖三>單一樣本實例,對不同Φ(z)值的分類"成本函數"J
以正規化(regularization)處裡高度適合(overfitting)現象:
高度適合(overfitting )是機器學習常見的一種現象,意旨一個模型在對"訓練數據集"時有很好的效能,但是面對"未知的數據集"或是"測試數據集"時,卻效能不佳。如果該模型有高度適合(overfitting )現象,也代表著有高變異性(high variance)其產生的原因可能是使用"過多的特徵",而相反的低度適合(underfitting)則代表有著高偏誤(high bias),其模型在訓練樣本時無法訓練出適合的模式,而在面對"未知的數據"時,通常也不會有好的效能。
變異數(variance)可以測量該模型對特定樣本,預測能力的一致性或是變異性,也就是說該模型對訓練數據的隨機性,是否反應良好。
偏誤(bias)一般而言是測量預測正確值的偏離,在於描述不是由隨機性所產生的系統誤差
可以用下圖來理解這些狀況:
若想要在"偏誤(bias)-變異數(variance)"之間找到一個平衡,其中一個方法是透過
正規化(regularization),來調整模型的複雜度。正規化(regularization)防止高度適合(overfitting )的觀念是
加入更多的偏誤(bias)來懲罰極端的參數權重,最常見的是"L2正規化",也被稱為L2收縮或加權衰減,其表示式為:
λ稱之為正規化參數(regularization parameter)
要運用正規化,只需要將正規項加入成本函數,用它來縮小邏輯斯迴歸的加權,如下:
藉由
正規化參數(regularization parameter)λ,我們可以讓加權保持很小。另一方面如果加大正規化參數(regularization parameter)λ,則可以增加正規化的強度。
在Scikit-learn 裡LogisticRegression類別的參數C,命名方式來自於SVM支援向量機,C定義為正規化參數(regularization parameter)λ的倒數:
我們可以重寫邏輯斯迴歸的正規化成本函數:
因此,降低反正規化參數(regularization parameter)C,也就是意謂著增加正規化參數(regularization parameter)λ的值,進而增加正規化強度,底下我們可以藉由繪製L2正規化兩個加權系數的變動路徑看出:
底下結果顯示將C變小,權重係數就會縮收,因此增加正規化強度。
<圖四_範例程式1>反正規化參數(regularization parameter)C 對權重係數調整的影響
<範例程式1:>
from sklearn import datasets
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
import warnings,math
from sklearn.linear_model import LogisticRegression
#load iris data
iris = datasets.load_iris()
X = iris.data[:, [2, 3]]
y = iris.target
#分成30%測試資料,70% 訓練資料
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=0)
#標準化資料
sc = StandardScaler()
sc.fit(X_train)
X_train_std = sc.transform(X_train)
X_test_std = sc.transform(X_test)
print("X_train_std.shape",X_train_std.shape)
print("X_test_std.shape",X_test_std.shape)
weights, params = [], []
for c in np.arange(-5, 5):
CC=math.pow(10,c)
lr = LogisticRegression(C=CC, random_state=0)
lr.fit(X_train_std, y_train)
weights.append(lr.coef_[1])
params.append(CC)
weights = np.array(weights)
plt.plot(params, weights[:, 0],
label='petal length')
plt.plot(params, weights[:, 1], linestyle='--',
label='petal width')
plt.ylabel('weight coefficient')
plt.xlabel('C')
plt.legend(loc='upper left')
plt.xscale('log')
plt.show()
<圖五>以邏輯斯迴歸模型(Logistic regression)分類鳶尾花數據
<邏輯斯迴歸模型(Logistic regression):>
from numpy.random import seed
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import ListedColormap
from sklearn.datasets import load_iris
def plot_decision_regions(X, y, classifier, resolution=0.02):
# setup marker generator and color map
markers = ('s', 'x', 'o', '^', 'v')
colors = ('red', 'green', 'lightgreen', 'gray', 'cyan')
cmap = ListedColormap(colors[:len(np.unique(y))])
# plot the decision surface
x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1 #feature 1
x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1 #feature 2
xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
np.arange(x2_min, x2_max, resolution))
Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
Z = Z.reshape(xx1.shape)
plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap)
plt.xlim(xx1.min(), xx1.max())
plt.ylim(xx2.min(), xx2.max())
# plot class samples
for idx, cl in enumerate(np.unique(y)):
plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1],
alpha=0.8, c=cmap(idx),
marker=markers[idx], label=cl)
class LogisticRegressionGD(object):
"""Logistic regression classifier via gradient descent.
Parameters
------------
eta : float
Learning rate (between 0.0 and 1.0)
n_iter : int
Passes over the training dataset.
Attributes
-----------
w_ : 1d-array
Weights after fitting.
errors_ : list
Number of misclassifications in every epoch.
"""
def __init__(self, eta=0.01, n_iter=50):
self.eta = eta
self.n_iter = n_iter
def fit(self, X, y):
""" Fit training data.
Parameters
----------
X : {array-like}, shape = [n_samples, n_features]
Training vectors, where n_samples is the number of samples and
n_features is the number of features.
y : array-like, shape = [n_samples]
Target values.
Returns
-------
self : object
"""
self.w_ = np.zeros(1 + X.shape[1])
self.cost_ = []
for i in range(self.n_iter):
net_input = self.net_input(X)
output = self.activation(X)
errors = (y - output)
self.w_[1:] += self.eta * X.T.dot(errors)
self.w_[0] += self.eta * errors.sum()
# note that we compute the logistic `cost` now
# instead of the sum of squared errors cost
cost = -y.dot(np.log(output)) - ((1 - y).dot(np.log(1 - output)))
self.cost_.append(cost)
return self
def net_input(self, X):
"""Calculate net input"""
return np.dot(X, self.w_[1:]) + self.w_[0]
def predict(self, X):
"""Return class label after unit step"""
# We use the more common convention for logistic
# regression returning class labels 0 and 1
# instead of -1 and 1. Also, the threshold then
# changes from 0.0 to 0.5
return np.where(self.activation(X) >= 0.5, 1, 0)
# The Content of `activation` changed
# from linear (Adaline) to sigmoid.
# Note that this method is now returning the
# probability of the positive class
# also "predict_proba" in scikit-learn
def activation(self, X):
""" Compute sigmoid activation."""
z = self.net_input(X)
sigmoid = 1.0 / (1.0 + np.exp(-z))
return sigmoid
#直接使用scikit-learn載入Iris資料集
iris = load_iris()
#只取兩個特徵及兩類的數據
X, y = iris.data[:100, [0, 2]], iris.target[:100]
# standardize features
X_std = np.copy(X)
X_std[:, 0] = (X[:, 0] - X[:, 0].mean()) / X[:, 0].std()
X_std[:, 1] = (X[:, 1] - X[:, 1].mean()) / X[:, 1].std()
lr = LogisticRegressionGD(n_iter=25, eta=0.15)
lr.fit(X_std, y)
plt.subplot(211)
plot_decision_regions(X_std, y, classifier=lr)
plt.title('Logistic Regression - Gradient Descent')
plt.xlabel('sepal length [standardized]')
plt.ylabel('sepal width [standardized]')
plt.legend(loc='upper left')
plt.subplot(212)
plt.plot(range(1, len(lr.cost_) + 1), lr.cost_, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Logistic Cost')
plt.tight_layout()
plt.show()
<參考資料>書名:Python機器學習,作者:Sebastian Raschka
加入阿布拉機的3D列印與機器人的FB專頁
https://www.facebook.com/arbu00/
<其他相關文章>
人工神經網路(1)--使用Python實作perceptron(感知器)
人工神經網路(2)--使用Python實作後向傳遞神經網路演算法(Backprogation artificial neature network)
深度學習(1)-如何在windows安裝Theano +Keras +Tensorflow並使用GPU加速訓練神經網路
機器學習(1)--使用OPENCV KNN實作手寫辨識
機器學習(2)--使用OPENCV SVM實作手寫辨識
演算法(1)--蒙地卡羅法求圓周率及橢圓面積(Monte carlo)
機器學習(3)--適應線性神經元與梯度下降法(Adaline neuron and Gradient descent)
機器學習(4)--資料標準常態化與隨機梯度下降法( standardization & Stochastic Gradient descent)