Logistic回归——李宏毅机器学习作业二

一,数据预处理

(1)将所有空值填充成0。
(2)由于倒数第一列和第二列的值相较于其他数值过大,所有除去他们自身的平均数使其拉回到相同的scale。
(3)将第2列到第58列作为feature_x,将第59列作为label_y。

将前3500作为训练集x_train(3500×57)、y_train(3500×1);后500作为验证集x_val(500×57)、y_val(500×1)。
(4)代码

    df = pd.read_csv('spam_train.csv')
    df = df.fillna(0)#将空值填充成0
    array = np.array(df)
    x = array[:,1:-1]
    x[:,-1] /= np.mean(x[:,-1])
    x[:,-2] /= np.mean(x[:,-2])
    y = array[:,-1]

    x_train,x_val = x[0:3500,:],x[3500:4000,:]
    y_train,y_train = y[0:3500,:],y[3500:4000,:]
    

二,模型建立

2.1 线性回归

根据课上所讲,先对数据进行线性回归:
Z n = ∑ i = 1 57 w i x i n + b Z^n=\sum\limits_{i=1}^{57}w_ix_i^n+b Zn=i=157wixin+b

 Z = weight.dot(x_train[i,:])+bias

weight为更新之后 w i w_i wi的权重

2.2 sigmoid 函数压缩回归值

将回归结果压缩到sigmod函数中,得到概率值
σ ( z ) = 1 1 + e − z \sigma(z)=\frac{1}{1+e^{-z}} σ(z)=1+ez1
如果 σ ( z ) ≥ 0.5 \sigma(z)\geq0.5 σ(z)0.5则输入类别1。

simga = 1/1+np.exp(-Z)

2.3 误差反向传播

	接着就到重头戏了。众所周知,不管线性回归还是Logistic回归,其关键和核心就在于通过误差的反向传播来更新参数,进而使模型不断优化。因此,损失函数的确定及对各参数的求导就成了重中之重。在分类问题中,模型一般针对各类别输出一个概率分布,因此常用交叉熵作为损失函数。交叉熵可用于衡量两个概率分布之间的相似、统一程度,两个概率分布越相似、越统一,则交叉熵越小;反之,两概率分布之间差异越大、越混乱,则交叉熵越大。

2.3.1 损失函数(Loss Function)
对于一般的k分类问题都有P为label,是一个概率分布,常用one_hot编码。例如针对3分类问题而言,若样本属于第一类,则P为(1,0,0),若属于第二类,则P为(0,1,0),若属于第三类,则为(0,0,1)。即所属的类概率值为1,其他类概率值为0。Q为模型得出的概率分布,可以是(0.1,0.8,0.1)等。
L o s s n = − ∑ 1 k P n l n Q n Loss^n=-\sum\limits_1^kP^nlnQ^n Lossn=1kPnlnQn
这次作业是一个二分类问题不需要,可以直接求出另一个概率值为1-p,并不需要单独计算。
所以Loss Function为:
L o s s n = − [ z ^ n l n σ n + ( 1 − z ^ n ) l n ( 1 − σ n ) ] Loss^n = -[\hat{z}^nln\sigma^n+(1-\hat{z}^n)ln(1-\sigma^n)] Lossn=[z^nlnσn+(1z^n)ln(1σn)]
这样通过简单的求偏导运算可以得出(具体步骤老师上课有讲),可以计算出
∂ L o s s n ∂ w i = − ∑ i n ( z ^ n − σ n ) x ^ i n \frac{\partial{Loss^n}}{\partial{w_i}}=-\sum_i^n(\hat{z}^n-\sigma^n)\hat{x}_i^n wiLossn=in(z^nσn)x^in
同理
∂ L o s s n ∂ b = − ∑ i n ( z ^ n − σ n ) \frac{\partial{Loss^n}}{\partial{b}}=-\sum_i^n(\hat{z}^n-\sigma^n) bLossn=in(z^nσn)
2.3.2 使用Gradient desent的方法更新参数
其中
b i a s = b i a s − η bias = bias - \eta bias=biasη

for j in range(num):
            y_pre = weights.dot(x_train[j,:])+bias
            sig = 1/(1+np.exp(-y_pre))
            b_g += (-1) * (y_train[j] - sig)
            for k in range(dim):
                w_g[k] += (-1) * (y_train[j] - sig) * x_train[j, k] + 2 * reg_rate * weights[k]#正则化
        b_g /= num
        w_g /= num

