> Photo by Tj Holowaychuk on Unsplash
Logistic迴歸的兩種方法:梯度下降法和最佳化函式
邏輯迴歸是一種非常流行的機器學習技術。當因變數是分類的時,我們使用邏輯迴歸。本文將重點介紹針對多類分類問題的邏輯迴歸的實現。我假設您已經知道如何使用Logistic迴歸實現二進位制分類。
因為多類分類是建立在二進位制分類之上的。
您將在本文中學習二進位制分類的概念,公式和工作示例
多類別分類多類分類的實現遵循與二進位制分類相同的思想。如您所知,在二進位制分類中,我們解決了是或否問題。就像上述文章中的示例一樣,輸出回答了一個人是否患有心臟病的問題。我們只有兩類:心臟病和無心臟病。
如果輸出為1,則該人患有心臟病,如果輸出為0,則該人沒有心臟病。
在多類別分類中,我們有兩個以上的類別。這是一個例子。說,我們具有汽車,卡車,腳踏車和船的不同特徵和特性作為輸入特徵。我們的工作是預測標籤(汽車,卡車,腳踏車或船)。
如何解決呢?
我們將以解決心臟病或無心臟病的方式將每個類別視為二元分類問題。
這種方法稱為"一對多"方法
在one vs all方法中,當我們使用一個類時,該類用1表示,其餘類變為0。
例如,如果我們有四個類別:汽車,卡車,腳踏車和船。當我們在汽車上工作時,我們將汽車用作1,將其餘類別用作零。同樣,當我們在卡車上工作時,卡車的元素將為1,其餘類別為零。
當您將其實現時,它將更加易於理解。我建議您在閱讀時繼續編碼並執行程式碼。
在這裡,我將以兩種不同的方式實現此演算法:
· 梯度下降法。
2.最佳化功能方法。
重要方程式及其運作方式:
Logistic迴歸使用S形函式來預測輸出。S形函式返回0到1的值。通常,我們採用一個閾值,例如0.5。如果sigmoid函式返回的值大於或等於0.5,則將其視為1;如果sigmoid函式返回的值小於0.5,則將其視為0。
z是輸入要素乘以表示為theta的隨機初始化值的乘積。
X是輸入要素。在大多數情況下,有幾種輸入功能。因此,此公式變得很大:
X1,X2,X3是輸入要素,並且將為每個輸入要素隨機初始化一個theta。開頭的Theta0是偏差項。
該演算法的目標是在每次迭代時更新此theta,以便它可以在輸入要素和輸出標籤之間建立關係。
成本函式和梯度下降
成本函式給出的想法是,我們的預測與原始輸出相差多遠。這是該公式:
這裡,
m是訓練示例數或訓練資料數,
y是原始輸出標籤,
h是假設或預測的輸出。
這是梯度下降的方程式。使用此公式,我們將在每次迭代中更新theta值:
梯度下降法的實現先決條件:
a。您需要能夠舒適地讀取和編寫python程式碼。
b。基本的Numpy和Pandas庫。
在這裡,我將逐步展示實現。
· 匯入必要的包和資料集。我從安德魯·伍(Andrew Ng)在Coursera的機器學習課程中獲取了資料集。這是一個手寫識別資料集。從1到10的數字。
從畫素資料集中,我們需要識別數字。在此資料集中,輸入變數和輸出變數在Excel檔案中的不同工作表中組織。請隨時從本頁末尾的連結下載資料集。
讓我們匯入必要的包和資料集,
import pandas as pdimport numpy as npxl = pd.ExcelFile('ex3d1.xlsx')df = pd.read_excel(xl, 'X', header=None)
2.匯入y,它是輸出變數
y = pd.read_excel(xl, 'y', header = None)
3.定義採用輸入變數和theta的假設。它返回計算出的輸出變數。
def hypothesis(theta, X): return 1 / (1 + np.exp(-(np.dot(theta, X.T)))) - 0.0000001
4.構建使用輸入變數,輸出變數和theta的成本函式。它返回假設的成本。這意味著它給出了關於預測距原始輸出有多遠的想法。
def cost(X, y, theta): y1 = hypothesis(X, theta) return -(1/len(X)) * np.sum(y*np.log(y1) + (1-y)*np.log(1-y1))
5.現在,該進行資料預處理了。
資料是乾淨的。不需要太多預處理。我們需要在輸入變數中新增一個偏差列。請檢查df和y的長度。如果長度不同,則該模型將不起作用。
print(len(df))print(len(y))X = pd.concat([pd.Series(1, index=df.index, name='00'), df], axis=1)
1. y列的數字從1到10。這意味著我們有10個類別。
y是一個不需要的DataFrame。我只會將列保留為包含值的系列。
y = y.iloc[:, 0]
我們將為每個類建立與y相同長度的一列。當類為5時,請為該行建立一個包含1的列,否則為5和0。
檢查一下,我們有幾個類,
y.unique()
輸出:
array([10, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int64)
因此,我們有10個班級。啟動一個具有10列和df.shape [0]行數的DataFrame。
y1 = np.zeros([df.shape[0], len(y.unique())])y1 = pd.DataFrame(y1)
我們將使用一些簡單的程式碼以程式設計方式進行操作:
for i in range(0, len(y.unique())): for j in range(0, len(y1)): if y[j] == y.unique()[i]: y1.iloc[j, i] = 1 else: y1.iloc[j, i] = 0y1.head()
7.現在定義函式" gradient_descent"。此函式將輸入變數,輸出變數,θ,alpha和曆元數作為引數。在這裡,alpha是學習率。
您應該根據需要選擇它。太小或太大的學習率可能會使您的演算法變慢。我喜歡針對不同的學習率執行該演算法,並獲得正確學習率的想法。選擇正確的學習率可能需要幾次迭代。
對於y1中的每一列,我們將實現一個二進位制分類。
例如,當我考慮數字2時,數字2應該返回1,其餘數字應該返回0。因此,由於我們有10個類,所以每個epoch(iteration)運行了10次。因此,我們在這裡有一個巢狀的for迴圈。
def gradient_descent(X, y, theta, alpha, epochs): m = len(X) for i in range(0, epochs): for j in range(0, 10): theta = pd.DataFrame(theta) h = hypothesis(theta.iloc[:,j], X) for k in range(0, theta.shape[0]): theta.iloc[k, j] -= (alpha/m) * np.sum((h-y.iloc[:, j])*X.iloc[:, k]) theta = pd.DataFrame(theta) return theta, cost
7.初始化theta。記住,我們將為每個類實現邏輯迴歸。每個課程也會有一系列的theta。
我正在執行1500個紀元。我敢肯定,隨著時間的推移,準確率會更高。
theta = np.zeros([df.shape[1]+1, y1.shape[1]])theta = gradient_descent(X, y1, theta, 0.02, 1500)
8.使用此更新的theta,計算輸出變數。
output = []for i in range(0, 10): theta1 = pd.DataFrame(theta) h = hypothesis(theta1.iloc[:,i], X) output.append(h)output=pd.DataFrame(output)
9.比較計算出的輸出和原始輸出變數,以計算模型的準確性。
accuracy = 0for col in range(0, 10): for row in range(len(y1)): if y1.iloc[row, col] == 1 and output.iloc[col, row] >= 0.5: accuracy += 1accuracy = accuracy/len(X)
準確度是72%。我相信,準確度會更高。因為花費了很多時間,所以我沒有重新執行演算法。
如果您正在執行此程式,請隨時嘗試更多的紀元,並在註釋部分中告知我您的準確度。
除了梯度下降方法外,您還可以使用已經為您內建的最佳化功能。
在這種方法中,您可以使用最佳化函式來最佳化演算法的theta。這是一種更快的方法。
具有最佳化功能的實現1.我們將使用與以前相同的資料集。如果使用相同的筆記本,請使用其他名稱匯入資料集:
xls = pd.ExcelFile('ex3d1.xlsx')df = pd.read_excel(xls, 'X', header=None)
2.我們仍然需要為df中的偏差項新增一列全為1的列。
X = np.c_[np.ones((df.shape[0], 1)), df]
3.匯入" y"的資料。
y = pd.read_excel(xls, 'y', header=None)
由於這是一個DataFrame,因此只需將列零作為一個序列並將其設為二維以將維與X的維匹配。
y = y[0]y = y[:, np.newaxis]
在這裡," y"只有一列。將其設為10列,以供10個班級使用。每列將處理一個類。例如,當我們處理類10時,我們將保留10的位置,並將其餘值替換為零。這是函式y_change,它將使用y本身和一個類(例如3)。然後它將用其他所有類將1替換為3,將其替換為0。此功能將在以後的步驟中很快使用。
def y_change(y, cl): y_pr=[] for i in range(0, len(y)): if y[i] == cl: y_pr.append(1) else: y_pr.append(0) return y_pr
資料準備完成。現在開發模型:
4.定義假設函式。這與以前的方法相同。
def hypothesis(X, theta): z = np.dot(X, theta) return 1/(1+np.exp(-(z)))
5.開發成本函式。此方法也與以前的方法相同:
def cost_function(theta, X, y): m = X.shape[0] y1 = hypothesis(X, theta) return -(1/len(X)) * np.sum(y*np.log(y1) + (1-y)*np.log(1-y1))
6.定義漸變。這是不同的。此函式定義如何更新theta。
def gradient(theta, X, y): m = X.shape[0] y1 = hypothesis(X, theta) return (1/m) * np.dot(X.T, y1 - y)
7.現在,匯入最佳化函式並初始化theta。我將零作為初始theta值。任何其他值也應該起作用。
from scipy.optimize import minimize, fmin_tnctheta = np.zeros((X.shape[1], 1))
8.讓我們做一個擬合函式,將X,y和theta作為輸入。它將使用最佳化函式併為我們輸出最佳化的theta。
它採用以下三個引數:
i。需要最小化的功能
ii。要最佳化的引數,
iii。用於最佳化的引數。
在此示例中,應將成本函式最小化,並且為此需要最佳化theta。輸入和輸出變數X和y是要使用的引數。
該最佳化函式採用另一個引數,即漸變。但這是可選的。在這裡,我們有一個用於漸變的公式或函式。因此,我們正在透過它。
def fit(X, y, theta): opt_weigths = fmin_tnc(func=cost_function, x0=theta, fprime=gradient, args=(X, y.flatten())) return opt_weigths[0]
9.使用這種擬合方法來找到最佳化的theta。我們必須分別為每個類最佳化theta。讓我們開發一個函式,其中對於每個類,將在步驟3中使用y_change方法相應地修改" y"。
def find_param(X, y, theta): y_uniq = list(set(y.flatten())) theta_list = [] for i in y_uniq: y_tr = pd.Series(y_change(y, i)) y_tr = y_tr[:, np.newaxis] theta1 = fit(X, y, theta) theta_list.append(theta1) return theta_list
使用此方法找到最終theta
theta_list = find_param(X, y, theta)
10.現在是時候預測輸出了。我們還必須單獨預測類別。
def predict(theta_list, x, y): y_uniq = list(set(y.flatten())) y_hat = [0]*len(y) for i in range(0, len(y_uniq)): y_tr = y_change(y, y_uniq[i]) y1 = hypothesis(X, theta_list[i]) for k in range(0, len(y)): if y_tr[k] == 1 and y1[k] >= 0.5: y_hat[k] = y_uniq[i] return y_hat
使用上面的預測方法並計算預測輸出y_hat:
y_hat = predict(theta_list, X, y)
11.計算精度
accuracy=0for i in range(0, len(y)): if y_hat[i] == y.flatten()[i]: accuracy += 1print(accuracy/len(df)*100)
此過程可提供100%的準確性。現在。您可以自己決定要在專案中使用哪種邏輯迴歸方法。
本文還使用神經網路解決了相同的問題。