機器學習算法 之邏輯迴歸以及python實現

相關文章目錄:python

  1. 機器學習 之線性迴歸
  2. 機器學習 之邏輯迴歸及python實現
  3. 機器學習項目實戰 交易數據異常檢測
  4. 機器學習之 決策樹(Decision Tree)
  5. 機器學習之 決策樹(Decision Tree)python實現
  6. 機器學習之 PCA(主成分分析)
  7. 機器學習之 特徵工程 下面分爲兩個部分:
  8. 邏輯迴歸的相關原理說明
  9. 經過python代碼來實現一個梯度降低求解邏輯迴歸過程

邏輯迴歸(Logistic Regression)

首先須要說明,邏輯迴歸屬於分類算法。分類問題和迴歸問題的區別在於,分類問題的輸出是離散的,如(0,1,2,...)而回歸問題的輸出是連續的。算法

咱們將要用來描述這個分類問題的標記以下:數據結構

m 表明訓練集中實例的數量app

n 表明特徵的數量dom

x^{(i)} 表示第i個訓練實例,是特徵矩陣的第i行,是一個向量機器學習

x_j^{(i)} 表示特徵矩陣中第i行的第j個特徵,也就是第i個訓練實例的第j個特徵函數

y 表明目標變量,也就是輸出變量post

(x,y) 表明訓練集中的一個實例學習

(x^{(i)},y^{(i)}) 表明第i個觀察實例測試

h 表明學習算法的函數,或者假設(hypothesis)

假設函數

邏輯迴歸是在線性迴歸的基礎上,轉化而來的。它是用來解決經典的二分類問題

首先說明下,什麼是二分類問題

咱們將輸出結果y可能屬於的兩個類分別稱爲負向類(negative class)和正向類(positive class),則輸出結果y屬於0,1 ,其中 0 表示負向類,1 表示正向類。

咱們將線性迴歸的輸出記爲:

z = \theta^TX

咱們知道,線性迴歸的輸出結果是實數域中連續的,要想解決二分類問題,這時,咱們引入Sigmoid函數, 對應公式爲:

g(z) = \frac{1}{1+e^{-z}}

對應圖像如上圖,可見,自變量取值爲任意實數,值域爲[0,1]

通過sigmoid函數,就將任意的輸入映射到了[0,1]區間內,咱們在線性迴歸中能夠獲得一個預測值,再將該值進映射到Sigmoid函數中,這樣就完成了由值到機率的轉換,這就是邏輯迴歸中的分類任務

因此,咱們邏輯迴歸的假設函數爲:

h_{\theta}(x) = g(\theta^TX) = \frac{1}{1+e^{-\theta^TX}}

邏輯迴歸的假設函數h_{\theta}(x)即爲對應y=1的機率值,即咱們能夠用下式表示:

P(y=1 \, |\,x;\theta) = h_{\theta}(x)
P(y=0\, |\,x;\theta) =1 - h_{\theta}(x)

通常狀況下,咱們斷定 當h_{\theta}(x) >=0.5時,預測y=1,當h_{\theta}(x) < 0.5時,預測y=0

目標函數

將上述機率進行整合,咱們得出:

P(y\,|\,x;\theta) = (h_{\theta}(x))^y(1-h_{\theta}(x))^{1-y}

其中,y屬於0,1 因爲每一個樣本最後得出的機率值都是獨立的,因此,對於全部樣原本說,咱們能夠獲得對應似然函數爲:

L(\theta) = \prod_{i=1}^{m} P(y^{(i)}\,|\,x^{(i)};\theta) =\prod_{i=1}^{m} (h_{\theta}(x^{(i)}))^{y^{(i)}}(1-h_{\theta}(x^{(i)}))^{1-y^{(i)}}

最終,咱們的目標就是求解最大似然函數,也就是讓全部樣本數據最終求得是正向類或者負向類的機率越大越好。

爲了計算方便,首先,咱們對上述似然函數取對數,得

這個時候,咱們是求的最大值,爲了轉換爲梯度降低任務,因此咱們引入J(\theta) = -\frac{1}{m}l(\theta)

最終,咱們的目標函數爲:

J(\theta) = -\frac{1}{m}\sum_ {i=1}^{m} [y^{(i)}log(h_{\theta}(x^{(i)}))+(1-y^{(i)})log(1-h_{\theta}(x^{(i)}))]

gradient descent(梯度降低)

對代價函數求偏導,得:

\frac{\partial J(\theta)}{\partial \theta_j} = {\frac{1}{m}} \sum_ {i=1}^{m}(h_{\theta}(x^{(i)})-y^{(i)})x_j^{(i)}

向量化後,得:

\frac{\partial J(\theta)}{\partial \theta} = \frac{1}{m}X^T(Sigmoid(\theta X)-y)

決策邊界

