Logistic Regression(邏輯回歸)模型實現二分類和多分類


一、邏輯回歸

二、判定邊界

當將訓練集的樣本以其各個特征為坐標軸在圖中進行繪制時,通常可以找到某一個 判定邊界 去將樣本點進行分類。例如:

線性判定邊界:

 


這里寫圖片描述

 

非線性判定邊界:

 


這里寫圖片描述

 

三、二分類和sigmoid函數



sigmoid函數圖像如下:

 

這里寫圖片描述

 

四、損失函數

1. 定義

2. 極大似然估計

上面是一種求損失函數的方式,我們也可以換一種方式來求損失函數,即極大似然估計。用極大似然估計來作為損失函數

3. 正則化

五、最小化損失函數

這里寫圖片描述

同樣,上式中的a為學習率(下山步長)。將上式的偏導展開,可得:

非正則化的損失函數的偏導:

這里寫圖片描述

含正則化項的損失函數的偏導:

這里寫圖片描述

其中 λ 為正則化的強度。

同線性回歸般,可以通過學習率a對特征系數向量中的元素不斷進行迭代,直到元素值收斂到某一值即可,這時可以得到損失函數較小時的特征向量系數Θ。

六、從二分類過渡到多分類

在上面,我們主要使用邏輯回歸解決二分類的問題,那對於多分類的問題,也可以用邏輯回歸來解決?

1. one vs rest

由於概率函數 hΘ(X) 所表示的是樣本標記為某一類型的概率,但可以將一對一(二分類)擴展為一對多(one vs rest):

  1. 將類型class1看作正樣本,其他類型全部看作負樣本,然后我們就可以得到樣本標記類型為該類型的概率p1;

  2. 然后再將另外類型class2看作正樣本,其他類型全部看作負樣本,同理得到p2;

  3. 以此循環,我們可以得到該待預測樣本的標記類型分別為類型class i時的概率pi,最后我們取pi中最大的那個概率對應的樣本標記類型作為我們的待預測樣本類型。

2. softmax函數

使用softmax函數構造模型解決多分類問題。

softmax回歸分類器需要學習的函數為 : (這里下面的公式有問題,括號中的每一項應該都是以e為底的)

這里寫圖片描述

其中 k 個 類別的個數 ,這里寫圖片描述 和 這里寫圖片描述 為 第 i 個 類別對應的 權重向量 和 偏移標量。

其中 這里寫圖片描述 可看作樣本 X 的標簽 為 第 j 個 類別的概率,且有 這里寫圖片描述 。

與 logistic回歸 不同的是,softmax回歸分類模型會有多個的輸出,且輸出個數 與 類別個數 相等,輸出為樣本 X 為各個類別的概率 ,最后對樣本進行預測的類型為 概率最高 的那個類別。

我們需要通過學習得到 這里寫圖片描述 和 這里寫圖片描述 ,因此建立目標損失函數為:

這里寫圖片描述

上式的代價函數也稱作:對數似然代價函數。

在二分類的情況下,對數似然代價函數 可以轉化為 交叉熵代價函數。

其中 m 為訓練集樣本的個數,k 為 類別的個數,這里寫圖片描述 為示性函數,當 這里寫圖片描述 為真時,函數值為 1 ,否則為 0 ,即 樣本類別正確時,函數值才為 1 。

這里寫圖片描述

繼續展開:

這里寫圖片描述

通過 梯度下降法 最小化損失函數 和 鏈式偏導,使用 這里寫圖片描述 對 這里寫圖片描述 求偏導:

這里寫圖片描述

化簡可得:

這里寫圖片描述

再次化簡可有:

這里寫圖片描述

因此由 梯度下降法 進行迭代:

這里寫圖片描述

同理 通過梯度下降法最小化損失函數也可以得到 這里寫圖片描述 的最優值。

同邏輯回歸一樣,可以給損失函數加上正則化項。

3. 選擇的方案

當標簽類別之間是互斥時,適合選擇softmax回歸分類器 ;當標簽類別之間不完全互斥時,適合選擇建立多個獨立的logistic回歸分類器。

4. tensorflow代碼示例:

  • 使用softmax回歸對sklearn中的digit手寫數據進行分類
import tensorflow as tf
 
from sklearn.datasets import load_digits
 
import numpy as np
 
digits = load_digits()
 
X_data = digits.data.astype(np.float32)
 
Y_data = digits.target.reshape(-1,1).astype(np.float32)
 
