线性回归和逻辑回归

最小二乘法


假设θ1是年龄的参数,θ2是工资的参数,那么,得到拟合曲线的公式为:

 真实值和预测值之间会存在一定差异,我们用ε来表示误差,则对于每个样本:

 假设误差ε(i)是独立的,并且服从均值为0,方差为θ2的正态分布:

高斯分布的积分为1,所以可以把闭区间的面积看作概率,中间区域的面积最大,说明值落在中间的概率大由图可知,有大概率的点是落在x=0附近的,高斯分布的纵坐标无实际意义,纵坐标的值与方差θ的平方有关,θ越大,表示样本的震荡幅度越大(不会密集的分布在0附近),那么图像就越矮,纵坐标越小。

因此:

由于(1)式是已知的,(2)式我们假设的,那么将(1)代入(2),就可以得到一个新的关于参数θ的函数,这就是一个似然函数。

下面先来说一下似然函数的概念,在数理统计中,似然函数是一种关于统计模型中的参数的函数,表示模型参数中的似然性。似然就是用结果推断参数,最大程度的你和数据。也就是,什么样的参数,跟我们的数据组合后,恰好是真实值。将上面的公式带入,得到:

上式为何要进行一个累乘?

因为因为一个单独的似然函数,概率最大时解出的θ是最满足那一个样本的参数θ,而我们的目标是要训练出一个拟合全部样本数据的θ,我们就得用累乘,来求一个联合概率密度。举个栗子,假设事件A,事件B,事件C为三个独立同分布的事件,那么三个事件同时发生的概率怎么计算呢?即P(A,B,C) = P(A) × P(B)×P( C ),这就是上面要累乘的原因。

似然函数是一个连乘的计算,这样的话,求解肯定是很不方便的,所以我们给它加上一个log函数,加上log之后,变化形式是,累乘变累加,所以,对上式求对数,得到对数似然,式子如下,

 

 由于和是常量,而我们希望似然函数越大越好,那么,就希望

越小越好,上式又称为最小二乘法。

还没完事啊,我们现在已经将问题简化到求最小二乘法的最小值,怎样求呢?让它偏导等于0不就是了嘛。先将最小二乘法展开,

对其求偏导,得:

那么我们怎么评估预测值与真实值的差距呢?一般常用R2来评估,式子如下,

 R的值越接近1,说明模型拟合的越好。

逻辑回归

