python原理_逻辑回归的原理及Python实现

1. 原理篇

我们用人话而不是大段的数学公式来讲讲逻辑回归是怎么一回事。

1.1 梯度下降法

请参考我的另一篇文章,在这里就不赘述。链接如下:李小文:梯度下降的原理及Python实现​zhuanlan.zhihu.comv2-0ecd341a4dfc716df74147c09b17a1e3_180x120.jpg

1.2 线性回归

请参考我的另一篇文章,在这里就不赘述。链接如下:李小文:线性回归的原理及Python实现​zhuanlan.zhihu.comv2-0ecd341a4dfc716df74147c09b17a1e3_180x120.jpg

1.3 Sigmoid函数

Sigmoid函数的表达式是:

equation?tex=f%28x%29+%3D+%5CLarge%5Cfrac%7B1%7D%7B1+%2B+e%5E%7B-x%7D%7D

不难得出:

equation?tex=%5Clim%5Climits_%7Bx%5Crightarrow%7B-%5Cinfty%7D%7D%5CLarge%5Cfrac%7B1%7D%7B1+%2B+e%5E%7B-x%7D%7D%5Cnormalsize+%3D+0

equation?tex=%5Clim%5Climits_%7Bx%5Crightarrow%7B%2B%5Cinfty%7D%7D%5CLarge%5Cfrac%7B1%7D%7B1+%2B+e%5E%7B-x%7D%7D%5Cnormalsize+%3D+1

equation?tex=f%27%28x%29+%3D+f%28x%29+%2A+%281+-+f%28x%29%29

所以,Sigmoid函数的值域是(0, 1),导数为y * (1 - y)

1.4 线性回归与逻辑回归

回归问题的值域是(-∞, +∞),用线性回归可以进行预测。而分类问题的值域是[0, 1],显然不可以直接用线性回归来预测这类问题。如果把线性回归的输出结果外面再套一层Sigmoid函数,正好可以让值域落在0和1之间,这样的算法就是逻辑回归。

1.5 最小二乘法

那么逻辑回归的损失函数是什么呢,根据之前线性回归的经验。

用MSE作为损失函数,有

equation?tex=L+%3D+%5Clarge%5Cfrac%7B1%7D%7Bm%7D%5Cnormalsize%5Csum_%7B1%7D%5E%7Bm%7D%28Y_%7Bi%7D+-+%5Clarge%5Cfrac%7B1%7D%7B1+%2B+e%5E%7B-WX_%7Bi%7D+-+b%7D%7D%5Cnormalsize%29%5E2

网上很多文章都说这个函数是非凸的,不可以用梯度下降来优化,为什么非凸也没见人给出个证明。我一开始是不信的,后来对损失函数求了二阶导之后...发现求导太麻烦了,所以我还是信了吧。

1.6 极大似然估计

既然不能用最小二乘法,那么肯定是有方法求解的,极大似然估计闪亮登场。前方小段数学公式低能预警:

线性函数

1.

equation?tex=z+%3D+WX+%2B+b

Sigmoid函数

2.

equation?tex=%5Chat+y+%3D+%5Clarge%5Cfrac%7B1%7D%7B1+%2B+e%5E%7B-z%7D%7D

似然函数

3.

equation?tex=P%28Y+%7C+X%2C+W%2C+b%29+%3D+%5Cprod_%7B1%7D%5E%7Bm%7D+%5Chat+y_%7Bi%7D%5E%7By_%7Bi%7D%7D+%2A+%281-%5Chat+y_%7Bi%7D%29%5E%7B1-y_%7Bi%7D%7D

对似然函数两边取对数的负值

4.

equation?tex=L+%3D+-%5Csum_%7B1%7D%5E%7Bm%7D%28y_%7Bi%7D+%2A+log+%5Chat+y_%7Bi%7D+%2B+%281-y_%7Bi%7D%29+%2A+log%281-%5Chat+y_%7Bi%7D%29%29

对1式求导

5.

equation?tex=%5Clarge%5Cfrac%7B%5Cmathrm%7Bd%7DZ%7D%7B%5Cmathrm%7Bd%7DW%7D%5Cnormalsize%3DX

对2式求导

6.

equation?tex=%5Clarge%5Cfrac%7B%5Cmathrm%7Bd%7D%5Chat%7By%7D%7D%7B%5Cmathrm%7Bd%7Dz%7D%5Cnormalsize%3Dz+%2A+%281+-+z%29

对3式求导

7.

equation?tex=%5Clarge%5Cfrac%7B%5Cmathrm%7Bd%7DL%7D%7B%5Cmathrm%7Bd%7D%5Chat%7By%7D%7D%5Cnormalsize%3Dy%2F%5Chat%7By%7D+-+%281-y%29%2F%281-%5Chat%7By%7D%29

8.

equation?tex=%5Clarge%5Cfrac%7B%5Cmathrm%7Bd%7DZ%7D%7B%5Cmathrm%7Bd%7Db%7D%5Cnormalsize%3D1

根据5, 6, 7式:

9.

