机器学习-最全LR逻辑回归原理以及python代码实现

简介

逻辑回归是一种分类模型,多用于二分类,以下讨论二分类情况。
逻辑回归是一种广义线性回归模型,它与传统线性回归的区别是,传统线性回归直接将 w x + b wx+b wx+b作为因变量,而逻辑回归将 w x + b wx+b wx+bSigmoid后激活的值作为因变量,可以将线性函数转化为概率:
P ( y = 1 ∣ x ) = 1 1 + e x p [ − ( w x + b ) ] ( 1 ) P(y=1|x)=\frac{1}{1+exp[-(wx+b)]} \qquad (1) P(y=1x)=1+exp[(wx+b)]1(1)
P ( y = 1 ∣ x ) = e x p ( w x + b ) 1 + e x p ( w x + b ) ( 2 ) P(y=1|x)=\frac{exp(wx+b)}{1+exp(wx+b)} \qquad (2) P(y=1x)=1+exp(wx+b)exp(wx+b)(2)
若将y视为事件发生的概率,1-y为反例发生的概率,这时,线性函数的值越接近正无穷,概率就越接近1,越接近负无穷,概率值就越接近0,这样的模型就是逻辑回归模型。
注意:为什么使用Sigmoid激活:1. 满足统计的最大熵模型
2. Sigmoid函数是平滑的,而且任意阶可导,一阶二阶导数可以直接由函数值得到不用进行求导,计算速度快,这在实现中很实用。

对于逻辑回归而言,输出Y=1的对数几率是X的线性模型:
l o g P ( Y = 1 ∣ x ) 1 − P ( Y = 1 ∣ x ) = w x + b ( 3 ) log\frac{P(Y=1|x)}{1-P(Y=1|x)}=wx+b \qquad (3) log1P(Y=1x)P(Y=1x)=wx+b(3)

模型参数估计

由于逻辑回归模型假设样本服从伯努利分布,则可以写出模型的对数似然函数,然后应用极大似然估计求解参数。
假设 P ( Y = 1 ∣ x ) = π ( x ) P(Y=1|x)=\pi(x) P(Y=1x)=π(x),则 P ( Y = 0 ∣ x ) = 1 − π ( x ) P(Y=0|x)=1-\pi(x) P(Y=0x)=1π(x)
似然函数为:
∏ i = 1 N [ π ( x i ) ] y i [ 1 − π ( x i ) ] 1 − y i \prod_{i=1}^{N}[\pi(x_i)]^{y_i}[1-\pi(x_i)]^{1-y_i} i=1N[π(xi)]yi[1π(xi)]1yi
对数似然函数为:
L ( w , b ) = ∑ i = 1 N [ y i l o g π ( x i ) + ( 1 − y i ) l o g ( 1 − π ( x i ) ) ] = ∑ i = 1 N [ y i l o g π ( x i ) 1 − π ( x i ) + l o g ( 1 − π ( x i ) ) ] = ∑ i = 1 N [ y i l o g π ( x i ) 1 − π ( x i ) + l o g ( 1 − π ( x i ) ) ] ( 4 ) L(w,b)=\sum_{i=1}^{N}[y_ilog\pi(x_i)+(1-y_i)log(1-\pi(x_i))]\\ =\sum_{i=1}^{N}[y_ilog\frac{\pi(x_i)}{1-\pi(x_i)}+log(1-\pi(x_i))]\\ =\sum_{i=1}^{N}[y_ilog\frac{\pi(x_i)}{1-\pi(x_i)}+log(1-\pi(x_i))] \qquad (4) L(w,b)=i=1N[yilogπ(xi)+(1yi)log(1π(xi))]=i=1N[yilog1π(xi)π(xi)+log(1π(xi))]=i=1N[yilog1π(xi)π(xi)+log(1π(xi))](4)
将(3)带入(4)得:
L ( w , b ) = ∑ i = 1 N [ y i ∗ ( w x i + b ) − l o g ( 1 + e x p ( w x i + b ) ) ] L(w,b)=\sum_{i=1}^{N}[y_i*(wx_i+b)-log(1+exp(wx_i+b))] L(w,b)=i=1N[yi(wxi+b)log(1+exp(wxi+b))]
求出对数似然函数后,我们对其进行极大似然估计,及对 − L ( w , b ) -L(w,b) L(w,b)进行梯度下降,即可求出模型参数
有趣的是,我们对 L ( w , b ) L(w,b) L(w,b)进行求导:
∂ L ∂ w = ∑ i = 1 N [ y i ∗ x i − x i e x p ( w x i + b ) ( 1 + e x p ( w x i + b ) ) ] = ∑ i = 1 N x i ∗ [ y i − π ( x i ) ] = − ∑ i = 1 N x i ∗ e r r o r \frac{\partial{L}}{\partial{w}}=\sum_{i=1}^{N}[y_i*x_i-x_i\frac{exp(wx_i+b)}{(1+exp(wx_i+b))}] \\=\sum_{i=1}^{N}x_i*[y_i-\pi(x_i)] \\=-\sum_{i=1}^{N}x_i*error wL=i=1N[yixixi(1+exp(wxi+b))exp(wxi+b)]=i=1Nxi[yiπ(xi)]=i=1Nxierror
∂ L ∂ b = ∑ i = 1 N [ y i − e x p ( w x i + b ) ( 1 + e x p ( w x i + b ) ) ] = ∑ i = 1 N [ y i − π ( x i ) ] = − ∑ i = 1 N e r r o r \frac{\partial{L}}{\partial{b}}=\sum_{i=1}^{N}[y_i-\frac{exp(wx_i+b)}{(1+exp(wx_i+b))}] \\=\sum_{i=1}^{N}[y_i-\pi(x_i)] \\=-\sum_{i=1}^{N}error bL=i=1N[yi(1+exp(wxi+b))exp(wxi+b)]=i=1N[yiπ(xi)]=i=1Nerror
这时会发现其实对数似然对 w w w b b b的导数只与 x x x和误差 e r r o r = π ( x ) − y error=\pi(x)-y error=π(x)y有关,这也是逻辑回归使用sigmoid函数的原因之一,运算速度快,因为不需要进行求导运算。

补充:1. 逻辑回归为什么不用MSE作为损失函数

  1. MSE 会有梯度消失现象
  2. MSE的导数非凸函数,求解最优解困难

证明:
δ ( x ) = s i g m o i d ( x ) = 1 1 + e − w x \delta(x)=sigmoid(x)=\frac{1}{1+e^{-wx}} δ(x)=sigmoid(x)=1+ewx1
∂ δ ( x ) ∂ w = − 1 ( 1 + e − w x ) 2 ∗ − x e − w x = x δ ( x ) ( 1 − δ ( x ) ) \frac{\partial{\delta(x)}}{\partial{w}}=-{\frac{1}{{(1+e^{-wx}})^2}}*-xe^{-wx} \\=x\delta(x)(1-\delta(x)) wδ(x)=(1+ewx)21xewx=xδ(x)(1δ(x))
均方误差的损失函数为 L = ( y − δ ( x ) ) 2 L=(y-\delta(x))^2 L=(yδ(x))2
∂ L ∂ w = 2 ( y − δ ( x ) ) ∂ δ ( x ) ∂ w = 2 x ( δ ( x ) 3 − ( 1 + y ) δ ( x ) 2 + y δ ( x ) ) \frac{\partial{L}}{\partial{w}}=2(y-\delta(x))\frac{\partial{\delta(x)}}{\partial{w}}\\ =2x(\delta(x)^3-(1+y)\delta(x)^2+y\delta(x)) wL=2(yδ(x))wδ(x)=2x(δ(x)3(1+y)δ(x)2+yδ(x))

∂ 2 L ∂ w 2 = 2 x 2 δ ( x ) ( 1 − δ ( x ) ( 3 δ ( x ) 2 − 2 ( 1 + y ) δ ( x ) + y ) \frac{\partial^2{L}}{\partial{w^2}}=2x^2\delta(x)(1-\delta(x)(3\delta(x)^2-2(1+y)\delta(x)+y) w22L=2x2δ(x)(1δ(x)(3δ(x)22(1+y)δ(x)+y)
因为 δ ( x ) ∈ ( 0 , 1 ) \delta(x)\in(0,1) δ(x)(0,1),所以 2 x 2 δ ( x ) ( 1 − δ ( x ) > 0 2x^2\delta(x)(1-\delta(x)>0 2x2δ(x)(1δ(x)>0
H ( x ) = 3 c 2 − 2 ( 1 + y ) δ ( x ) + y H(x)=3c^2-2(1+y)\delta(x)+y H(x)=3c22(1+y)δ(x)+y
因为 y ∈ [ 0 , 1 ] y \in [0,1] y[0,1]

  • y=0时, H ( x ) = 3 δ ( x ) 2 − 2 δ ( x ) = 3 δ ( x ) ( δ ( x ) − 2 3 ) H(x)=3\delta(x)^2-2\delta(x)=3\delta(x)(\delta(x)-\frac{2}{3}) H(x)=3δ(x)22δ(x)=3δ(x)(δ(x)32)
    0 < δ ( x ) < 2 3 0<\delta(x)<\frac{2}{3} 0<δ(x)<32时, H ( x ) < 0 H(x)<0 H(x)<0
  • y=1时, H ( x ) = 3 δ ( x ) 2 − 4 δ ( x ) + 1 = 3 ( δ ( x ) − 1 ) ( δ ( x ) − 1 3 ) H(x)=3\delta(x)^2-4\delta(x)+1=3(\delta(x)-1)(\delta(x)-\frac{1}{3}) H(x)=3δ(x)24δ(x)+1=3(δ(x)1)(δ(x)31)
    1 3 < δ ( x ) < 1 \frac{1}{3}<\delta(x)<1 31<δ(x)<1时, H ( x ) < 0 H(x)<0 H(x)<0

根据凸函数的定义:二阶导数非负,则L不为凸函数

2. LR为什么要将特征离散化

  1. 离散化后的特征对异常数据有很强的鲁棒性:比如一个特征是年龄>30是1,否则0。如果特征没有离散化,一个异常数据“年龄300岁”会给模型造成很大的干扰。
  2. 逻辑回归属于广义线性模型,表达能力受限;单变量离散化为N个后,每个变量有单独的权重,相当于为模型引入了非线性,能够提升模型表达能力,加大拟合。
  3. 特征离散化以后,起到了简化了逻辑回归模型的作用,降低了模型过拟合的风险。(当使用连续特征时,一个特征对应于一个权重,那么,如果这个特征权重较大,模型就会很依赖于这个特征,这个特征的一个微小变化可能会导致最终结果产生很大的变化,这样子的模型很危险,当遇到新样本的时候很可能因为对这个特征过分敏感而得到错误的分类结果,也就是泛化能力差,容易过拟合)。而使用离散特征的时候,一个特征变成了多个,权重也变为多个,那么之前连续特征对模型的影响力就被分散弱化了,从而降低了过拟合的风险

python代码及详解

定义激活函数Sigmoid

from numpy import *
def sigmoid(x):
    return 1.0/(1+exp(-x))

训练,请注意观察梯度更新的计算,非常简便,只需要求误差,再乘以数据即可:

def train_logistic_regression(data, y):
    data, y = mat(data), mat(y).transpose()
    m, n = shape(data)
    weights = ones((n, 1))  # 初始化权重 n*1
    alpha = 0.001  # 学习率
    epoches = 10000  # 训练轮数
    l2_rate = 0.00001  # L2正则化系数

    for i in range(epoches):
        l2 = linalg.norm(weights, ord=2, keepdims=True)
        pred_y = sigmoid(data*weights)  # m*1
        error = y-pred_y  # m*1
        h = data.transpose()*error  # n*1
        weights -= alpha*h+l2*l2_rate
    return weights

预测

def test_logistic_regression(train_data, y, test_data):
    W = test_logistic_regression(train_data, y)
    pred_y=sigmoid(mat(test_data)*W)
    return pred_y

加载数据:这里使用sklearn自带cancer数据集

from sklearn import datasets
from sklearn.model_selection import train_test_split

def load_data():
    cancer = datasets.load_breast_cancer()
    X = cancer.data
    y = cancer.target
    X_train, X_test, y_train, y_test = train_test_split(X, y)
    return X_train, X_test, y_train, y_test

计算准确率

# 计算准确率
def accuracy(y,pred):
    N = len(y)
    res = sum([1 for i in range(N) if y_test[i] == pred[i]])
    return res/N

函数定义好之后,运行如下代码即可得到结果:

X_train, X_test, y_train, y_test = load_data()
pred = test_logistic_regression(X_train, y_train, X_test)
print('acc',accuracy(y_test,pred))
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
逻辑回归是一种用于分类问题的机器学习算法,其原理是基于线性回归的思想,通过使用逻辑函数(也称为sigmoid函数)将预测结果映射到[0,1]之间的概率值。以下是一个使用Python实现逻辑回归的示例代码: ```python import numpy as np import matplotlib.pyplot as plt # 定义sigmoid函数 def sigmoid(z): return 1 / (1 + np.exp(-z)) # 定义损失函数 def loss(h, y): return (-y * np.log(h) - (1 - y) * np.log(1 - h)).mean() # 定义逻辑回归模型 class LogisticRegression: def __init__(self, lr=0.01, num_iter=100000, fit_intercept=True, verbose=False): self.lr = lr self.num_iter = num_iter self.fit_intercept = fit_intercept self.verbose = verbose def add_intercept(self, X): intercept = np.ones((X.shape[0], 1)) return np.concatenate((intercept, X), axis=1) def fit(self, X, y): if self.fit_intercept: X = self.add_intercept(X) # 初始化权重参数 self.theta = np.zeros(X.shape[1]) for i in range(self.num_iter): z = np.dot(X, self.theta) h = sigmoid(z) gradient = np.dot(X.T, (h - y)) / y.size self.theta -= self.lr * gradient if(self.verbose == True and i % 10000 == 0): z = np.dot(X, self.theta) h = sigmoid(z) print(f'loss: {loss(h, y)}') def predict_prob(self, X): if self.fit_intercept: X = self.add_intercept(X) return sigmoid(np.dot(X, self.theta)) def predict(self, X, threshold=0.5): return self.predict_prob(X) >= threshold # 示例:使用逻辑回归对二分类数据进行训练和预测 from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split # 生成二分类数据集 X, y = make_classification(n_samples=100, n_features=2, n_informative=2, n_redundant=0, random_state=42) # 将数据集划分为训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 创建逻辑回归模型进行训练 model = LogisticRegression(lr=0.1, num_iter=300000) model.fit(X_train, y_train) # 在测试集上进行预测 y_pred = model.predict(X_test) # 计算准确率 accuracy = (y_pred == y_test).mean() print(f'Accuracy: {accuracy}') ``` 这段代码首先定义了sigmoid函数和损失函数,然后实现了一个LogisticRegression类,其包含了fit方法用于训练模型,以及predict_prob和predict方法用于预测。最后,示例代码使用sklearn库生成了一个二分类数据集,将数据集划分为训练集和测试集,并使用逻辑回归模型进行训练和预测。最后计算了预测的准确率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值