逻辑回归其实是个经典的二分类算法。从名字来理解逻辑回归.在逻辑回归中,逻辑一词是logistics [lə'dʒɪstɪks]的音译字,并不是因为这个算法是突出逻辑的特性.至于回归,我们前一段讲到回归任务是结果为连续型变量的任务,logistics regression是用来做分类任务的,为什么叫回归呢?那我们是不是可以假设逻辑回归就是用回归的办法来做分类的呢?

假设刚刚的思路是正确的,逻辑回归就是在用回归的办法做分类任务,那有什么办法可以做到呢,此时我们就先考虑最简单的二分类,结果是正例或者负例的任务.

  按照多元线性回归的思路,我们可以先对这个任务进行线性回归,学习出这个事情结果的规律,比如根据人的饮食,作息,工作和生存环境等条件预测一个人"有"或者"没有"得恶性肿瘤,可以先通过回归任务来预测人体内肿瘤的大小,取一个平均值作为阈值,假如平均值为y,肿瘤大小超过y为恶心肿瘤,无肿瘤或大小小于y的,为非恶性.这样通过线性回归加设定阈值的办法,就可以完成一个简单的二分类任务.如下图:

上图中,红色的x轴为肿瘤大小,粉色的线为回归出的函数的图像,绿色的线为阈值.

预测肿瘤大小还是一个回归问题,得到的结果(肿瘤的大小)也是一个连续型变量.通过设定阈值,就成功将回归问题转化为了分类问题.但是,这样做还存在一个问题.

我们上面的假设,依赖于所有的肿瘤大小都不会特别离谱,如果有一个超大的肿瘤在我们的例子中,阈值就很难设定.加入还是取平均大小为阈值,则会出现下图的情况:

从上边的例子可以看出,使用线性的函数来拟合规律后取阈值的办法是行不通的,行不通的原因在于拟合的函数太直,离群值(也叫异常值)对结果的影响过大,但是我们的整体思路是没有错的,错的是用了太"直"的拟合函数,如果我们用来拟合的函数是非线性的,不这么直,是不是就好一些呢?

        所以我们下面来做两件事:

                1-找到一个办法解决掉回归的函数严重受离群值影响的办法.

                2-选定一个阈值.

由于判别函数不能很好地解决离群值的影响,.我们能做的呢,就是换一个.判别函数。我们目前就用sigmod函数,函数如下:

  

该函数具有很强的鲁棒性并且将函数的输入范围(∞,-∞)映射到了输出的(0,1)之间且具有概率意义.具有概率意义是怎么理解呢:将一个样本输入到我们学习到的函数中,输出0.7,意思就是这个样本有70%的概率是正例,1-70%就是30%的概率为负例.

 总结一下上边所讲:我们利用线性回归的办法来拟合然后设置阈值的办法容易受到离群值的影响,sigmod函数可以有效的帮助我们解决这一个问题,所以我们只要在拟合的时候把即y = 换成即可,其中z=,也就是说g(z) = . 同时,因为g(z)函数的特性,它输出的结果也不再是预测结果,而是一个值预测为正例的概率,预测为负例的概率就是1-g(z).

        函数形式表达:

                 P(y=0|w,x) = 1 – g(z)

                 P(y=1|w,x) =  g(z)

                 P(正确) = *         为某一条样本的预测值,取值范围为0或者1.

        到这里,我们得到一个回归函数,它不再像y=wT * x一样受离群值影响,他的输出结果是样本预测为正例的概率(0到1之间的小数).我们接下来解决第二个问题:选定一个阈值.

选定阈值

        选定阈值的意思就是,当我选阈值为0.5,那么小于0.5的一定是负例,哪怕他是0.49.此时我们判断一个样本为负例一定是准确的吗?其实不一定,因为它还是有49%的概率为正利的.但是即便他是正例的概率为0.1,我们随机选择1w个样本来做预测,还是会有接近100个预测它是负例结果它实际是正例的误差.无论怎么选,误差都是存在的.所以我们选定阈值的时候就是在选择可以接受误差的程度.

        我们现在知道了sigmod函数预测结果为一个0到1之间的小数,选定阈值的第一反应,大多都是选0.5,其实实际工作中并不一定是0.5,阈值的设定往往是根据实际情况来判断的.本小节我们只举例让大家理解为什么不完全是0.5,并不会有一个万能的答案,都是根据实际工作情况来定的.

        0到1之间的数阈值选作0.5当然是看着最舒服的,可是假设此时我们的业务是像前边的例子一样,做一个肿瘤的良性恶性判断.选定阈值为0.5就意味着,如果一个患者得恶性肿瘤的概率为0.49,模型依旧认为他没有患恶性肿瘤,结果就是造成了严重的医疗事故.此类情况我们应该将阈值设置的小一些.阈值设置的小,加入0.3,一个人患恶性肿瘤的概率超过0.3我们的算法就会报警,造成的结果就是这个人做一个全面检查,比起医疗事故来讲,显然这个更容易接受.

        第二种情况,加入我们用来识别验证码,输出的概率为这个验证码识别正确的概率.此时我们大可以将概率设置的高一些.因为即便识别错了又能如何,造成的结果就是在一个session时间段内重试一次.机器识别验证码就是一个不断尝试的过程,错误率本身就很高.

        以上两个例子可能不大准确,只做意会,就是根据具体情况具体对待,你懂了就好. 

        到这里,逻辑回归的由来我们就基本理清楚了,现在我们知道了逻辑回归的判别函数就是,z=.休息两分钟,我们下面看如何求解逻辑回归,也就是如何找到一组可以让全都预测正确的概率最大的W.

综合上式:

 

上式中,y=0或y=1.

对上式求似然函数,则有:

 求对数似然数,则有:

 因为上式要应用梯度上升求最大值,我们引入

 将其转化为梯度下降任务,然后对上式求偏导得:

得到上式偏导以后,我们就可以用它来更新参数了,

上式中,α其实就是更新的步长,

是更新的方向, 

说明要综合考虑所有的m个样本,其实就是一个小的batch。 

实战:

import numpy as np
import matplotlib.pyplot as plt
import  pandas as pd

# 由于*我觉得很复杂,因此元素乘法我就使用np.multiply, 矩阵乘法我就用np.dot
# 元素的乘法:w的列数只能为 1 或 与x的列数相等(即n),w的行数与x的行数相等 才能进行乘法运算。例如:
# 如果w为m*1的矩阵,x为m*n的矩阵,那么通过点乘结果就会得到一个 m*n 的矩阵。
# 若 w 为 m*n 的矩阵,x 为 m*n 的矩阵,那么通过点乘结果就会得到一个 m*n 的矩阵。

#矩阵乘法的条件:只有 w 的列数 == x的行数 时,才能进行乘法运算
#
def sigmoid(z):
    return 1.0/(1+np.exp(-z))

def model(x,theta):
    y_hat =  sigmoid(np.dot(x,theta.T))
    print('y_hat:',y_hat.shape)
    return y_hat

def cost(y,y_hat):
    loss = np.sum(y * np.log(y_hat) + (1-y) * np.log(1-y_hat))
    print('loss:',loss.shape)
    return loss

def gradient(y,y_hat,x,theta,learning_rate):
    grad = np.zeros(theta.shape)
    for i in range(len(theta.ravel())):
        grad[0,i] = np.mean( (y_hat - y)*x[:,i] )
    theta = theta - learning_rate * grad
    return theta

def gradientDescent(data,theta,batch_size,learning_rate):
    batch_index = 0
    np.random.shuffle(data)
    x = data[:,0:-1]
    y = data[:,-1]
    y = y[:,np.newaxis]
    batch_x = x[batch_index : batch_index + batch_size]
    batch_y = y[batch_index : batch_index + batch_size]
    y_hat = model(batch_x,theta)
    for i in range(100):
        theta = gradient(batch_y,y_hat,batch_x,theta,learning_rate)
    return theta

def predict(x,theta):
    return [1 if x>0.5 else 0 for x in model(x,theta)]

def test(x,theta):
    tempx = x[:,0:3]
    tempy = x[:,3]
    pred = predict(tempx,theta)
    correct = np.sum(np.equal(pred,tempy))
    accuracy = correct / len(tempx)
    print('accuracy:{}'.format(accuracy))

if __name__ == "__main__":
    data = pd.read_csv('historyscore.csv',header=None,names = ['score1','score2','pass'])
    # print(data.shape)
    passData = data[data['pass'] == 1]
    notPassdata = data[data['pass'] == 0]
    # print(passData.shape,notPassdata.shape)
    xy = plt.subplot()
    xy.scatter(passData['score1'], passData['score2'], c='r', marker='o', label='pass')
    xy.scatter(notPassdata['score1'], notPassdata['score2'], c='b', marker='+', label='notpass')
    # plt.show()
    data.insert(0,'one',1)
    data = data.as_matrix()
    theta = np.zeros((1,3))
    theta = gradientDescent(data,theta=theta,batch_size=100,learning_rate=0.001)
    test(data,theta)

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值