Python Logistic回歸分類

1.Logistic回歸

人們將已知存在的數(shù)據(jù)點(diǎn)利用一條直線進(jìn)行擬合(該直線被稱為最佳擬合直線)的過程稱為回歸。
而今天介紹的Logistic回歸分類的主要思想就是依據(jù)現(xiàn)有已分類的數(shù)據(jù)樣本建立回歸公式,以此進(jìn)行分類。
“回歸”源于最佳擬合,而Logistic回歸中訓(xùn)練分類器的做法就是利用一些最優(yōu)算法尋找符合最佳擬合的擬合參數(shù)。

1.1 Logistic分布

設(shè)X是連續(xù)的隨機(jī)變量,且具有如下的分布函數(shù)和密度函數(shù):

![](http://latex.codecogs.com/svg.latex? \Large $$ F(X) = P(X\leq{x}) = \frac{1}{1+\exp^{-\frac{(x-\mu)}{\gamma}}}$$)

![](http://latex.codecogs.com/svg.latex? \Large $$ f(X) = F'(X) = \frac{\exp{-\frac{x-\mu}{\gamma}}}{\gamma(1+\exp{-\frac{x-\mu}{\gamma}})^2}$$)

其中μ為位置參數(shù),γ > 0為形狀參數(shù)。

下圖是F(X),f(X)的大致圖像,人們又把F(X)函數(shù)成為sigmoid函數(shù)(以后會(huì)經(jīng)常見到它)。

import matplotlib.pyplot as plt
import numpy as np
import scipy

x = np.linspace(-5, 5)
y1 = 1/(1 + np.exp(- x))
y2 = np.exp(- x)/(1 + np.exp(- x))**2
fig1 = plt.figure()
plt.xlabel('x')
plt.ylabel('F(x)')
plt.plot(x, y1, linewidth = 2.0)
fig2 = plt.figure()
plt.xlabel('x')
plt.ylabel('f(x)')
plt.plot(x, y2, linewidth = 2.0)
plt.show()

1.2 二項(xiàng)式Logistic回歸

從以上的Logistic分布定義中引申出一種分類模型,就是下面要介紹的二項(xiàng)式Logistic回歸模型。
在上述X中,將其分為0、1兩類。即隨機(jī)變量X的取值為實(shí)數(shù),其分類變量定義為Y,每個(gè)x所屬類別可以通過條件概率分布P(Y|X)進(jìn)行表示。
條件概率分布如下:

![](http://latex.codecogs.com/svg.latex? \Large $$P(Y=1\mid x) = \frac{\exp(\omega \cdot x+b)}{1+\exp(\omega \cdot x+b)}$$)

![](http://latex.codecogs.com/svg.latex? \Large $$P(Y=0\mid x) = \frac{1}{1+\exp(\omega \cdot x+b)}$$)

xRn是輸入,Y∈ {0, 1}是輸出,ωRn為權(quán)值向量,bR為偏置,ω·xωx的內(nèi)積。

這里將ωx進(jìn)行擴(kuò)充,即![](http://latex.codecogs.com/svg.latex? \Large $\omega = {\omega ^{(1)},\omega ^{(2)},...,\omega ^{(n)},b }$)和![](http://latex.codecogs.com/svg.latex? \Large $x = {x{(1)},x{(2)},...,x^{(n)},1}$)

此時(shí)的Logistic回歸模型如下:

![](http://latex.codecogs.com/svg.latex? \Large $$P(Y=1\mid x) = \frac{\exp(\omega \cdot x)}{1+\exp(\omega \cdot x)}$$)

![](http://latex.codecogs.com/svg.latex? \Large $$P(Y=0\mid x) = \frac{1}{1+\exp(\omega \cdot x)}$$)

在考慮一個(gè)事件發(fā)生為p,則不發(fā)生的概率為1-p,那么這個(gè)事件發(fā)生的幾率(odds)為p/(1-p)。對數(shù)幾率(log odds)為

![](http://latex.codecogs.com/svg.latex? \Large $$logit(p) = \log{\frac{p}{1-p}}$$)

將上述Logistic回歸模型代入其中可以得到:

![](http://latex.codecogs.com/svg.latex? \Large $$\log{\frac{P(Y = 1\mid x)}{1-P(Y = 1\mid x)}} = \omega \cdot x$$)

可以看出輸出Y = 1的對數(shù)幾率是輸入x的線性函數(shù),即Y可以用x的線性函數(shù)表示。自然地,在Logistic回歸模型中,x的線性函數(shù)值ω·x越接近于+∞,其概率越接近于1,反之,ω·x越接近于-∞,其概率越接近于0。

1.3 參數(shù)估計(jì)

假設(shè)給定訓(xùn)練數(shù)據(jù)集![](http://latex.codecogs.com/svg.latex? \Large $T = {(x_1,y_1),(x_2,y_2),...,(x_N,y_N)}$)
其中,xiRnyi ∈ {0,1},利用極大似然估計(jì)法估計(jì)模型參數(shù)。

設(shè)![](http://latex.codecogs.com/svg.latex? \Large $P(Y=1\mid x) =\pi (x)$,則$P(Y=0\mid x) =1-\pi (x)$)

似然函數(shù)為:![](http://latex.codecogs.com/svg.latex? \Large $$\prod_{i=1}^{N} [\pi(x_i)]{y_i}[1-\pi(x_i)]{1-y_i}$$)

對數(shù)似然函數(shù)為:

此時(shí)對L(ω)求最大值,即得到ω的估計(jì)值。
為此,后續(xù)利用梯度下降法或者擬牛頓法進(jìn)行該值的求解。

假設(shè)ω的極大似然估計(jì)值為ω',那么Logistic模型為:

![](http://latex.codecogs.com/svg.latex? \Large $$P(Y=1\mid x) = \frac{\exp(\omega' \cdot x)}{1+\exp(\omega' \cdot x)}$$)

![](http://latex.codecogs.com/svg.latex? \Large $$P(Y=0\mid x) = \frac{1}{1+\exp(\omega' \cdot x)}$$)

1.4 梯度法求解估計(jì)值

對上述L(ω)中的ω求導(dǎo),得到:

令L(ω) = 0,可以求得其最大的L(ω)對應(yīng)的ω',但由于無法直接求解,故采用梯度下降法進(jìn)行求解。

由上求導(dǎo)過程可以知道,L(ω) 的梯度為

![](http://latex.codecogs.com/svg.latex? \Large $$\triangledown_{\omega}L(\omega) =\sum_{i=1}^{N}{y_i - \pi(x_i)}x_i$$)

故迭代公式(此處為梯度上升算法)為

![](http://latex.codecogs.com/svg.latex? \Large $$\omega = \omega + \alpha \sum_{i=1}^{N}{y_i - \pi(x_i)}x_i$$)

其中α為步長,當(dāng)![](http://latex.codecogs.com/svg.latex? \Large $\mid\mid \triangledown_{\omega}L(\omega) \mid\mid < \varepsilon$) 即可求得最大的ωε為誤差。

2、Logistic分類器實(shí)現(xiàn)

仍然使用這份數(shù)據(jù)進(jìn)行算法實(shí)現(xiàn)

以下列數(shù)據(jù)集為例,進(jìn)行Logistic分類器的設(shè)計(jì)。

編號 色澤 根蒂 敲聲 紋理 臍部 觸感 密度 含糖率 好瓜
1 青綠 蜷縮 濁響 清晰 凹陷 硬滑 0.697 0.460
2 烏黑 蜷縮 沉悶 清晰 凹陷 硬滑 0.774 0.376
3 烏黑 蜷縮 濁響 清晰 凹陷 硬滑 0.634 0.264
4 青綠 蜷縮 沉悶 清晰 凹陷 硬滑 0.608 0.318
5 淺白 蜷縮 濁響 清晰 凹陷 硬滑 0.556 0.215
6 青綠 稍蜷 濁響 清晰 稍凹 軟粘 0.403 0.237
7 烏黑 稍蜷 濁響 稍糊 稍凹 軟粘 0.481 0.149
8 烏黑 稍蜷 濁響 清晰 稍凹 硬滑 0.437 0.211
9 烏黑 稍蜷 沉悶 稍糊 稍凹 硬滑 0.666 0.091
10 青綠 硬挺 清脆 清晰 平坦 軟粘 0.243 0.267
11 淺白 硬挺 清脆 模糊 平坦 硬滑 0.245 0.057
12 淺白 蜷縮 濁響 模糊 平坦 軟粘 0.343 0.099
13 青綠 稍蜷 濁響 稍糊 凹陷 硬滑 0.639 0.161
14 淺白 稍蜷 沉悶 稍糊 凹陷 硬滑 0.657 0.198
15 烏黑 稍蜷 濁響 清晰 稍凹 軟粘 0.360 0.37
16 淺白 蜷縮 濁響 模糊 平坦 硬滑 0.593 0.042
17 青綠 蜷縮 沉悶 稍糊 稍凹 硬滑 0.719 0.103

2.1 解析數(shù)據(jù)文件

上一篇的《樸素貝葉斯法》已經(jīng)利用了Pandas對讀入的數(shù)據(jù)文件進(jìn)行解析并進(jìn)行啞變量處理,下面即封裝好的解析代碼:

#導(dǎo)入numpy和pandas庫
import numpy as np
import pandas as pd
#解析數(shù)據(jù)文件
def loadDataSet(filename):
    dataSet = pd.read_csv(filename, sep = '\t', index_col = '編號')

    #啞變量處理
    featureDict = []
    new_dataSet = pd.DataFrame()
    for i in range(len(dataSet.columns)):
        featureList = dataSet[dataSet.columns[i]]
        classSet = list(set(featureList))
        count = 0
        for feature in classSet:
            d = dict()
            if isinstance(feature, float):#判斷是否為連續(xù)變量
                continue
            else:
                featureList[featureList == feature] = count
                d[feature] = count
                count += 1
            featureDict.append(d)
        new_dataSet = pd.concat([new_dataSet, featureList], axis = 1)

    dataMat = [list(new_dataSet.loc[i][:-1]) for i in range(1,len(new_dataSet) + 1)]
    labelMat = list(new_dataSet[new_dataSet.columns[-1]])
    return dataMat, labelMat
filename = 'data.txt'
dataMat, labelMat = loadDataSet(filename)

import pprint
pprint.pprint(dataMat)
pprint.pprint(labelMat)
[[1, 1, 2, 2, 0, 0, 0.69700000000000006, 0.46000000000000002],
 [0, 1, 1, 2, 0, 0, 0.77400000000000002, 0.376],
 [0, 1, 2, 2, 0, 0, 0.63400000000000001, 0.26400000000000001],
 [1, 1, 1, 2, 0, 0, 0.60799999999999998, 0.318],
 [2, 1, 2, 2, 0, 0, 0.55600000000000005, 0.215],
 [1, 2, 2, 2, 1, 1, 0.40299999999999997, 0.23699999999999999],
 [0, 2, 2, 0, 1, 1, 0.48100000000000004, 0.14899999999999999],
 [0, 2, 2, 2, 1, 0, 0.43700000000000006, 0.21100000000000002],
 [0, 2, 1, 0, 1, 0, 0.66599999999999993, 0.090999999999999998],
 [1, 0, 0, 2, 2, 1, 0.24299999999999999, 0.26700000000000002],
 [2, 0, 0, 1, 2, 0, 0.245, 0.057000000000000002],
 [2, 1, 2, 1, 2, 1, 0.34299999999999997, 0.099000000000000005],
 [1, 2, 2, 0, 0, 0, 0.63900000000000001, 0.161],
 [2, 2, 1, 0, 0, 0, 0.65700000000000003, 0.19800000000000001],
 [0, 2, 2, 2, 1, 1, 0.35999999999999999, 0.37],
 [2, 1, 2, 1, 2, 0, 0.59299999999999997, 0.042000000000000003],
 [1, 1, 1, 0, 1, 0, 0.71900000000000008, 0.10300000000000001]]
[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]

可以看到,該操作將字符串型的分類變量解析成為了數(shù)值型的分類變量,從而方便了將要進(jìn)行的數(shù)值運(yùn)算。

2.2 利用梯度上升法求最佳回歸系數(shù)

在前面的定義中,Logistic分布函數(shù)$F(X)$又被稱為sigmoid函數(shù),其對數(shù)幾率為

![](http://latex.codecogs.com/svg.latex? \Large $$\log{\frac{P(Y = 1\mid x)}{1-P(Y = 1\mid x)}} = \omega \cdot x$$)

即將sigmoid函數(shù)的輸入可以看作是:

![](http://latex.codecogs.com/svg.latex? \Large $$z = \omega {(1)}x{(1)}+\omega {(2)}x{(2)}+,...,+\omega {(n)}x{(n)} = \omega^{T} \cdot x$$)

由此,定義下面的代碼進(jìn)行梯度上升法的實(shí)現(xiàn):

#定義Sigmoid函數(shù)
def sigmoid(inX):
    return 1.0/(1 + np.exp(- inX))

#隨機(jī)的梯度上升法
def gradAscent(dataMatIn, classLabels, numIter = 150):
    #獲得行數(shù)和列數(shù),即樣本數(shù)和特征數(shù)
    m, n = np.shape(dataMatIn)
    #權(quán)重初始化
    weights = np.ones(n)
    for j in range(numIter):
        dataIndex = range(m)
        for i in range(m):
            alpha = 4/(1.0 + j + i) + 0.01
            randIndex = int(np.random.uniform(0, len(dataIndex)))
            h = sigmoid(sum(dataMatIn[randIndex] * weights))
            error = classLabels[randIndex] - h
            weights = weights + np.dot(alpha * error, dataMatIn[randIndex])
    return weights
weights = gradAscent(dataMat, labelMat)
print(weights)
[-1.91739131 -2.37320272  3.30085298  1.32020706 -2.30328752  0.58413608
  0.84630395 -0.63702599]

2.3 分類器設(shè)計(jì)

由上,求出了相應(yīng)的輸入特征對應(yīng)權(quán)重,利用對數(shù)幾率公式,可以簡單實(shí)現(xiàn)分類的效果,相關(guān)設(shè)計(jì)代碼如下:

def classfy(testdir, weights):
    dataMat, labelMat = loadDataSet(testdir)
    dataMat = np.mat(dataMat)
    weights = np.mat(weights)
    h = sigmoid(dataMat * weights.transpose())
    h = h.tolist()
    m = len(h)
    error = 0.0
    for i in range(m):
        if h[i][0] > 0.5:
            print(int(labelMat[i]),'is classfied as: 1')
            if int(labelMat[i])!=1:
                error += 1
                print('error')
        else:
            print(int(labelMat[i]),'is classfied as: 0')
            if int(labelMat[i])!=0:
                error += 1
                print('error')
    print('error rate is:','%.4f' %(error/m))
classfy(filename, weights)
1 is classfied as: 1
1 is classfied as: 1
1 is classfied as: 1
1 is classfied as: 1
1 is classfied as: 1
1 is classfied as: 1
1 is classfied as: 1
1 is classfied as: 1
0 is classfied as: 0
0 is classfied as: 0
0 is classfied as: 0
0 is classfied as: 0
0 is classfied as: 1
error
0 is classfied as: 0
0 is classfied as: 1
error
0 is classfied as: 0
0 is classfied as: 0
error rate is: 0.1176

將訓(xùn)練的數(shù)據(jù)樣本進(jìn)行測試,可以看出上述分類中,只有兩個(gè)樣本被分類錯(cuò)誤了,準(zhǔn)確度達(dá)到了88.24%,分類效果不錯(cuò)。

2.4 Scikit - Learn庫簡單實(shí)現(xiàn)Logistic分類

下面的代碼是簡單通過Scikit - Learn庫實(shí)現(xiàn)Logistic的分類:

from sklearn.linear_model import LogisticRegression

X, Y = loadDataSet(filename)

clf = LogisticRegression()
clf.fit(X, Y)
y_pred = clf.predict(X)
accuracy = np.mean(Y == y_pred)
print('準(zhǔn)確度為:', accuracy)
準(zhǔn)確度為: 0.882352941176

?

可以看出,上述實(shí)現(xiàn)的準(zhǔn)確度與設(shè)計(jì)的分類器的準(zhǔn)確度基本一樣,效果不錯(cuò)。

3、總結(jié)

Logist回歸分類的優(yōu)缺點(diǎn):

  • 優(yōu)點(diǎn):計(jì)算代價(jià)低,易于理解和實(shí)現(xiàn);
  • 缺點(diǎn):易欠擬合,分類精度普遍不高。

本文實(shí)現(xiàn)過程中使用的數(shù)據(jù)樣本量較少,結(jié)果也較為單一,后續(xù)可以通過訓(xùn)練和測試較多樣本量的數(shù)據(jù),來感受其作用。

4、 參考文獻(xiàn)

[1] 李航. 統(tǒng)計(jì)學(xué)習(xí)方法.清華大學(xué)出版社,2012
[2] Peter Harrington. 機(jī)器學(xué)習(xí)實(shí)戰(zhàn). 人民郵電出版社,2013
[3] http://blog.csdn.net/lsldd/article/details/41551797

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容