逻辑回归原理解析及python实现

       前两篇讲了线性回归和感知机,铺垫已经做好了,现在终于可以讲讲逻辑回归了。通过之前的博客我们知道,感知机是线性模型在分类问题上的尝试与改进,那么逻辑回归可以看做是感知机的优化,不了解的小伙伴可以参考博客线性回归感知机

引言

      为了实现分类的功能,感知机通过sign函数将线性模型f(x)=wx+b的输出y映射成1和-1,sign函数如下

                                                              

    sign函数是一个非连续的阶跃函数,它有两个问题:

  • 由于是非连续函数,那么模型的目标函数就无法进行微分(感知机是剥离了sign函数设计的目标函数)
  • 阶跃函数太过于粗暴,比如y=0.01和y=1最后都判断为同一类,但是明显y=0.01的样本点更接近超平面,也更容易分错;再比如y=0.01和y=-0.01最终分为两类不同类别,但是者两个样本点都离超平面很近,超平面稍有波动,者两个样本点就可能变成同一类了

逻辑回归原理

        逻辑回归模型是为了将线性回归模型应用于分类任务而设计的,线性函数的输出值y是一个具有一定范围的连续数值,那么我们能不能设计一种激活函数,既能保证对y处理后的结果任然连续(解决不可微),又能对不同大小的y有不同的评价(解决过于粗暴),比如接近超平面的程度、属于某类别的概率等。

  • 激活函数

       逻辑回归模型中设计了Sigmoid函数,该函数将y映射到[0,1]这个连续的空间中,能同时满足以上两点要求。在分类任务中,Sigmoid函数的输出值代表判断为某类别的概率,以z=0.5作为分界点,大于0.5判定为一个类别,小于0.5判断为另一个类别。假现在要判断x是否属于类别A,y越大z越接近1,表示为类A的概率越大;y越小z越接近0,表示为类A的概率越小,y接近0时z接近0.5,表示判断为类A不太有把握。

                                                                                  z=\frac{1}{1+e^{-y}}

                                              

  • 数学模型

       根据线性模型y=wx+b,Sigmoid函数z=\frac{1}{1+e^{-y}},得到最终的模型f(x)=\frac{1}{1+e^{-(wx+b)}}

损失函数

       现在是模型已经知道但是模型的参数未知,而且Sigmoid函数将输出变成概率,因此特别适合使用极大似然估计的原理求解模型。

首先需要设计似然函数。假设类别标签为0和1,则有

                                       P(y=1|x,w,b)=f(x)

                                       P(y=0|x,w,b)=1-f(x)

       将两个式子合并得到P(y|x,w,b)=f(x)^{y}(1-f(x))^{1-y},根据极大似然估计的原理(可以参考博客极大似然估计)可以设计损失函数如下

                                 L(w,b)=\prod_{i=1}^{m}p(y_{i}|x_{i},w,b)=\prod_{i=1}^{m}f(x_{i})^{y_{i}}(1-f(x_{i}))^{1-y_{i}}

      为了方便求导,同时ln函数不会改变单调性,所以对等式取对数将乘法运算转化为加法运算;原本的优化目标是最大化损失函数(对应于梯度上升法),但是大家习惯于最小化损失函数(对应梯度下降法),所以在公式前加一个负号,得到最终的损失函数:

                               l(w,b)=-\frac{1}{m}\sum_{i=1}^{m}y_{i}\ln f(x_{i})+(1-y_{i})\ln (1-f(x_{i}))

     有了损失函数,就可以利用梯度下降法来求模型的参数了,前面几篇博客有讲解,这里就不展开了。

注:其实上述损失函数还有另外一个名字:交叉熵损失函数,是不是很神奇?其实极大似然和交叉熵、最大熵的数学原理都有相通之处

代码实现

def GradientDescent(X, Y, lr, iters):
    '''
    全局梯度下降法,每次迭代以整个数据集更新参数
    根据线性回归的损失函数求得梯度G=X.T*(exp(X*theta)/(exp(X*theta)+1)-Y)
    :param X: (m,n+1) m个数据,每个数据n维 每个数据n维,在数据前加一列1方便计算wx+b
    :param Y: (m,1) m个数据对应的输出结果
    :param lr:  学习率
    :param iters:  迭代次数
    :return: theta: (n+1,1) 权重(b+w)
    '''

    sample_num = X.shape[0]
    dim = X.shape[1]

    theta = np.zeros((dim, 1))  # (n+1,1)

    XT = X.transpose()  # 表示X的转置
    for i in range(iters):
        Y_ = np.exp(np.dot(X, theta))/(np.exp(np.dot(X, theta))+1)  # 模型预测值
        gradient = np.dot(XT, Y_-Y)/sample_num  # theta的梯度 (n+1,1)

        # 梯度更新
        theta = theta - lr*gradient

    return theta


def logisticRegression(data, label, lr=0.1, iters=200):

    sample_num = data.shape[0]
    data = np.hstack((np.ones((sample_num, 1)), data))  # 在数据前加一列1方便计算wx+b

    theta = GradientDescent(data, label, lr, iters)

    return theta


def predict(x, theta):
    x = np.hstack((np.ones((1)), x))
    pre = np.exp(np.dot(x, theta))/(np.exp(np.dot(x, theta))+1)

    if pre >= 0.5:
        return 1

    return 0


def test(data, label, theta):
    sample_num = data.shape[0]

    errorcount = 0.0
    for i in range(sample_num):
        x = data[i]
        if label[i] != predict(x, theta):
            errorcount += 1

    accuracy = 1 - errorcount/sample_num

    return accuracy


if __name__ == '__main__':
    #加载训练集和验证集
    traindata, trainlabel = loadData('../Mnist/mnist_train.csv')
    evaldata, evallabel = loadData('../Mnist/mnist_test.csv')

    theta = logisticRegression(traindata, trainlabel)

    accuracy = test(evaldata, evallabel, theta)
    print('accuracy rate is:', accuracy)

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值