equation?tex=%5Clarge%5Cfrac%7B%5Cmathrm%7Bd%7DL%7D%7B%5Cmathrm%7Bd%7DW%7D%5Cnormalsize%3D-%5Csum%28y+-+%5Chat%7By%7D%29+%2A+X

根据6, 7, 8式:

10.

equation?tex=%5Clarge%5Cfrac%7B%5Cmathrm%7Bd%7DL%7D%7B%5Cmathrm%7Bd%7DW%7D%5Cnormalsize%3D-%28y+-+%5Chat%7By%7D%29

注:有的同学会纠结为什么没有9和10式子1/m这个常量,其实我们后来还要设置学习率,所以基本没有影响。

2. 实现篇

本人用全宇宙最简单的编程语言——Python实现了逻辑回归算法,没有依赖任何第三方库,便于学习和使用。简单说明一下实现过程,更详细的注释请参考本人github上的代码。

2.1 创建RegressionBase类

初始化,存储权重weights和偏置项bias。

class RegressionBase(object):

def __init__(self):

self.bias = None

self.weights = None

2.2 创建LogisticRegression类

初始化,继承RegressionBase类。

class LogisticRegression(RegressionBase):

def __init__(self):

RegressionBase.__init__(self)

2.3 预测一个样本

def _predict(self, Xi):

z = sum(wi * xij for wi, xij in zip(self.weights, Xi)) + self.bias

return sigmoid(z)

2.4 计算梯度

根据损失函数的一阶导数计算梯度。

def _get_gradient_delta(self, Xi, yi):

y_hat = self._predict(Xi)

bias_grad_delta = yi - y_hat

weights_grad_delta = [bias_grad_delta * Xij for Xij in Xi]

return bias_grad_delta, weights_grad_delta

2.5 批量梯度下降

正态分布初始化weights,外层循环更新参数,内层循环计算梯度。

def _batch_gradient_descent(self, X, y, lr, epochs):

m, n = len(X), len(X[0])

self.bias = 0

self.weights = [normalvariate(0, 0.01) for _ in range(n)]

for _ in range(epochs):

bias_grad = 0

weights_grad = [0 for _ in range(n)]

for i in range(m):

bias_grad_delta, weights_grad_delta = self._get_gradient_delta(

X[i], y[i])

bias_grad += bias_grad_delta

weights_grad = [w_grad + w_grad_d for w_grad, w_grad_d

in zip(weights_grad, weights_grad_delta)]

self.bias += lr * bias_grad * 2 / m

self.weights = [w + lr * w_grad * 2 / m for w,

w_grad in zip(self.weights, weights_grad)]

2.6 随机梯度下降

正态分布初始化weights,外层循环迭代epochs,内层循环随机抽样计算梯度。

def _stochastic_gradient_descent(self, X, y, lr, epochs, sample_rate):

m, n = len(X), len(X[0])

k = int(m * sample_rate)

self.bias = 0

self.weights = [normalvariate(0, 0.01) for _ in range(n)]

for _ in range(epochs):

for i in sample(range(m), k):

bias_grad, weights_grad = self._get_gradient_delta(X[i], y[i])

self.bias += lr * bias_grad

self.weights = [w + lr * w_grad for w,

w_grad in zip(self.weights, weights_grad)]

2.7 训练模型

使用批量梯度下降或随机梯度下降训练模型。

def fit(self, X, y, lr, epochs, method="batch", sample_rate=1.0):

assert method in ("batch", "stochastic")

if method == "batch":

self._batch_gradient_descent(X, y, lr, epochs)

if method == "stochastic":

self._stochastic_gradient_descent(X, y, lr, epochs, sample_rate)

2.8 预测多个样本

def predict(self, X, threshold=0.5):

return [int(self._predict(Xi) >= threshold) for Xi in X]

3 效果评估

3.1 main函数

使用著名的乳腺癌数据集,按照7:3的比例拆分为训练集和测试集,训练模型,并统计准确度。

def main():

@run_time

def batch():

print("Tesing the performance of LogisticRegression(batch)...")

clf = LogisticRegression()

clf.fit(X=X_train, y=y_train, lr=0.05, epochs=200)

model_evaluation(clf, X_test, y_test)

@run_time

def stochastic():

print("Tesing the performance of LogisticRegression(stochastic)...")

clf = LogisticRegression()

clf.fit(X=X_train, y=y_train, lr=0.01, epochs=200,

method="stochastic", sample_rate=0.5)

model_evaluation(clf, X_test, y_test)

X, y = load_breast_cancer()

X = min_max_scale(X)

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=10)

batch()

stochastic()

3.2 效果展示

批量梯度下降AUC 0.984,运行时间677.9 毫秒;

随机梯度下降AUC 0.997,运行时间437.6 毫秒。

效果还算不错~

3.3 工具函数

本人自定义了一些工具函数,可以在github上查看

utils

run_time - 测试函数运行时间

load_breast_cancer - 加载乳腺癌数据

train_test_split - 拆分训练集、测试集

model_evaluation - 计算AUC,准确度,召回率

min_max_scale - 归一化

总结

逻辑回归的原理:线性回归结合Sigmoid函数

逻辑回归的实现:加减法,for循环。线性回归的原理及Python实现全连接神经网络的原理及Python实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值