机器学习之线性回归

单变量线性回归

说到机器学习的话,很多人首先会想到的是单变量的线性回归,好像大家高中的时候都学过。很多人不理解,这种线性回归的东西跟机器学习有什么关系。

其实单变量的话形式很简单:


但是让这种函数充分拟合大致有线性关系的离散点,怎么做到呢?这就需要一个损失函数了:


其实就是回归函数值与真实的y值的欧式距离求和。想要拟合效果最好,就要使得损失函数最小化。怎么最小化呢?

我们很容易看得出损失函数是个凸函数,二阶导数大于零。也就说有最优解。怎么求最优解呢?另两个变量的偏导等于0,即可。


令两式都为0.解得:


这个就是高中我们学过最小二乘法解线性回归的参数了!

行吧,先拿单变量练一练手。

数据集是关于年龄与身高的,来源:点击打开链接

把两个文件与代码放在同一个文件下面。然后就可以打码了。

import numpy as np
import matplotlib.pyplot as plt

def linear_regression_one_var(x, y):
    #  y=bx+a
    num = len(x)
    b = (np.sum(x*y)-num*np.mean(x)*np.mean(y))/(np.sum(x*x)-num*np.mean(x)**2)
    a = np.mean(y)-b*np.mean(x)
    return np.array([b, a])


x = np.loadtxt('ex2x.dat')
y = np.loadtxt('ex2y.dat')
b, a = linear_regression_one_var(x, y)
print(b,a)
fx = b*x+a
plt.plot(x, fx)
plt.plot(x, y, 'o')
plt.xlabel('age')
plt.ylabel('height')
plt.show()

输出:

0.0638811658258342 0.7501625370012386

等等,上面写的还停留在标量的阶段,实在是很不简洁,要是算多变量就很麻烦了。

这该怎么办呢?向量化,矩阵化!


重新定义参数,W是参数的矩阵,本质上是一个列向量,w0其实是常量的参数,不是变量的参数,为了运算的方便,纳入到参数矩阵中。X是变量的矩阵,上标代表是哪一个样本,每一列都是一个样本的特征变量,这里是单变量线性回归嘛,所以每列第一个都是1,代表那个常量,每列第二个就是该样本的特征变量了,因为是单变量,所以就不添下标了。Y的话就不用说了,本质上是一个列向量。

好了,那个回归函数就很容易写出来了。


我写的这个形式和别人的可能不太一样。

然后定义损失函数:


m是样本的个数,这个实践例子中,m=50,为什么是2m呢?为了求导后的形式美观,待会你看就知道了。

改变W矩阵,使得损失函数最小化!很简单,令


其实这个0是零矩阵,这是矩阵求导!矩阵求导细节,知乎上有个很好的讲解:矩阵求导术

还是写下求导的具体过程:

1、处理J(W):


2、套迹,其实我们知道J(W)是标量,所以可以套个迹,方便后面的微分


3、全微分


4、求导数


终于把导数求出来了。如果直接令导数等于0,解W是可以的。


这种求法的弊端在于矩阵的逆不存在时(也就是有多个最优解时),就不能用这种方法算了。

更推荐一种方法是,梯度下降法。原理的话,网上大把

具体形式:


alpha是步长。行吧最后上代码:

import numpy as np

def gradient_descent(x, y, w, col, alpha=0.06,times=3000,eps=1e-9):  # 调参有点难受啊
    for i in range(times):
        y_predit_T = x.T * w
        dJ_dw = 1 / col * x * (y_predit_T - y.T)
        w -= alpha * dJ_dw  # 同一个w矩阵
        if np.sum(np.abs(dJ_dw))<eps:
            print('第{}次迭代后的结果'.format(i))
            break
x = np.loadtxt('ex2x.dat')
y = np.loadtxt('ex2y.dat')
x.resize((1,50))
x=np.append(np.ones((1,50)),x,0)
y.resize((1,50))
row,col=x.shape
w = np.mat(np.zeros((row,1)))
x_mat=np.mat(x)#矩阵化后可以直接使用矩阵乘法
y_mat=np.mat(y)
gradient_descent(x_mat,y_mat,w,col)
print(w)
w0=(x_mat*x_mat.T).I*x_mat*y_mat.T#I表示矩阵的逆
print('直接求解的结果')
print(w0)
输出:
第2917次迭代后的结果
[[0.75016253]
 [0.06388117]]
直接求解的结果
[[0.75016254]
 [0.06388117]]

感觉还行吧,就是调参有点恶心。

多变量就不写了,一样的。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值