1. 程式人生 > >機器學習-Logistic迴歸python實踐【3】(10.26更新)

機器學習-Logistic迴歸python實踐【3】(10.26更新)

寫在最前面:Logistic迴歸通過Sigmoid函式接受輸入然後進行預測

首先,介紹一下什麼是Sigmoid函式。大家一定聽過海維賽德階躍函式(Heaviside step function),什麼?沒聽過,好吧,換個名字,單位階躍函式,這個認識吧!

在這裡插入圖片描述
這個函式的問題在於該函式在跳躍點上從0瞬間跳躍到1,這樣處理起來不是很方便

然鵝我們還有另一個具有類似性質的函式Sigmoid函式,計算公式如下:
f(z) = 1/1+e^-z
在這裡插入圖片描述

當x軸的尺度足夠大

在這裡插入圖片描述

import matplotlib.pyplot as plt
import numpy as np


def sigmoid(x):
    # 直接返回sigmoid函式
    return 1. / (1. + np.exp(-x))


def plot_sigmoid():
    # param:起點,終點,間距
    x = np.arange(-30, 30, 0.2)
    y = sigmoid(x)
    plt.plot(x, y)
    plt.show()


if __name__ == '__main__':
    plot_sigmoid()

在這裡插入圖片描述

Sigmoid函式的輸入記為z,給出輸入z的公式:

z = w0x0 + w1x1 + w2x2 + w3x3 +…+ wnxn

用向量去理解的話,就是w^T * x,w是一個列向量,大家都知道行向量和列向量相乘得到一個數。其中向量x是分類器的輸入資料,向量w是我們要找的最佳引數。

我們通過梯度上升法尋找最佳迴歸係數。梯度上升法的基本思想是:想要找到某函式的最大值,最好的方法是沿著該函式的梯度放向探尋。
記梯度為▽,則函式f(x,y)的梯度▽f(x,y) = (■((∂f(x,y))/∂x@(∂f(x,y))/∂y))

這個梯度意味著要沿著x的方向移動在這裡插入圖片描述

然後沿著y的方向移動在這裡插入圖片描述

這裡引入移動量的大小α,用向量表示梯度上升演算法的迭代公式如下:
w := w + α▽wf(w) 大家肯定會疑惑這裡的 := 什麼意思,其實就是程式語言裡的賦值,程式設計裡一般用 = ,但是這裡用 = 會有歧義。

該公式將會一直迭代,直到達到某個停止條件為止。

好了,基礎介紹到這裡
下面舉個栗子

def loadDataSet(filename):
    dataMat = []; labelMat = []
    fr = open(filename)
    for line in fr.readlines():
        lineArr = line.strip().split()
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
        labelMat.append(int(lineArr[2]))
    return dataMat,labelMat

該函式的作用是開啟文字

-0.017612	14.053064	0
-1.395634	4.662541	1
-0.752157	6.538620	0
-1.322371	7.152853	0
0.423363	11.054677	0
0.406704	7.067335	1
0.667394	12.741452	0
-2.460150	6.866805	1
0.569411	9.548755	0
-0.026632	10.427743	0
0.850433	6.920334	1
1.347183	13.175500	0
1.176813	3.167020	1
.
.
.

每行前兩個值分別是x1,x2,第三個值是資料對應的類別標籤。

第二個函式是梯度上升演算法,該函式有兩個引數,第一個引數是dataMatin,是一個二維Numpy陣列,每列分別代表每個不同的特徵,每行則代表每個訓練樣本。dataMatin存放的事100x3的矩陣,alpha是目標移動的步長,maxCycless是迭代次數。
由於txt檔案中包含x1,x2,我們還將x0設為1.0,那麼將三個特徵值作為二維矩陣的列,txt中的100個數據作為行,這就是一個100x3的矩陣,第二個引數是一個1x100的矩陣,列是gradAscent的第二個引數classLabels,為了便於計算,我們使用transpose函式進行轉置,轉成100x1的列向量

labelMat = mat(classLabels).transpose()

然後shape函式計算這個100x3的矩陣的維度,m=100,n=3

m,n = shape(dataMatrix)

步長預設為0.001

alpha = 0.001

迭代次數為500次

maxCycles = 500

ones函式構造了一個全1矩陣,n行1列的矩陣

weights = ones((n,1))

相當於將回歸係數全部初始化為1

迴圈500次,將100x3的矩陣和nx1的矩陣相乘,得到100x1的矩陣,再把這個矩陣作為引數輸入Sigmoid函式,error是標籤減去函式的輸出,這裡計算的是真實類別和預測類別的差值,毫無疑問,h是我們的預測類別。按照該差值的方向調整迴歸係數。

    for k in range(maxCycles):              #heavy on matrix operations
        h = sigmoid(dataMatrix*weights)     #matrix mult
        error = (labelMat - h)              #vector subtraction
        weights = weights + alpha * dataMatrix.transpose()* error #matrix mult

下面是這個函式的完整程式碼

def gradAscent(dataMatIn, classLabels):
    dataMatrix = mat(dataMatIn)             #convert to NumPy matrix
    labelMat = mat(classLabels).transpose() #convert to NumPy matrix
    m,n = shape(dataMatrix)
    alpha = 0.001
    maxCycles = 500
    weights = ones((n,1))
    for k in range(maxCycles):              #heavy on matrix operations
        h = sigmoid(dataMatrix*weights)     #matrix mult
        error = (labelMat - h)              #vector subtraction
        weights = weights + alpha * dataMatrix.transpose()* error #matrix mult
    print(weights)
    return weights

計算出迴歸係數:

[[ 4.12414349]
 [ 0.48007329]
 [-0.6168482 ]]

畫出資料集和Logistic最佳擬合直線的函式

def plotBestFit(weights):
    import matplotlib.pyplot as plt
    dataMat,labelMat=loadDataSet('testSet.txt')
    dataArr = array(dataMat)
    n = shape(dataArr)[0]
    xcord1 = []; ycord1 = []
    xcord2 = []; ycord2 = []
    for i in range(n):
        if int(labelMat[i])== 1:
            xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2])
        else:
            xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2])
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
    ax.scatter(xcord2, ycord2, s=30, c='green')
    x = arange(-3.0, 3.0, 0.1)
    y = (-weights[0]-weights[1]*x)/weights[2]
    ax.plot(x, y)
    plt.xlabel('X1'); plt.ylabel('X2');
    plt.show()

在這裡插入圖片描述

這個例子用到了100x3的資料集,資料量很小,但是卻需要迭代300次,那麼當樣本達到千萬甚至億的級別的時候,遍歷資料集的成本和代價會非常大。

下面介紹一種改進方法,隨機梯度上升演算法
該演算法每次僅用一個樣本點更新迴歸係數

def stocGradAscent0(dataMatrix, classLabels):
    m,n = shape(dataMatrix)
    alpha = 0.01
    weights = ones(n)   #initialize to all ones
    for i in range(m):
        h = sigmoid(sum(dataMatrix[i]*weights))
        error = classLabels[i] - h
        weights = weights + alpha * error * dataMatrix[i]
    return weights

可以看到,隨機梯度上升演算法和梯度上升演算法差別並不大

將每一行和迴歸係數相乘, weights是一個1x3的Numpy陣列,初始化為1

[1. 1. 1.]

然後和每一行的特徵值相乘,得出一個numpy型的float

<class 'numpy.float64'>

最後繪製圖像
在這裡插入圖片描述

今天先到這兒吧,後續看情況更新,大家週末愉快~