在邏輯迴歸中,咱們預測:

h_{\theta}(x) >=0.5時,預測y=1,當h_{\theta}(x) < 0.5時,預測y=0

即: 當\theta^TX >= 0時,預測y=1,當\theta^TX < 0時,預測y=1

因此,決策邊界爲:

\theta^TX = 0

梯度降低求解邏輯迴歸問題

下面,經過邏輯迴歸模型,來實現一個預測某個學生是否會被大學錄取的問題。假設你是一個大學系的管理員,你想根據兩次考試的結果來決定每一個申請人的錄取機會,如今你擁有以前申請學生的能夠用於訓練邏輯迴歸的訓練樣本集。對於每個訓練樣本,你有他們兩次測試的評分和最後是被錄取的結果。爲了完成這個預測任務,咱們準備構建一個能夠基於兩次測試評分來評估錄取可能性的分類模型。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics import classification_report#這個包是評價報告
複製代碼

首先,讓咱們獲取下數據,看下數據結構

#exam1,exam2表明兩次測試評分,也就是特徵值x1,y1,admitted爲錄取結果,也就是y
data = pd.read_csv('ex2data1.txt',names=['exam1','exam2','admitted'])
data.head()  #打印前五行,看看
複製代碼
exam1 exam2 admitted
0 34.623660 78.024693 0
1 30.286711 43.894998 0
2 35.847409 72.902198 0
3 60.182599 86.308552 1
4 79.032736 75.344376 1

一般狀況下,進行相關數據可視化,能夠幫咱們更好的分析數據

# 數據可視化
sns.lmplot('exam1','exam2', hue='admitted', data=data, size=6,fit_reg=False,scatter_kws={"s":50})
plt.show()
複製代碼

數據初始化

包括分離出特徵值和輸出變量,進行特徵縮放以及theat向量的初始化等操做

#進行歸一化處理,也就是特徵縮放(注意,這塊只是針對特徵,也就是X)
def normalize_feature(df):
    data_explame = df.iloc[:,:-1]
    data_x = data_explame.apply(lambda column: (column - column.mean())/column.std())
    data = pd.concat([data_x,df.iloc[:,-1]], axis=1)
    return data

#插入x0列並轉換爲ndarray
def insert_x0_and_asmatrix(data):
    ones = pd.DataFrame({'ones': np.ones(len(data))}) #生成一個m行1列的dataFrame
    data = pd.concat([ones,data], axis=1)  #根據列,合併數據
    return data.as_matrix()    #轉化爲ndarray進行返回

#刷新數據
def shuffleData(data):
    np.random.shuffle(data)
    return data

#讀取特徵
def get_X(data):
    return data[:,:-1]

#讀取輸出變量
def get_Y(data):
    return data[:,-1]


複製代碼
data = normalize_feature(data)
data.head()  #打印下特徵縮放後的數據看看
複製代碼
exam1 exam2 admitted
0 -1.594216 0.635141 0
1 -1.817101 -1.201489 0
2 -1.531325 0.359483 0
3 -0.280687 1.080923 1
4 0.688062 0.490905 1
orig_data = insert_x0_and_asmatrix(data)  #加入x0列
orig_data[0:5]
複製代碼
array([[ 1.        , -1.59421626,  0.63514139,  0.        ],
       [ 1.        , -1.81710142, -1.20148852,  0.        ],
       [ 1.        , -1.53132516,  0.35948329,  0.        ],
       [ 1.        , -0.28068724,  1.08092281,  1.        ],
       [ 1.        ,  0.68806193,  0.49090485,  1.        ]])
複製代碼
shuffleData(orig_data)  #打亂樣本次序
orig_data[0:5]
複製代碼
array([[ 1.        ,  0.96558389, -1.22094762,  1.        ],
       [ 1.        ,  0.14514418,  1.04248696,  1.        ],
       [ 1.        ,  0.74754551, -1.15162347,  1.        ],
       [ 1.        , -0.5222529 , -1.64944586,  0.        ],
       [ 1.        ,  0.08608101,  0.01976857,  1.        ]])
複製代碼
X = get_X(orig_data)
y = get_Y(orig_data)
theta = np.zeros(3)
X.shape,y.shape,theta
複製代碼
((100, 3), (100,), array([0., 0., 0.]))
複製代碼

sigmoid函數

g(z) = \frac{1}{1+e^{-z}}
def sigmoid(z):
    return 1/(1+np.exp(-z))
複製代碼

咱們來看下sigmoid函數的函數圖像

#看下sigmoid函數的函數圖像
numbers = np.arange(-10,10,step=0.1)
plt.plot(numbers, sigmoid(numbers),'r')
plt.show()
複製代碼

計算代價函數

