python实现吴恩达机器学习线性回归ex.1.1
前述: 本节我们简单介绍下线性回归知识点,然后用常规方式完成作业,进一步引入矩阵将代码简单化。
首先,让咱们下载数据集:
数据集下载
提取码:0r1r
单线性回归
数据集介绍:
对于单线性回归我们用到的是ex1data1.txt数据集,该数据提供了两组数据,第一组是人口,第二组是收入,采取一对一的数据方式,一组人口对应一组收入。
线性回归简要介绍:
对于这个人口收入的模型,我们采取了很常规的直线模型(数据集输入绘图很类似直线):h(x) = θ1 * x + θ0
所以我们要做的就是找到最合适的θ1和θ2来拟合整个数据。
因此我们引入了代价函数:(实在打不出来了,建议自己去看自己看视频笔记)
巧妙之处就在于,为了使代价函数值最小,需要使得模型结果与训练结果十分接近,为了使得两者接近,就需要使两个参数θ1,θ0调整成更加合适的值,于是引入了反向传播函数进行梯度下降。
梯度下降的目的就是调整θ1,θ0,调整后的θ1,θ0带入代价函数得到反向传播中的到新的梯度下降,然后连续套娃,得到合适的θ1,θ0值。
实战:
引入库:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
库自己去了解下,推荐B站up主,莫烦。https://space.bilibili.com/243821484/
数据输入:
data = pd.read_csv(r'C:\Users\Administrator\Desktop\ex1\ex1data1.txt',sep=',',names=['population','profit'])
简单介绍下代码参数功能,第一个参数是路径,建议写绝对路径,第二个参数是分隔符,就是参数分列的依据,默认是‘,’,第三个是自定义列名,该数据集有两列,分别为人口和收入。
我们提取前五列看看数据:
data.head()
输出:
将数据集绘制成图片:
data.plot.scatter('population','profit')
我们重点讲思想,代码就简单一点,散点图绘制还是建议自己学习。那么输出的图片为:
看,很类似直线吧!
初始化数据:
我这里将X,Y赋值处理也算进初始化中,但一般初始化是指的权值、阈值初始化。
x,y赋值处理:
x = data.iloc[:,0]
y = data.iloc[:,1]
print(type(x))
x = np.array([x]).T
y = np.array([y]).T
我们将已经输入的数据data进行切片,将第一列数据作为输入x,第二列数据当成输出y。
但是我们输出了x,y的数据类型发现<class 'pandas.core.series.Series'>数据比较难处理,所以我们将数据转化成 ndarray类型处理。
转化后的维度是(1,97),我将它转置一下变成(97,1)维度处理(也可以不转置 ,w我转置只是为了符合我的习惯)。
θ1,θ2初始化
我们就直接把θ1,θ2赋值为0,由于传播性质(很重要),θ0,θ1在加减乘除过程中会被传播成与需要维度相同的矩阵。
theta1 = 0
theta0 = 0
正反向传播:
对于简单的模型,我正常将正反向传播合在一起:
def forbackward_propagation(theta1,theta0,x,y):
#正向传播
m = x.shape[0]
a = theta1 * x + theta0
J =np.sum(np.power(a-y,2))/(2*m)
#反向传播
d_theta1 = np.sum(x*(a-y))/m
d_theta0 = np.sum(a-y)/m
return J,d_theta1,d_theta0
很明显,正向传播的目的是为了得到模型结果,进而得到代价函数。
反向传播是为了的到θ1,θ0的偏导数(视频有偏导数计算)。
迭代函数:
def iter_propagation(theta1,theta0,x,y,rate,n):
cost =[]
for i in range(n):
J,d_theta1,d_theta0 = forbackward_propagation(theta1,theta0,x,y)
theta1 = theta1-rate*d_theta1
theta0 = theta0-rate*d_theta0
cost.append(J)
if i %100 ==0:
print(i,J)
return cost,theta1,theta0
套娃开始,根据前边反向传播得到的dθ1,dθ0偏导,不断优化θ1,θ0,rate为学习速率,n为迭代次数。
我们设定一个cost列表来储存J的值,便于画图。
每迭代100次,我们将迭代次数与对应的代价函数打印出来。
测试
cost,theta1,theta2,= iter_propagation(theta1,theta0,x,y,rate=0.02,n=2000)
plt.plot(cost)
这里设置了学习率rate为0.02,迭代次数2000次。打印出cost (储存J的字典)的图片。运行:
我们可以看出代价函数结果很快的下降到5.17左右开始缓慢下降,最终趋于平缓。这就证明J已经下降到一个相对优的位置了,也就是说在这个位置得到的θ1,θ2可以算是最合适模型的解。
绘制拟合函数曲线。
plt.figure()
data.plot.scatter('population','profit',label='point')
x = np.linspace(np.min(x),np.max(x),100)
print(theta1,theta0)
y = theta1 * x + theta0
plt.plot(x,y,c='r',label='line')
plt.legend()
plt.show()
我们选取输入x(人口)最小和最大为定义域,将数据分为100等分,用得到的θ1,θ2求出拟合函数对应的输出y(收入),绘制成线,放入同一个图中。输出如下:
接下来引入矩阵:
引入库:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
数据输入:
data = pd.read_csv(r'C:\Users\Administrator\Desktop\ex1\ex1data1.txt',sep=',',names=['population','profit'])
数据处理(不同点开始)
我们之前知道h(x) = θ1 * x + θ0
换成矩阵形式,大概是这样的:
从x数据集中的单个元素的矩阵转换,引入了x数据集的矩阵转换。我们可以看出原本输入的x数据集变成了多出一列1的数据集,所以我们接下来要做的就是将数据集前加上一列1,创造[1,x]的数据集。
我们用以下的函数插入列1:
data.insert(0,'ones',1)
data.head()
第一个参数是插入的位置,第二个参数是插入标题,第三个参数是插入的数字。
老规矩,我们输出前五个数据:
(看,是不是多了一列1)
数据初始化
x = data.iloc[:,0:2]
y = data.iloc[:,2]
x = np.array(x).T
y = np.array([y]).T
theta = np.zeros((2,1))
对于输入x,我们需要切片出一组一列全部为1,一列为人口的数据。也就是处理后数据的第0,1列。
输出y收入则是处理后数据的第2列。
θ0,θ1需要合并成一个二行一列的矩阵,也就是初始化θ为一个维度为(2,1)的零矩阵。
正反向传播
其实与前边没用矩阵步骤一样,带入相同的公式往下计算,不同的是我们这次是矩阵乘法。
def forback_propagation(x,y,theta):
m = x.shape[0]
a = x @ theta
J = np.sum(np.power(a-y,2))/(2*m)
d_theta = x.T@(x@theta-y)/m
return J,d_theta
注:
1.* = np.multiply(A,B) 指的是A,B两个矩阵对于元素相乘,需要A,B维度一致。
2.@ = np.dot(A,B) ,矩阵乘法。
d_theta的得到涉及到矩阵求导 ,我简单的手动推导下。
迭代
还是一样,不同的是迭代的不是单个的θ1,θ0,而是两个组合成的θ。
def iter_propagation(x,y,theta,rate=0.02,n=2000):
costs = []
for i in range (n):
J,d_theta = forback_propagation(x,y,theta)
theta = theta - rate*d_theta
costs.append(J)
if i %100 ==0:
print(i,J)
return costs,theta
我们输出一下发现与上边相同:
costs,theta_iterd = iter_propagation(x,y,theta,rate=0.02,n=2000)
输出为:
绘制拟合函数曲线:
步骤完全一样,只不过θ1,θ0,需要从矩阵θ取出来。
plt.figure()
data.plot.scatter('population','profit',label='point')
x = np.linspace(np.min(x),np.max(x),100)
print(theta_iterd )
y = x * theta_iterd[1,0] + theta_iterd[0,0]
plt.plot(x,y,c='r',label='line')
plt.legend()
plt.show()
依旧没什么区别:
hahah,是不是突然发现有点变化,又感觉没错。自己找下为啥这样,话都我说了,怎么学习啊。