2.3.3 参数更新
求出梯度后,再拿原参数减去梯度与学习率的乘积,即可实现参数的更新。

#adagrad
bg2_sum += b_g**2
wg2_sum += w_g**2
#更新b和w_i
bias -= learn_rate / bg2_sum**0.5*b_g
weights -= learn_rate / wg2_sum**0.5*w_g

2.4 参数验证

通过验证集观测对训练集训练出来的参数效果:

def validate(x_val,y_val,weights,bias):
    num = 500
    acc = 0
    result = np.zeros(num)
    for j in range(num):
        y_pre = weights.dot(x_val[j,:])+bias
        sig = 1 / (1 + np.exp(-y_pre))
        if sig >= 0.5:
            result[j] = 1
        else:
            result[j] = 0
        if result[j] == y_val[j]:
            acc += 1.0
    return acc/num

三、代码展示

import pandas as pd
import numpy as np

def train(x_train,y_train,epoch):
    num = x_train.shape[0]
    dim = x_train.shape[1]
    bias = 0 # 偏置值初始化
    weights = np.ones(dim) # 权重初始化
    learn_rate = 1 # 初始学习率
    reg_rate = 0.001 # 正则项系数
    bg2_sum = 0
    wg2_sum = np.zeros(dim)

    for i in range(epoch):
        b_g = 0   #b的partial值
        w_g = np.zeros(dim)   #w_i的partial值
        for j in range(num):
            y_pre = weights.dot(x_train[j,:])+bias
            sig = 1/(1+np.exp(-y_pre))
            b_g += (-1) * (y_train[j] - sig)
            for k in range(dim):
                w_g[k] += (-1) * (y_train[j] - sig) * x_train[j, k] + 2 * reg_rate * weights[k]#正则化
        b_g /= num
        w_g /= num

        #adagrad
        bg2_sum += b_g**2
        wg2_sum += w_g**2
        #更新b和w_i
        bias -= learn_rate / bg2_sum**0.5*b_g
        weights -= learn_rate / wg2_sum**0.5*w_g

        # 每训练100轮,输出一次在训练集上的正确率
        # 在计算loss时,由于涉及到log()运算,因此可能出现无穷大,计算并打印出来的loss为nan
        # 有兴趣的同学可以把下面涉及到loss运算的注释去掉,观察一波打印出的loss
        if i % 3 == 0:
            # loss = 0
            acc = 0
            result = np.zeros(num)
            for j in range(num):
                y_pre = weights.dot(x_train[j, :]) + bias
                sig = 1 / (1 + np.exp(-y_pre))
                if sig >= 0.5:
                    result[j] = 1
                else:
                    result[j] = 0

                if result[j] == y_train[j]:
                    acc += 1.0
                # loss += (-1) * (y_train[j] * np.log(sig) + (1 - y_train[j]) * np.log(1 - sig))
            # print('after {} epochs, the loss on train data is:'.format(i), loss / num)
            print('经过 {} 轮次的Grdient desent, 模型在训练集上的准确率为:'.format(i), acc / num)

    return weights, bias

def validate(x_val,y_val,weights,bias):
    num = 500
    acc = 0
    result = np.zeros(num)
    for j in range(num):
        y_pre = weights.dot(x_val[j,:])+bias
        sig = 1 / (1 + np.exp(-y_pre))
        if sig >= 0.5:
            result[j] = 1
        else:
            result[j] = 0

        if result[j] == y_val[j]:
            acc += 1.0
    return acc/num



def main():
    df = pd.read_csv('spam_train.csv')
    df = df.fillna(0)#将空值填充成0
    array = np.array(df)
    x = array[:,1:-1]
    x[:,-1] /= np.mean(x[:,-1])
    x[:,-2] /= np.mean(x[:,-2])
    y = array[:,-1]

    x_train,x_val = x[0:3500,:],x[3500:4000,:]
    y_train,y_val = y[0:3500],y[3500:4000]

    epoch = 30
    w,b = train(x_train,y_train,epoch)
    acc = validate(x_val,y_val,w,b)
    print('最终在验证集的准确性为:',acc)

if __name__ == '__main__':
        main()


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值