J(\theta) = -\frac{1}{m}\sum_ {i=1}^{m} [y^{(i)}log(h_{\theta}(x^{(i)}))+(1-y^{(i)})log(1-h_{\theta}(x^{(i)}))]
#計算代價
def cost(theta, X, y):
    return -np.mean(y * np.log(sigmoid(X @ theta)) 
                    + (1-y) * np.log(1-sigmoid(X @ theta)))
複製代碼

來,咱們看下初始狀態下,代價值是多少

cost(theta, X, y)
複製代碼
0.6931471805599453
複製代碼

計算梯度

\frac{\partial J(\theta)}{\partial \theta_j} = {\frac{1}{m}} \sum_ {i=1}^{m}(h_{\theta}(x^{(i)})-y^{(i)})x_j^{(i)}

向量化後,得:

\frac{\partial J(\theta)}{\partial \theta} = \frac{1}{m}X^T(Sigmoid(X\theta )-y)
#計算梯度
def gradient(theta, X, y):
    return 1/len(X) * X.T @ (sigmoid(X @ theta) - y)
複製代碼

決策邊界

\theta^TX = 0
def decision_fun(x,theta):
    coef = -(theta/theta[2])
    print(coef)
    return coef[0] + coef[1]*x

def draw_decision_fun(theta):
    x = np.arange(-2,2,step = 0.01)
    y = decision_fun(x,theta)
    sns.lmplot('exam1','exam2', hue='admitted', data=data, size=6,fit_reg=False,scatter_kws={"s":25})
    plt.plot(x,y)
    plt.xlim(-2,2)
    plt.ylim(-2,2)
    plt.title('Decision Boundary')
    plt.show()
複製代碼

在進行梯度降低算法時,咱們有三種不一樣的中止策略

  1. 直接設置迭代次數,次數到了中止迭代
  2. 設置一個代價函數降低的閾值,若是本次和上一次迭代完後的代價函數的差值 若是小於這個閾值,則中止迭代
  3. 設置梯度的閾值,若是某次迭代後,梯度小於閾值,則中止迭代
STOP_ITER = 0  #設置迭代次數
STOP_COST = 1  #設置目標函數降低的閾值
STOP_GRAD = 2  #設置梯度的閾值

def stopCriterion(type, value, threshold):
    #設定三種不一樣的中止策略
    if type == STOP_ITER:        return value > threshold
    elif type == STOP_COST:      return abs(value[-1]-value[-2]) < threshold
    elif type == STOP_GRAD:      return np.linalg.norm(value) < threshold
複製代碼
#繪製代價函數圖像
def drwcosts(costs):
    fig, ax = plt.subplots(figsize=(12,4))
    ax.plot(np.arange(len(costs)), costs, 'r')
    ax.set_xlabel('Iterations')
    ax.set_ylabel('Cost')
複製代碼

下面來實現梯度降低算法

import time
def descent(data, theta, batchSize, stopType, thresh, alpha):
    init_time = time.time()
    i = 0; #迭代次數
    k = 0; #batch
    X = get_X(data)  
    y = get_Y(data)
    grad = gradient(theta,X,y)  #計算梯度
    costs = [cost(theta, X, y)]   #計算代價值
    
    
    while True:
        #根據不一樣的梯度降低算法(批量,隨機,小批量),先計算梯度
        grad = gradient(theta, X[k:k+batchSize],y[k:k+batchSize])
        k = k+batchSize
        if k>= data.shape[0]:
            k = 0
            shuffleData(data)   #從新打亂數據
            X = get_X(data)
            y = get_Y(data)
        theta = theta - alpha * grad  #更新theta
        costs.append(cost(theta, X, y)) #保存本次迭代後的目標值
        i += 1  #迭代次數加1
        
        #根據不一樣的中止策略,傳入不一樣的value,來判斷迭代是否結束
        if stopType == STOP_ITER: 
            value = i
        elif stopType == STOP_COST:
            value = costs
        elif stopType == STOP_GRAD:
            value = grad
         
        if stopCriterion(stopType, value, thresh):  #若是知足中止策略,則中止迭代
            break
    print("theta:",theta)
    print("迭代次數:",i-1)
    print("最後求得的收斂的目標值:",costs[-1])
    print("最後的梯度:",grad)
    print("所用時間:",time.time() - init_time)
    return theta, i-1, costs, grad, time.time() - init_time
         
            
複製代碼

不一樣的中止策略

首先看下,當直接設置迭代次數爲5000,學習率爲0.0001時,對應模型狀況

theat, iter, costs, grad, durtime = descent(orig_data, theta, orig_data.shape[0], STOP_ITER, thresh=5000, alpha=0.0001)
drwcosts(costs)
複製代碼
theta: [0.04702107 0.13181832 0.11768083]
迭代次數: 5000
最後求得的收斂的目標值: 0.6262088600901743
最後的梯度: [-0.08832936 -0.24808112 -0.22154761]
所用時間: 0.8178122043609619
複製代碼

