MindSpore机器学习系列文章
前言
在上一个章节中,我们已经给大家讲解了什么是线性回归,并且用python几个功能强大的库演示了线性回归的实际效果,但是真正的想弄懂线性回归的原理我们还是得从他的根本出发,一步步推理,结合数学理论,再加手动实现!
当然我这边以简单的一元线性方程为例
一、线性回归的第一步
准备或收集数据集,计算相关系数,我们一切线性关系的寻找都是建立在有价值的数据集基础之上的。
数据集好理解,那什么是相关系数呢,其实相关系数在我们上一章节中已经演示,他是描述数据与数据直接关联程度的一个概念。我们之前的实现方法也是采用直接库的调用,但其实相关系数的实现原理很简单,我们来一起了解一下。
1、数据读取和相关性分析
相关系数的定义式:
当然这只是最简单的相关系数表达式,也就是针对两个变量之间联系的计算方法。
那他使用代码怎么实现呢。
import numpy as np
#读取数据
data = np.genfromtxt("1.txt",encoding="utf-8")
#数据分割
data_x,data_y = data[:,0],data[:,1]
x_ave,y_ave = data_x.mean(),data_y.mean()
xysum,xsum,ysum,sum = 0,0,0,0
dic = dict(zip(data_x,data_y))
for x,y in dic.items():
x_t,y_t = x-x_ave,y-y_ave
xysum,xsum,ysum = xysum+x_t*y_t,xsum+x_t**2,ysum+y_t**2
sum = xysum/((xsum*ysum)**0.5)
print(sum**2)
12345678910111213
可以看到我们的数据散点图肉眼看上去还是很有线性关系的,同时r²的结果也证明了这种关系,说明我们的数据应该还是挺适合最线性规划分析的。
二、线性回归理论分析
1.统计学概念
在统计学中,线性回归(Linear Regression)是利用回归方程的最小平方函数对一个或多个自变量和因变量之间关系进行建模的一种概念。当自变量只有一个的情况称为简单回归,大于一个自变量的情况则叫多元回归。
本章我们举例的便是一个简单回归
2.回归方程构建
因为我们是一个单自变量的简单回归,所以我们的回归方程可以很简单的表示为一个一元一次方程:
y=w*x+b
针对这样的一个未知方程,对 w 、b 的确定便是回归的核心任务。
但苦恼的是面对这样一大堆离散的数据点,面对其中任意的某个点,方程的w、b值都是不一样的,我们又如何唯一确定出这样一条最拟合全部数据点的直线呢?
首先,我们现在明确知道的一点就是他最后会产生一条线,那我们索性就先用k和b来暂代最终结果。然后来调整kb的值来试探性的接近我们的最终答案。那么这边就涉及到一个概念了,我们怎么知道试探到什么程度这就是最终答案了呢?
答案就是用:最小二乘法(当然还有其他方法)
3.最小二乘法
最小二乘法的概念:
最小二乘法其实是一种在误差估计中广泛应用的数学思想,他表达通过求解涉及的参数(w,b),但这组w,b代入后使计算结果与实际结果的方差最小,也就说明估计相对准确了的思想。
他的数学表达为:
minF(x) = ∑ [yi-f(xi,wi,bi)]²,(i<n,n代表数据点个数)
最小二乘法的实现:
虽然通过其概念我们能很容易了解他的思想,但这边涉及到一个技术难点便是:怎么去调整参数来求得这个解呢?
因为我们涉及到的数据点很多,这条表达式展开异常的复杂,不可能直接求解,但我们有计算机这个工具,所以我们最简单粗暴的方法就是进行试探,比如:答案是2,我们并不知道,现在估计的是1,我们去与结果比较,小了,那我们就加一点:1+0.5,一比较,发现还是比答案小,那就再:1+0.5,一比较,对了,那答案就被我们试探出来了。
这下思路清晰了,但我们又遇到一个问题:
- 怎么知道大了小了
- 怎么去确定这个试探的幅度
这就又引出来一个算法:梯度下降算法
4.梯度下降
梯度下降的概念
梯度下降是迭代法的一种,可以用于求解最小二乘问题(线性和非线性都可以)。在求解机器学习算法的模型参数时,梯度下降(Gradient Descent)是最常采用的方法之一。在求解二乘法的最小值时,可以通过梯度下降法来一步步的迭代求解,得到最小化的损失函数和模型参数值。
梯度下降原理
举一个非常简单的例子,如求函数 f(x)= x² 的最小值
利用梯度下降的方法解题步骤如下:
1、求梯度,f’(x) = 2x
用于确定我们目前与最终答案的方向关系,观察导数图像即可懂得。
2、向梯度相反的方向移动x来逼近答案 ,如下
x = x-lr*2x,其中, lr为步长。如果步长足够小,则可以保证每一次迭代都在减小(不会跨过答案,导致在答案左右来回跳动),但可能导致收敛太慢,如果步长太大,则不能保证收敛。
3、重复步骤2,直到x 的值变化使得 f(x)(注意是f(x)不是f’(x))在两次迭代之间的差值足够小,比如0.00000001(到达极值点),也就是说,直到两次迭代计算出来的f(x) 基本没有变化,则说明f(x)已经达到局部最小值了。
4、此时,输出 x,这个 x就是使得函数f(x)最小时的x 的取值,当这个f(x)是我们的最小二乘法时,那不就能求出其解,而得出最小二乘法的解后,kb的解不也就对应得出了 。
5.求解最小二乘法
我们已知的最小二乘法公式为:
minF(x) = ∑ [yi-f(xi,wi,bi)]²,(i<n,n代表数据点个数)
参考梯度下降求解方法
第一步先求梯度:
f’w(x)=((yi-wixi-bi)² )’= -2xi*(yi-wixi-bi) / n
f’b(x)=((yi-wixi-bi)² )’= -2*(yi-wi*xi-bi) / n
第二步迭代计算:
定义步长:lr = 0.001
迭代次数:epoch = 3000
第三步梯度更新
w = w- lr*(-2xi(yi-wixi-bi)) / n
b = b- lr(-2*(yi-wi*xi-bi)) / n
第四步完成计算
完全我们的全部迭代后,得出的w和b就是我们的最终结果了
三、线性回归代码实现
1.数据读取和相关性评估
这个模块的工作我们在上面已经完成了,大家可以参考前面所描述的源码。
2.参数设置
#y=kx+b
#参数预定义
lr=0.001
b=1
k=0
epochs=3000 #轮次
data_len=float(len(data_x))
1234567
3.定义损失函数
def error_num(b,k):
sum=0
for i in range(0,len(data_x)):
sum+=(data_y[i]-(k*data_x+b))**2
return sum/float(len(data_x))
12345
4.定义梯度下降函数
def Gradient_Descent(b,k,lr,epochs):
for i in range(epochs):
b_grad=0
k_grad=0
for j in range(0,len(data_x)):
b_grad,k_grad=b_grad-(1/data_len)*(data_y[j]-k*data_x[j]-b),k_grad-(1/data_len)*(data_x)*(data_y[j]-k*data_x[j]-b)
b,k=b-(lr*b_grad),k-(lr*k_grad)
if i%1000 == 0:
print("epochs:",i)
print('b:',b,'k:',k)
print('error:',error_num(b,k))
plt.plot(data_x,data_y,'b')
plt.plot(data_x,k*data_x+b,'r')
plt.show()
return b,k
123456789101112131415
5.进行线性回归
Gradient_Descent(b,k,lr,epochs)
1
6.结果分析
至此我们已经完成了线性规划的代码实现,根据最终的结果我们可以发现,最开始我们随便估计的结果与实际趋势相差较大,但随着迭代的进行,直线越来越拟合我们的离散点。
总结
在本章节中,我们真正深入的了解了什么是线性回归的原理。分析了线性回归的过程,以及求解的方法——最小二乘法,但面对最小二乘法难以用公式直接求解的问题,我们结合计算机又提出了梯度下降的方法来帮助我们求解最小二乘法,最终实现一个完整的线性回归。