这篇教程逻辑回归的原理及Python实现写得很实用,希望能帮到您。完整实现代码请参考本人的p...哦不是...github:regression_base.py logistic_regression.py logistic_regression_example.py
1. 原理篇
我们用人话而不是大段的数学公式来讲讲逻辑回归是怎么一回事。
1.1 梯度下降法
请参考我的另一篇文章,在这里就不赘述。链接如下:
李小文:梯度下降的原理及Python实现 zhuanlan.zhihu.com
1.2 线性回归
请参考我的另一篇文章,在这里就不赘述。链接如下:
李小文:线性回归的原理及Python实现 zhuanlan.zhihu.com
1.3 Sigmoid函数
Sigmoid函数的表达式是:
不难得出:
所以,Sigmoid函数的值域是(0, 1),导数为y * (1 - y)
1.4 线性回归与逻辑回归
回归问题的值域是(-∞, +∞),用线性回归可以进行预测。而分类问题的值域是[0, 1],显然不可以直接用线性回归来预测这类问题。如果把线性回归的输出结果外面再套一层Sigmoid函数,正好可以让值域落在0和1之间,这样的算法就是逻辑回归。
1.5 最小二乘法
那么逻辑回归的损失函数是什么呢,根据之前线性回归的经验。 用MSE作为损失函数,有 网上很多文章都说这个函数是非凸的,不可以用梯度下降来优化,为什么非凸也没见人给出个证明。我一开始是不信的,后来对损失函数求了二阶导之后...发现求导太麻烦了,所以我还是信了吧。
1.6 极大似然估计
既然不能用最小二乘法,那么肯定是有方法求解的,极大似然估计闪亮登场。前方小段数学公式低能预警: 线性函数 1. Sigmoid函数 2. 似然函数 3. 对似然函数两边取对数的负值 4. 对1式求导 5. 对2式求导 6. 对3式求导 7. 8.
根据5, 6, 7式: 9.
根据6, 7, 8式: 10.
注:有的同学会纠结为什么没有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实现