看上面的圖像,迭代5000次後,模型遠遠沒到收斂的程度,說明目前尚未近似找到最優解,須要繼續增長迭代次數

讓咱們將迭代次數,加到30000次看看

heat, iter, costs, grad, durtime = descent(orig_data, theta, orig_data.shape[0], STOP_ITER, thresh=30000, alpha=0.0001)
drwcosts(costs)
複製代碼
theta: [0.21656628 0.60953923 0.54481303]
迭代次數: 30000
最後求得的收斂的目標值: 0.44649953741239545
最後的梯度: [-0.05269534 -0.14810478 -0.1325817 ]
所用時間: 4.967716455459595
複製代碼

能夠看到,相對於上次,此次明顯效果稍好點,單是目標函數仍是沒能很好的收斂,你能夠繼續增長迭代次數,或者適當增長學習率,進行嘗試看看。

下面,咱們來換種中止策略,採用 設置目標函數降低的閾值 這種中止策略看看

設置閾值爲0.000001,學習率爲0.001

heat, iter, costs, grad, durtime = descent(orig_data, theta, orig_data.shape[0], STOP_COST, thresh=0.000001, alpha=0.001)
drwcosts(costs)
複製代碼
theta: [0.88388452 2.24688547 2.04464801]
迭代次數: 36738
最後求得的收斂的目標值: 0.23470607174751176
最後的梯度: [-0.01016408 -0.02172708 -0.02060574]
所用時間: 6.014917373657227
複製代碼

能夠看到基本已經收斂。用時6秒鐘左右

下面,再來看下 設置梯度的閾值 這種中止策略下訓練出的模型

設置梯度閾值爲0.01,學習率爲0.001

heat, iter, costs, grad, durtime = descent(orig_data, theta, orig_data.shape[0], STOP_GRAD, thresh=0.01, alpha=0.001)
drwcosts(costs)
複製代碼
theta: [1.31220652 3.14902915 2.90906189]
迭代次數: 112802
最後求得的收斂的目標值: 0.20918126836321715
最後的梯度: [-0.00323388 -0.00681177 -0.00656816]
所用時間: 19.595609664916992
複製代碼

能夠看到,此次效果最好,代價函數基本已經收斂,最後的目標值爲:0.20918126836321718 迭代了112802次,耗時20秒左右

對比不一樣的梯度降低方法

上面,咱們都用的是批量梯度降低,下面,咱們來嘗試下隨機梯度降低。 中止策略採設置梯度閾值, 閾值爲0.01,學習率爲0.001

heat, iter, costs, grad, durtime = descent(orig_data, theta, 1,  STOP_GRAD, thresh=0.01, alpha=0.001)
drwcosts(costs)
複製代碼
theta: [0.67632327 1.78493605 1.61049596]
迭代次數: 20239
最後求得的收斂的目標值: 0.2623021373549509
最後的梯度: [-0.00449379 -0.00741967 -0.00495884]
所用時間: 1.0222656726837158
複製代碼

對比上面的批量梯度降低,能夠發現,最後模型效果沒批量梯度降低好,可是所用時間明顯下降了。

可是,須要注意,採用隨機梯度降低,並非每次都能收斂,有時若是樣本數據不是很好,可能會出現目標函數沒法收斂的狀況!

因此,咱們更經常使用批量梯度降低,下面看下

heat, iter, costs, grad, durtime = descent(orig_data, theta, 64,  STOP_GRAD, thresh=0.01, alpha=0.001)
drwcosts(costs)
複製代碼
theta: [0.90249119 2.28523187 2.08373685]
迭代次數: 38617
最後求得的收斂的目標值: 0.2329190821129908
最後的梯度: [-0.00311558 -0.00452799 -0.00279034]
所用時間: 4.404224395751953
複製代碼

咱們能夠看到,批量梯度降低所訓練出的模型,效果和所用時間,在上述兩種降低算法之間。

用訓練集預測和驗證

def predict(X,theta):   #預測
    prob = sigmoid(X @ theta)
    return (prob >= 0.5).astype(int)
複製代碼
y_predict = predict(X, theat)  #獲得訓練集數據對應的預測結果
print(classification_report(y, y_predict))
#precision:精確度
#recall:召回率
#f1-score: f1值
複製代碼
precision    recall  f1-score   support

        0.0       0.88      0.88      0.88        40
        1.0       0.92      0.92      0.92        60

avg / total       0.90      0.90      0.90       100
複製代碼

歡迎關注個人我的公衆號 AI計算機視覺工坊,本公衆號不按期推送機器學習,深度學習,計算機視覺等相關文章,歡迎你們和我一塊兒學習,交流。

相關文章
相關標籤/搜索