1、算法思想線性回歸可以對數(shù)據(jù)進行線性擬合,擬合后的模型可以輸出連續(xù)的值。由于它沒有范圍,因此不適合與分類問題。邏輯回歸用于離散變量的分類問題,其輸出值為屬于某一類的概率,主要用于類的判別。 2、算法推導2.1 邏輯回歸對于線性回歸的預測函數(shù)為: 其中, ![]() 圖1. sigmoid函數(shù) ![]() 圖2. 邏輯回歸示意圖 由圖1所示: 當 當 因此,函數(shù)的輸出值在0-1之間。 對于邏輯回歸: 當 當 因此,預測輸出 例如,對于給定的 2.2 損失函數(shù)對于線性回歸模型,我們定義的代價函數(shù)是所有模型誤差的平方和。理論上來說,我們也可以對邏輯回歸模型沿用這個定義,但是問題在于,當我們將下述公式 帶入到線性回歸的損失函數(shù)中會得到圖3. 非凸函數(shù),梯度下降法會得到局部最小值。因此,需要重新設計損失函數(shù)。 ![]() 圖3. 非凸函數(shù) 采用BCE (Binary Cross Entropy)二分類交叉熵損失函數(shù)。 其中,
為類別1的真實值, 因此: 當 import numpy as npimport seabornimport matplotlib.pyplot as pltx = np.arange(0.1, 1, .01)y = -np.log(x)seaborn.lineplot(x=x, y=y)plt.show() ![]() 圖4. 類別1損失函數(shù) 由圖4類別1的損失函數(shù),隨著預測值 當y=0時,
![]() 圖5. 類別0損失函數(shù) 由圖5類別0的損失函數(shù),隨著預測值 2.3 求解方法![]() ![]() ?詳細推導如下: ![]() 可以使用梯度下降法對參數(shù)進行更新 3、算法實現(xiàn)![]() ?代碼如下: (1)logistic_regression.py # -*- coding: utf-8 -*-import numpy as npclass LogisticRegression(object): def __init__(self, learning_rate=0.1, max_iter=100, seed=None): self.seed = seed self.lr = learning_rate self.max_iter = max_iter def fit(self, x, y): np.random.seed(self.seed) self.w = np.random.normal(loc=0.0, scale=1.0, size=x.shape[1]) self.b = np.random.normal(loc=0.0, scale=1.0) self.x = x self.y = y for i in range(self.max_iter): self._update_step() # print('loss: \t{}'.format(self.loss())) # print('score: \t{}'.format(self.score())) # print('w: \t{}'.format(self.w)) # print('b: \t{}'.format(self.b)) def _sigmoid(self, z): return 1.0 / (1.0 + np.exp(-z)) def _f(self, x, w, b): z = x.dot(w) + b return self._sigmoid(z) def predict_proba(self, x=None): if x is None: x = self.x y_pred = self._f(x, self.w, self.b) return y_pred def predict(self, x=None): if x is None: x = self.x y_pred_proba = self._f(x, self.w, self.b) y_pred = np.array([0 if y_pred_proba[i] < 0.5 else 1 for i in range(len(y_pred_proba))]) return y_pred def score(self, y_true=None, y_pred=None): if y_true is None or y_pred is None: y_true = self.y y_pred = self.predict() acc = np.mean([1 if y_true[i] == y_pred[i] else 0 for i in range(len(y_true))]) return acc def loss(self, y_true=None, y_pred_proba=None): if y_true is None or y_pred_proba is None: y_true = self.y y_pred_proba = self.predict_proba() return np.mean(-1.0 * (y_true * np.log(y_pred_proba) + (1.0 - y_true) * np.log(1.0 - y_pred_proba))) def _calc_gradient(self): y_pred = self.predict() d_w = (y_pred - self.y).dot(self.x) / len(self.y) d_b = np.mean(y_pred - self.y) return d_w, d_b def _update_step(self): d_w, d_b = self._calc_gradient() self.w = self.w - self.lr * d_w self.b = self.b - self.lr * d_b return self.w, self.b (2)train_test_lr.py
|
|