print X_data.shape
 
print Y_data.shape
 
(1797, 64)
 
(1797, 1)
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
X_data = scaler.fit_transform(X_data)
from sklearn.preprocessing import OneHotEncoder
Y = OneHotEncoder().fit_transform(Y_data).todense() #one-hot編碼
Y
 
matrix([[ 1., 0., 0., ..., 0., 0., 0.],
 
[ 0., 1., 0., ..., 0., 0., 0.],
 
[ 0., 0., 1., ..., 0., 0., 0.],
 
...,
 
[ 0., 0., 0., ..., 0., 1., 0.],
 
[ 0., 0., 0., ..., 0., 0., 1.],
 
[ 0., 0., 0., ..., 0., 1., 0.]])
print Y.shape
 
(1797, 10)
 
1797
batch_size = 10 # 使用MBGD算法,設定batch_size為10
 
def generatebatch(X,Y,n_examples, batch_size):
 
for batch_i in range(n_examples // batch_size):
 
start = batch_i*batch_size
 
end = start + batch_size
 
batch_xs = X[start:end, :]
 
batch_ys = Y[start:end]
 
yield batch_xs, batch_ys # 生成每一個batch
 
tf.reset_default_graph()
 
tf_X = tf.placeholder(tf.float32,[None,64])
 
tf_Y = tf.placeholder(tf.float32,[None,10])
 
tf_W_L1 = tf.Variable(tf.zeros([64,10]))
 
tf_b_L1 = tf.Variable(tf.zeros([1,10]))
pred = tf.nn.softmax(tf.matmul(tf_X,tf_W_L1)+tf_b_L1)
 
loss = -tf.reduce_mean(tf_Y*tf.log(tf.clip_by_value(pred,1e-11,1.0)))
 
# 也可以直接使用tensorflow的版本:
 
# loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=tf_Y,logits=pred))
train_step = tf.train.GradientDescentOptimizer(0.2).minimize(loss)
 
y_pred = tf.arg_max(pred,1)
 
bool_pred = tf.equal(tf.arg_max(tf_Y,1),y_pred)
accuracy = tf.reduce_mean(tf.cast(bool_pred,tf.float32)) # 准確率
 
with tf.Session() as sess:
 
sess.run(tf.global_variables_initializer())
 
for epoch in range(2001): # 迭代2001個周期
 
for batch_xs,batch_ys in generatebatch(X_data,Y,Y.shape[0],batch_size): # 每個周期進行MBGD算法
 
sess.run(train_step,feed_dict={tf_X:batch_xs,tf_Y:batch_ys})
 
if(epoch%1000==0):
 
res = sess.run(accuracy,feed_dict={tf_X:X_data,tf_Y:Y})
 
print (epoch,res)
 
res_ypred = y_pred.eval(feed_dict={tf_X:X_data,tf_Y:Y}).flatten()
 
print res_ypred
 
(0, 0.86866999)
 
(1000, 0.99332219)
 
(2000, 0.99833053)
 
[0 1 2 ..., 8 9 8]
from sklearn.metrics import  accuracy_score
print accuracy_score(Y_data,res_ypred.reshape(-1,1))
0.998330550918

 

八、Logistic Loss的另一種表達

在上面的邏輯回歸的二分類問題中,我們令正樣本的標簽 y = 1 ,負樣本的標簽 y = 0。對於單個樣本來說,其損失函數Cost(hΘ(X),y)可以表示為:(hΘ(X)的值表示正樣本的概率)

這里寫圖片描述

若我們 令正樣本的標簽 y = 1 ,負樣本的標簽 y = -1,則有:

其中(待續)

七、代碼示例

  • 使用ovr多分類的邏輯回歸判斷鳶尾屬植物的類型
  •  
    from sklearn import datasets
     
     
     
    iris = datasets.load_iris() # 加載數據
     
    X = iris.data
     
    y = iris.target
     
    print X.shape
     
    print y.shape
     
    (150L, 4L)
     
    (150L,)
     
    from sklearn.model_selection import train_test_split
     
     
     
    #分隔訓練集和測試集
     
    X_train, X_test, y_train, y_test = train_test_split(X, y ,test_size = 1/3.,random_state = 8)
     
    from sklearn.preprocessing import PolynomialFeatures
     
     
     
    featurizer = PolynomialFeatures(degree=2) # 特征多項式化
     
    X_train = featurizer.fit_transform(X_train)
     
    X_test = featurizer.transform(X_test)
     
    from sklearn.preprocessing import StandardScaler # 對數據歸一化
     
     
     
    scaler = StandardScaler()
     
    X_std_train = scaler.fit_transform(X_train)
     
    X_std_test = scaler.transform(X_test)
     
    from sklearn.linear_model import LogisticRegression
     
    from sklearn.linear_model import SGDClassifier
     
     
     
    # penalty:正則化 l2/l1
     
    # C :正則化強度
     
    # multi_class:多分類時使用 ovr: one vs rest
     
    lor = LogisticRegression(penalty='l1',C=100,multi_class='ovr')
     
    lor.fit(X_std_train,y_train)
     
    print lor.score(X_std_test,y_test)
     
     
     
    sgdv = SGDClassifier(penalty='l1')
     
    sgdv.fit(X_std_train,y_train)
     
    print sgdv.score(X_std_test,y_test)
     
    0.94
     
    0.92
     
     
     
     
     
    LogisticRegression對參數的計算采用精確解析的方式,計算時間長但模型的性能高;SGDClassifier采用隨機梯度下降/上升算法估計模型的參數,計算時間短但模型的性能較低。
    使用Tensorflow實現線性邏輯回歸:
     
    from sklearn.datasets import make_classification
     
    import matplotlib.pyplot as plt
     
    import numpy as np
     
    X, y = make_classification(n_features=2, n_redundant=0, n_informative=2,
     
    n_clusters_per_class=1,random_state=78,n_samples=200)
     
    X = X.astype(np.float32)
     
    y = y.astype(np.float32)
     
    plt.scatter(X[:,0],X[:,1],c=y)
     
    plt.show()
    這里寫圖片描述
    
     
    from sklearn import preprocessing
     
    scaler = preprocessing.StandardScaler().fit(X)
     
    X = scaler.transform(X)
     
    print X.shape
    (200, 2)
     
    b = tf.Variable(tf.zeros([1,1]))
     
    W = tf.Variable(tf.zeros([2,1]))
     
    X_DATA = tf.placeholder(tf.float32,[None,2])
     
    Y = tf.placeholder(tf.float32,[None,1])
     
    H = 1 / (1 + tf.exp(-(tf.matmul(X_DATA, W) + b)))
     
    loss = tf.reduce_mean(- Y* tf.log(tf.clip_by_value(H,1e-11,1.0)) - (1 - Y) * tf.log(1 - tf.clip_by_value(H,1e-11,1.0)))
     
    # 也可以使用tensorflow的版本:
     
    #loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=tf_Y,logits=pred))
    optimizer = tf.train.GradientDescentOptimizer(0.1)
    train = optimizer.minimize(loss)
     
    init_vals = tf.global_variables_initializer()
     
    with tf.Session() as sess:
     
    sess.run(init_vals)
     
    for step in range(15501):
     
    sess.run(train,feed_dict={X_DATA:X,Y:y.reshape(-1,1)})
     
    if(step%5000==0):
     
    print(step,sess.run(W).flatten(),sess.run(b).flatten())
     
    w1 = sess.run(W).flatten()
     
    b1 = sess.run(b).flatten()
     
    (0, array([ 0.04289575, 0.04343094], dtype=float32), array([-0.0005], dtype=float32))
     
    (5000, array([ 3.44468737, 3.617342 ], dtype=float32), array([-1.10549724], dtype=float32))
     
    (10000, array([ 3.46032 , 4.07498837], dtype=float32), array([-1.60735476], dtype=float32))
     
    (15000, array([ 3.45384622, 4.39454508], dtype=float32), array([-1.95797122], dtype=float32))
    print (w1,b1)
    (array([ 3.45412397,  4.42197132], dtype=float32), array([-1.9879719], dtype=float32))
     
    x1_min, x1_max = X[:,0].min(), X[:,0].max(),
     
    x2_min, x2_max = X[:,1].min(), X[:,1].max(),
     
    xx1, xx2 = np.meshgrid(np.linspace(x1_min, x1_max), np.linspace(x2_min, x2_max))
     
    f = w1[0]*xx1+w1[1]*xx2+b1[0]
     
    plt.contour(xx1, xx2, f, [0], colors = 'r') # 繪制分隔超平面
     
    plt.scatter(X[:,0],X[:,1],c=y)
     
    plt.show()
    

     

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM