逻辑回归(LR)公式推导及代码实现

逻辑回归是用来解决分类问题用的,与线性回归不同的是,逻辑回归输出的不是具体的值,而是一个概率。除去了sigmoid函数的逻辑归回和线性回归几乎是一样的。

Logistic Regression 虽然被称为回归,但其实际上是分类模型,并常用于二分类。Logistic Regression 因其简单可解释性好可并行化、可解释强深受工业界喜爱。

Logistic 回归的本质是:假设数据服从这个分布,然后使用极大似然估计做参数的估计。

逻辑回归假设数据服从伯努利分布,通过极大化似然函数方法,运用梯度下降来求解参数,来达到将数据二分目的。

构造hypothesis

逻辑回归的 H H H可以看做是一个线性回归方程的结果经过一个sigmoid函数得到的结果(为正样本的概率),逻辑回归的假设函数如下:
h θ ( x ) = g ( θ T x ) = 1 1 + e − θ T x h _ { \theta } ( x ) = g \left( \theta ^ { T } x \right) = \frac { 1 } { 1 + e ^ { - \theta ^ { T } x } } hθ(x)=g(θTx)=1+eθTx1

函数 h θ ( x ) h _ { \theta } ( x ) hθ(x) 表示样本被预测为正例 1 1 1 的概率,我们很容易的得到样本被预测为正例和负例的概率如下:
P ( y = 1 ∣ x ;   θ ) = h θ ( x ) P ( y = 0 ∣ x ;   θ ) = 1 − h θ ( x ) \begin{array} { l } P ( y = 1 | x ;\ \theta ) = h_{\theta} ( x ) \\ P ( y = 0 | x ; \ \theta ) = 1 - h _ { \theta } ( x ) \end{array} P(y=1∣x; θ)=hθ(x)P(y=0∣x; θ)=1hθ(x)

上式可以合并为一个式子:(预测结果的概率表示)
P ( y ∣ x ; θ ) = ( h θ ( x ) ) y ( 1 − h θ ( x ) ) 1 − y P ( y | x ; \theta ) = \left( h _ { \theta } ( x ) \right) ^ { y } \left( 1 - h _ { \theta } ( x ) \right) ^ { 1 - y } P(yx;θ)=(hθ(x))y(1hθ(x))1y

构造损失函数

我们对“预测结果的概率表示”取似然函数,取似然函数就是将模型对样本的概率预测值累乘起来。得到如下的似然函数
L ( θ ) = ∏ i = 1 m P ( y ( i ) ∣ x ( i ) ; θ ) = ∏ i = 1 m ( h θ ( x ( i ) ) ) y ( i ) ( 1 − h θ ( x ( i ) ) ) 1 − y ( i ) L ( \theta ) = \prod _ { i = 1 } ^ { m } P \left( y ^ { ( i ) } | x ^ { ( i ) } ; \theta \right) = \prod _ { i = 1 } ^ { m } \left( h _ { \theta } \left( x ^ { ( i ) } \right) \right) ^ { y ^ { ( i ) } } \left( 1 - h _ { \theta } \left( x ^ { ( i ) } \right) \right) ^ { 1 - y ^ { ( i ) } } L(θ)=i=1mP(y(i)x(i);θ)=i=1m(hθ(x(i)))y(i)(1hθ(x(i)))1y(i)

由于该式比较麻烦涉及连乘法,所以我们对其去加对数操作得到对数似然函数

上述利用的是最大似然估计原理:极大似然估计就是利用已知的样本分布,找到最有可能(即最大概率)导致这种分布的参数值;或者说什么样的参数才能使我们观测到目前这组数据的概率最大。
l ( θ ) = log ⁡ L ( θ ) = ∑ i = 1 m ( y ( i ) log ⁡ h θ ( x ( i ) ) + ( 1 − y ( i ) ) log ⁡ ( 1 − h θ ( x ( i ) ) ) ) l ( \theta ) = \log L ( \theta ) = \sum _ { i = 1 } ^ { m } \left( y ^ { ( i ) } \log h _ { \theta } \left( x ^ { ( i ) } \right) + \left( 1 - y ^ { ( i ) } \right) \log \left( 1 - h _ { \theta } \left( x ^ { ( i ) } \right) \right) \right) l(θ)=logL(θ)=i=1m(y(i)loghθ(x(i))+(1y(i))log(1hθ(x(i))))

当似然函数求得最大值时,模型参数能够最大可能的满足当前的样本,求最大值使用梯度向上法,我们可以对似然函数加个负号,通过求等价问题的最小值来求原问题的最大值,这样我们就可以使用极大似然估计法。(注意这里还多加了个 1 m \frac { 1 } { m } m1
J ( θ ) = − 1 m l ( θ ) J ( \theta ) = - \frac { 1 } { m } l ( \theta ) J(θ)=m1l(θ)

这样我们就能得到损失函数的最终形式
J ( θ ) = − 1 m ∑ i = 1 m ( y ( i ) log ⁡ h θ ( x ( i ) ) + ( 1 − y ( i ) ) log ⁡ ( 1 − h θ ( x ( i ) ) ) ) J ( \theta ) = - \frac { 1 } { m } \sum _ { i = 1 } ^ { m } \left( y ^ { ( i ) } \log h _ { \theta } \left( x ^ { ( i ) } \right) + \left( 1 - y ^ { ( i ) } \right) \log \left( 1 - h _ { \theta } \left( x ^ { ( i ) } \right) \right) \right) J(θ)=m1i=1m(y(i)loghθ(x(i))+(1y(i))log(1hθ(x(i))))

即等价于:
cost ⁡ ( h θ ( x ) ,   y ) = { − log ⁡ ( h θ ( x ) )  if  y = 1 − log ⁡ ( 1 − h θ ( x ) )  if  y = 0 \operatorname { cost } ( h _ { \theta } ( x ) ,\ y ) = \left\{ \begin{array} { l l } - \log \left( h _ { \theta } ( x ) \right) & \text { if } y = 1 \\ - \log \left( 1 - h _ { \theta } ( x ) \right) & \text { if } y = 0 \end{array} \right. cost(hθ(x), y)={log(hθ(x))log(1hθ(x)) if y=1 if y=0

通过“梯度下降法”求参数 θ \theta θ 的更新式

我们下图为推导式,面试推导的时候可以不写下标(假设我们使用随机梯度下降法),这样可以使推导式更简洁。

求梯度
在这里插入图片描述
这里需要提一下的是,sigmoid函数有如下性质,在上述推导的第三行中可以看到:
S ′ ( x ) = e − x ( 1 + e − x ) 2 = S ( x ) ( 1 − S ( x ) ) S ^ { \prime } ( x ) = \frac { e ^ { - x } } { \left( 1 + e ^ { - x } \right) ^ { 2 } } = S ( x ) ( 1 - S ( x ) ) S(x)=(1+ex)2ex=S(x)(1S(x))

θ更新式:α 为学习率
θ j : = θ j − α 1 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) x j ( i ) \theta _ { j } : = \theta _ { j } - \alpha \frac { 1 } { m } \sum _ { i = 1 } ^ { m } \left( h _ { \theta } \left( x ^ { ( i ) } \right) - y ^ { ( i ) } \right) x _ { j } ^ { ( i ) } θj:=θjαm1i=1m(hθ(x(i))y(i))xj(i)

总结:LR在确定了模型的形式后,通过最大似然估计法来实现最小散度从而求出模型参数。

代码实现

向量化:向量化是使用矩阵计算来代替for循环,以简化计算过程,提高效率。

# -*- coding: utf-8 -*-
from numpy import *
from matplotlib import pyplot as plt


def plot_best_fit(wei, data_set, label):
    weights = wei
    data_set = array(data_set)
    n = shape(data_set)[0]
    xcourd1 = []; ycourd1 = []
    xcourd2 = []; ycourd2 = []
    for i in range(n):
        if int(label[i]) == 1:
            xcourd1.append(data_set[i, 1]); ycourd1.append(data_set[i, 2])
        else:
            xcourd2.append(data_set[i, 1]); ycourd2.append(data_set[i, 2])
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(xcourd1, ycourd1, s=30, c='red', marker='s')
    ax.scatter(xcourd2, ycourd2, s=30, c='green')
    x = arange(-3.0, 3.0, 0.1)
    y = (-weights[0] - weights[1]*x)/weights[2]
    ax.plot(x, y)
    plt.xlabel('X1'); plt.ylabel('X2')
    plt.show()

def load_data():
    data_set = []
    label = []
    fr = open('./text.txt')
    for line in fr.readlines():
        line = line.strip().split()
        data_set.append([1.0, float(line[0]), float(line[1])])
        label.append(int(line[2]))
    return data_set, label


def sigmoid(x):
    return 1.0 / (1 + exp(-x))

# 梯度下降算法               GD
def train(data_set, label):
    data_matrix = mat(data_set)
    label = mat(label).transpose()
    m, n = shape(data_matrix)
    alpha = 0.001
    max_cycles = 500
    weights = ones((n, 1))
    for k in range(max_cycles):
        h = sigmoid(data_matrix*weights)
        error = h - label
        weights = weights - alpha * data_matrix.transpose() * error
    return weights

# on line to study         SGD
def stoc_grad_descent(data_set, label):
    m, n = shape(data_set)
    alpha = 0.01
    weights = ones(n)
    for i in range(m):
        h = sigmoid(sum(data_set[i]*weights))
        error = h - label[i]
        weights = weights - alpha * error * data_set[i]
    return weights

# on line to study prove
def prove_grad_ascent(data_set, label, num_iter=450):
    m, n = shape(data_set)
    weights = ones(n)
    for j in range(num_iter):
        data_index = range(m)
        for i in range(m):
            alpha = 4/(1.0+j+i)+0.01    # prevent swings
            # choose a random value to prevent periodic swings
            rand_index = int(random.uniform(0, len(data_index)))
            h = sigmoid(sum(data_set[rand_index]*weights))
            error = label[rand_index] - h
            weights = weights + alpha * error * data_set[rand_index]
            del data_index[rand_index]
    return weights

if __name__ == "__main__":
    data_set, label = load_data()
    #print label
    #weights = train(array(data_set), label)
    #weights = stoc_grad_ascent(array(data_set), label)
    weights = prove_grad_ascent(array(data_set), label)
    plot_best_fit(weights, data_set, label)

References

  • https://blog.csdn.net/dpengwang/article/details/86746233
  • https://www.jianshu.com/p/471b2fd570a3
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RBM(Restricted Boltzmann Machine)是一种基于能量的概率模型,常用于无监督学习任务中。下面给出RBM的公式推导及Matlab代码实现。 一、RBM的公式推导 RBM是一个两层神经网络,包括输入层和隐藏层。假设输入层有m个节点,隐藏层有n个节点。RBM的网络结构如下图所示: ![RBM网络结构](https://img-blog.csdn.net/20180320235415595?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGl1bmd5b25n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/q/80) RBM的能量函数为: $$ E(v,h)=-\sum_{i=1}^{m}\sum_{j=1}^{n}v_iw_{ij}h_j-\sum_{i=1}^{m}v_ib_i-\sum_{j=1}^{n}h_jc_j $$ 其中,$v$表示输入层的节点状态,$h$表示隐藏层的节点状态,$w_{ij}$表示第$i$个输入节点和第$j$个隐藏节点之间的连接权重,$b_i$表示第$i$个输入节点的偏置,$c_j$表示第$j$个隐藏节点的偏置。 RBM的概率分布为: $$ P(v,h)=\frac{1}{Z}e^{-E(v,h)} $$ 其中,$Z$为归一化因子,可以表示为: $$ Z=\sum_{v}\sum_{h}e^{-E(v,h)} $$ RBM的训练目标是最大化样本出现的概率,即最大化对数似然函数。对于一个训练样本$v$,其对应的对数似然函数为: $$ \log P(v)=\log\sum_{h}e^{-E(v,h)} $$ 使用对比散度(Contrastive Divergence,CD)算法来学习RBM的参数。CD算法的核心思想是通过采样来估计对数似然函数的梯度。具体地,对于一个训练样本$v$,按照以下步骤进行: 1. 将$v$作为输入层的状态,通过前向传播计算出隐藏层的状态$h_0$; 2. 从隐藏层的概率分布中采样出一个样本$h_1$; 3. 将$h_1$作为隐藏层的状态,通过反向传播计算出输入层的状态$v_1$; 4. 从输入层的概率分布中采样出一个样本$v_2$; 5. 将$v_2$作为输入层的状态,通过前向传播计算出隐藏层的状态$h_2$。 最后,更新参数$w_{ij}$、$b_i$和$c_j$,使得对数似然函数的梯度最大化。 具体地,对于一个样本$v$,其对应的参数梯度为: $$ \frac{\partial\log P(v)}{\partial w_{ij}}=v_ih_{0j}-v_ih_{1j} $$ $$ \frac{\partial\log P(v)}{\partial b_i}=v_i-v_{2i} $$ $$ \frac{\partial\log P(v)}{\partial c_j}=h_{0j}-h_{2j} $$ 其中,$h_{0}$、$h_{1}$和$h_{2}$分别表示通过前向传播计算出的隐藏层状态。 二、RBM的Matlab代码实现 以下是使用Matlab实现RBM的代码示例,其中使用了CD算法来训练RBM模型。 ```matlab % RBM的Matlab代码实现 % 数据集:MNIST手写数字数据集,训练集60000个样本,测试集10000个样本 % 神经网络结构:输入层784个节点,隐藏层100个节点 % CD算法的参数:k=1,学习率lr=0.1 % 加载数据集 load mnist_train_data.mat load mnist_test_data.mat % 初始化RBM模型参数 input_size = 784; % 输入层节点数 hidden_size = 100; % 隐藏层节点数 w = 0.1 * randn(input_size, hidden_size); % 输入层和隐藏层之间的连接权重 b = zeros(1, input_size); % 输入层的偏置 c = zeros(1, hidden_size); % 隐藏层的偏置 % 训练RBM模型 batch_size = 100; % 每个batch的样本数 num_epochs = 10; % 迭代次数 k = 1; % CD算法的参数 lr = 0.1; % 学习率 % 对训练集进行预处理,将像素值归一化到[0,1]之间 train_data = double(train_data) / 255; for epoch = 1:num_epochs % 迭代训练 for batch = 1:floor(size(train_data, 1) / batch_size) % 逐个batch训练 % 选取一个batch的样本 batch_data = train_data((batch - 1) * batch_size + 1 : batch * batch_size, :); % 正向传播 h0_prob = sigmoid(batch_data * w + repmat(c, batch_size, 1)); % 隐藏层的概率分布 h0_sample = double(h0_prob > rand(size(h0_prob))); % 从概率分布中采样出隐藏层的状态 v1_prob = sigmoid(h0_sample * w' + repmat(b, batch_size, 1)); % 重构输入层的概率分布 v1_sample = double(v1_prob > rand(size(v1_prob))); % 从概率分布中采样出重构的输入层状态 % 反向传播 h1_prob = sigmoid(v1_sample * w + repmat(c, batch_size, 1)); % 重构的隐藏层的概率分布 h1_sample = double(h1_prob > rand(size(h1_prob))); % 从概率分布中采样出重构的隐藏层状态 % 计算参数梯度 w_grad = batch_data' * h0_prob - v1_sample' * h1_prob; % 输入层和隐藏层之间的连接权重的梯度 b_grad = sum(batch_data - v1_sample); % 输入层的偏置的梯度 c_grad = sum(h0_prob - h1_prob); % 隐藏层的偏置的梯度 % 更新参数 w = w + lr * w_grad / batch_size; b = b + lr * b_grad / batch_size; c = c + lr * c_grad / batch_size; end % 每个epoch结束后,计算一次对数似然函数的值 error = zeros(size(train_data, 1), 1); for i = 1:size(train_data, 1) v = train_data(i, :); h_prob = sigmoid(v * w + repmat(c, 1, 1)); % 隐藏层的概率分布 v_recon = sigmoid(h_prob * w' + repmat(b, 1, 1)); % 重构的输入层的概率分布 error(i) = -sum(v .* log(v_recon) + (1 - v) .* log(1 - v_recon)); end fprintf('Epoch %d, error = %f\n', epoch, mean(error)); end % 测试RBM模型 test_data = double(test_data) / 255; % 对测试集进行预处理 h_prob = sigmoid(test_data * w + repmat(c, size(test_data, 1), 1)); % 隐藏层的概率分布 v_recon = sigmoid(h_prob * w' + repmat(b, size(test_data, 1), 1)); % 重构的输入层的概率分布 error = -sum(sum(test_data .* log(v_recon) + (1 - test_data) .* log(1 - v_recon), 2)); % 计算对数似然函数的值 fprintf('Test error = %f\n', error); % 定义sigmoid函数 function y = sigmoid(x) y = 1 ./ (1 + exp(-x)); end ``` 参考文献: [1] Hinton G E, Salakhutdinov R R. Restricted Boltzmann machines for collaborative filtering[C]//Proceedings of the 25th international conference on Machine learning. ACM, 2008: 448-455. [2] Fischer A, Igel C. An introduction to restricted Boltzmann machines[J]. Progress in Pattern Recognition, Image Analysis, Computer Vision, and Applications, 2012, 7441: 14-36.

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值