1、简介
线性回归是一个回归模型,输出值为连续值
2、一元线性回归
我们假设以房屋交易为例,这里我们只有一个自变量(房屋的大小,x),还有一个因变量(房屋的价格,y),那么我们要做的就是根据已知的样本数据(x,y)发现一个规则(也可以称为映射),之后如果有人问你他的房子值多少钱时,你就可以依据他房子的大小根据我们发现的规则很容易的给出他房子的近似价格。具体如下:
我们给定若干训练数据(小大,价格),然后我们所有数据投影到二维空间中,以房屋大小为x轴,以价格为y轴。这样我们就可以用一个函数
取近似拟合我们的数据。因其只有一个自变量(输入变量或特征),因此这样的问题我们叫做一元线性回归。
3、多元线性回归
到目前为止,我们探讨了一元线性回归模型。自然界中一切事物都不是受到单一元素的影响,而是是同时受到多个因素的共同相互作用影响,房价也不列外。我们可以想像,房家除了受到占地面积影响,还有很多影响因素,如:地理位置(是不是在市区),楼层数,周围交通便利程度等等,这都有可能成为影响我们房价的因素。既然有这么多因素,现在我们如何表示我们的假设函数呢?
若我们令
则我们的假设函数可以写成:
这时我们训练样本为
每个样本的特征都是一个n+1维的向量:
表示的是第i个样本的第n个特征。
x和θ都是n+1维向量
故,我们的假设函数可以写成:
4、损失函数/代价函数
损失函数/代价函数:
5、最优参数求解方法
要找到最优模型,即要找到使得代价函数最小的参数(𝜃0,𝜃1,…,𝜃n),主要有两种求解最优参数的方法:最小二乘法和梯度下降法
1)最小二乘法/正规方程法
我们知道求解函数最小值的一个方法就是求导,到后令导数等于0。这里也是适用的,即求解下面的方程来找出使得代价函数最小的参数。
有m个训练实例,每个实例有n个特征,则训练实例集为:
表示的是第i个样本的第n个特征。
特征参数:
故代价函数可表示为:
求导后得:
进一步分析导数:
第一项:
第二项:
该矩阵求导为分母布局下的标量/向量形式,故:
第三项:
该矩阵求导为分母布局下的标量/向量形式,故:
第四项:
该矩阵求导为分母布局下的标量/向量形式,故:
矩阵求导参考:
https://wenku.baidu.com/view/70e4a60ff90f76c660371a28.html
https://blog.csdn.net/a493823882/article/details/81324037
故最终导数为
令导数等于0
解得:
即当时,代价函数取得最小值,即为最优解。
python代码实现:
# -*- coding: utf-8 -*-
import numpy as np
from sklearn.datasets import load_boston #导入波士顿房价数据
from sklearn import linear_model
class LinerRegression:
theta = [] #参数
def __init__(self):
pass
def fit(self, data, target):
M_x = np.mat(data) #创建data矩阵
M_x0 = np.ones((len(data), 1)) #创建分量x0,用来对应系数θ0
M_x = np.hstack((M_x0, M_x)) #加入分量x0
M_y = np.mat(target)
self.theta = (M_x.T * M_x).I * M_x.T * M_y.T #通过最小二乘法计算出参数向量
def predict(self, data):
M_x = np.mat(data)
M_x0 = np.ones((len(M_x), 1))
M_x = np.hstack((M_x0, M_x))
estimate = np.matmul(M_x, self.theta) #矩阵相乘
return estimate
if __name__ == '__main__':
data, target = load_boston(return_X_y=True)
my_lr = LinerRegression()
my_lr.fit(data,target)
test = data[:10,:] #拿最后10条数据测试
real = target[:10] #实际数值real
#与sklearn库线性回归模型比较
lr = linear_model.LinearRegression()
lr.fit(data, target)
estimate1=my_lr.predict(test)
estimate2=lr.predict(test)
for i in range(len(test)):
print("实际值:",real[i]," 估计值1:",estimate1[i,0],"估计值2:", estimate2[i])
#训练数据的平方误差
rs=my_lr.predict(data)
inner = np.power(( rs - np.matrix(target).T),2)
print("train error:",np.sum(inner)/(2*len(data)))
问题:最小二乘法需要对求逆,若不可逆怎么办?
解决方法:
1.删除多余/冗余特征(线性相关)
2.删除一些特征(特征数大于样本数)
3.正则化
其中 𝜆为一个很小的正数,𝐼为单位矩阵
2)梯度下降法
(1)梯度下降的思想
当你站在山顶,现在要下山。你环顾一下四周,默默问一下自己在那个方向上下山最快呢,然后你朝着你认为下山最快的方向迈出你的第一步;现在又到了一个新的位置,再一次环顾一下四周,默默问一下自己在那个方向上下山最快呢,然后你朝着你认为下山最快的方向迈出你的第二步,一直重复这个过程,直到你到达山下位置。
我们再结合这个例子看一下梯度下降的实际操作是什么样子的:开始时我们随机选择一个参数的组合(这就相当于让你在山的任一一个位置下山),计算代价函数,然后我们寻找下一个能让代价函数值下降最多的参数组合,我们持续的重复这个过程直到到达一个局部最小值!注:因为我们并没有尝试所有的参数组合,所以我们并不能确定得到的局部最小值是不是全局最小值,所以我们如果选择不同的参数组合,可能会找到不同的局部最小值(像上图一样)。
(2)梯度下降的算法定义
step1:初始化参数为任意值
step2:求解梯度
step3:更新参数
step4:若达到指定迭代次数或收敛条件,训练结束,否则继续执行step2、step3
梯度下降参数更新公式(举例:当只有两个参数时):
:学习率,控制着我们将以多大的幅度来更新我们参数,相当于表示你下山迈的步子大小;
:表示最快的下降方向;
注意参数更新是同步更新的:
1.学习率对梯度下降算法的收敛性和收敛速度有着至关重要的影响。
学习率α太小:参数的更新幅度就会非常小,带来时间上的浪费。
学习率α太大:可能会越过了最低点,并且离最低点会越来越远,导致无法收敛的情况发生。
实际上,梯度下降法也会自动的采取更小的幅度以确保其可以收敛到局部最低点,因为参数在更新过程中不断的减小,在α固定的情况下幅度是不断减小的。因此在实际工作中,我们没有必要在另外减小α的值。
2.如何选择合适的学习率呢?
在执行梯度下降时,顺带着画出代价函数随着迭代次数增加而变化的曲线(如图),由曲线的表现来判断我们的梯度下降是否收敛以及收敛速度是快是慢。
在尝试时,一般取……, 0.001, 0.003, 0.01, 0.03, 0.1, 0.3, 1, 3, 10, …… (大约间隔3倍)
3.为啥损失函数的偏导指向下降最快的方向呢?
参考:https://www.cnblogs.com/lianyingteng/p/7679825.html
(3)迭代更新方式
按每次迭代使用的样本量不同,有以下几种迭代更新方式:
a.批量梯度下降法(batch gradient descent)
也就是是梯度下降法最原始的形式,对全部的训练数据求得误差后再对θ进行更新,优点是每步都趋向全局最优解;缺点是对于大量数据,由于每步要计算整体数据,训练过程慢;
b.随机梯度下降法(stochastic gradient descent)
每一步随机选择一个样本对θ进行更新,优点是训练速度快;缺点是每次的前进方向不好确定,容易陷入局部最优;
c.小批量随机梯度下降法(mini-batch SGD)
每步选择一小批数据进行批量梯度下降更新θ,属于批量梯度下降和随机梯度下降的一种折中,非常适合并行处理。
(注意:使用梯度下降法做多变量线性回归之前必须要Feature Scaling!)
1.什么是Feature Scaling/特征缩放?
特征缩放:在面对多维特征的时候,很多特征的尺度相差较大。例如:房间的尺寸和房间的数量,尺寸的值为0~200平方米,而房间数量的值为0~5。
通常特征缩放公式:
是平均值,是标准差
2.为什么要特征缩放?
如果两个特征尺度相差太大,则代价函数等高线如下:
图像会很扁,梯度下降算法将需要非常多次的迭代才能收敛。
python代码实现:
1.批量梯度下降法
# -*- coding: utf-8 -*-
import numpy as np
from sklearn.datasets import load_boston #导入波士顿房价数据
from sklearn import linear_model
class LinerRegression_Batch_Grad_Desc:
alpha = 0.15 #学习率
theta = [] #参数
num_iter = 5000 #迭代次数
#训练函数
def fit(self, x, y):
x_0 = np.ones((len(x), 1)) #创建分量x0
x = np.hstack((x_0, x)) #加入分量x0到x中
M_x, M_y = np.mat(x), np.mat(y).T
#step 1. 初始化参数为任意值,这里设为全0
self.theta = np.zeros((M_x.shape[1], 1))
#step 2. 求解梯度
grad = (M_x.T * (M_x * self.theta - M_y))/len(M_x) #梯度计算的矩阵形式
#step 3. 更新参数(同步更新)
temp_theta = self.theta - self.alpha * grad
self.theta = temp_theta
#step 4. 若达到指定迭代次数或收敛条件,训练结束,否则,继续执行step2、step3
for i in range(self.num_iter):
grad = (M_x.T * (M_x * self.theta - M_y))/len(M_x)
temp_theta = self.theta - self.alpha * grad
self.theta = temp_theta
#预测函数
def predict(self, test_x):
M_test_x = np.mat(test_x)
x_0 = np.ones((len(test_x), 1)) #创建分量x0
M_test_x = np.hstack((x_0, M_test_x)) #加入分量x0到x中
result = M_test_x * self.theta #返回结果
return result
if __name__ == '__main__':
x, y = load_boston(return_X_y=True)
my_lr_bgd = LinerRegression_Batch_Grad_Desc()
x = (x - np.mean(x, axis=0)) / np.std(x, axis = 0) #Feature Scaling
my_lr_bgd.fit(x,y)
test_x = x[:10,:]
test_y = y[:10]
lr = linear_model.LinearRegression()
lr.fit(x, y)
estimate1 = my_lr_bgd.predict(test_x)
estimate2 = lr.predict(test_x)
for i in range(len(test_x)):
print("实际值:",test_y[i]," 估计值1:",estimate1[i,0],"估计值2:", estimate2[i])
#训练误差
rs=my_lr_bgd.predict(x)
rs=rs.reshape(len(rs),-1)
inner = np.power(( rs - np.matrix(y).T),2)
print("train error:",np.sum(inner)/(2*len(x)))
2.随机梯度下降法
# -*- coding: utf-8 -*-
import numpy as np
from sklearn.datasets import load_boston #导入波士顿房价数据
from sklearn import linear_model
class LinerRegression_Stoc_Grad_Desc:
alpha = 0.001 #学习率
theta = [] #参数
num_iter = 50000 #迭代次数
#训练函数
def fit(self, x, y):
x_0 = np.ones((len(x), 1)) #创建分量x0
x = np.hstack((x_0, x)) #加入分量x0到x中
M_x, M_y = np.mat(x), np.mat(y).T
#step 1. 初始化参数为任意值,这里设为全0
self.theta = np.zeros((M_x.shape[1], 1))
#step 2. 求解梯度
grad = (M_x.T * (M_x * self.theta - M_y))/len(M_x) #梯度计算的矩阵形式
#step 3. 更新参数(同步更新)
temp_theta = self.theta - self.alpha * grad
self.theta = temp_theta
#step 4. 若达到指定迭代次数或收敛条件,训练结束,否则,继续执行step2、step3
for i in range(self.num_iter):
rand_arr = np.arange(M_x.shape[0]) #生成行号
np.random.shuffle(rand_arr) #打乱顺序
M_batch_x = M_x[rand_arr[0]] #取出随机编号对应1行
M_batch_y = M_y[rand_arr[0]] #取出随机编号对应1行
#计算梯度
grad = (M_batch_x.T * (M_batch_x * self.theta - M_batch_y))/len(M_batch_x)
#更新参数
temp_theta = self.theta - self.alpha * grad #
self.theta = temp_theta
#print(((M_x * self.theta - M_y).T * (M_x * self.theta - M_y))/(2 * len(x)))
#预测函数
def predict(self, test_x):
M_test_x = np.mat(test_x)
x_0 = np.ones((len(test_x), 1)) #创建分量x0
M_test_x = np.hstack((x_0, M_test_x)) #加入分量x0到x中
result = M_test_x * self.theta #返回结果
return result
if __name__ == '__main__':
x, y = load_boston(return_X_y=True)
my_lr_sgd = LinerRegression_Stoc_Grad_Desc()
x = (x - np.mean(x, axis=0)) / np.std(x, axis = 0) #Feature Scaling
my_lr_sgd.fit(x,y)
test_x = x[:10,:]
test_y = y[:10]
lr = linear_model.LinearRegression()
lr.fit(x, y)
estimate1 = my_lr_sgd.predict(test_x)
estimate2 = lr.predict(test_x)
for i in range(len(test_x)):
print("实际值:",test_y[i]," 估计值1:",estimate1[i,0],"估计值2:", estimate2[i])
#训练误差
rs=my_lr_sgd.predict(x)
rs=rs.reshape(len(rs),-1)
inner = np.power(( rs - np.matrix(y).T),2)
print("train error:",np.sum(inner)/(2*len(x)))
3.小批量随机梯度下降法
# -*- coding: utf-8 -*-
import numpy as np
from sklearn.datasets import load_boston #导入波士顿房价数据
from sklearn import linear_model
class LinerRegression_MiniBatch_Stoc_Grad_Desc:
alpha = 0.01 #学习率
theta = [] #参数
num_iter = 5000 #迭代次数
batch_size = 100 #批量样本数量
#训练函数
def fit(self, x, y):
x_0 = np.ones((len(x), 1)) #创建分量x0
x = np.hstack((x_0, x)) #加入分量x0到x中
M_x, M_y = np.mat(x), np.mat(y).T
#step 1. 初始化参数为任意值,这里设为全0
self.theta = np.zeros((M_x.shape[1], 1))
#step 2. 求解梯度
grad = (M_x.T * (M_x * self.theta - M_y))/len(M_x) #梯度计算的矩阵形式
#step 3. 更新参数(同步更新)
temp_theta = self.theta - self.alpha * grad
self.theta = temp_theta
#step 4. 若达到指定迭代次数或收敛条件,训练结束,否则,继续执行step2、step3
for i in range(self.num_iter):
rand_arr = np.arange(M_x.shape[0]) #生成行号
np.random.shuffle(rand_arr) #打乱顺序
M_batch_x = M_x[rand_arr[0 : self.batch_size]] #取出随机编号对应M_x的行
M_batch_y = M_y[rand_arr[0 : self.batch_size]] #取出随机编号对应M_y的行
#计算梯度
grad = (M_batch_x.T * (M_batch_x * self.theta - M_batch_y))/len(M_batch_x)
#更新参数
temp_theta = self.theta - self.alpha * grad #
self.theta = temp_theta
# print(((M_x * self.theta - M_y).T * (M_x * self.theta - M_y))/(2 * len(x)))
#预测函数
def predict(self, test_x):
M_test_x = np.mat(test_x)
x_0 = np.ones((len(test_x), 1)) #创建分量x0
M_test_x = np.hstack((x_0, M_test_x)) #加入分量x0到x中
result = M_test_x * self.theta #返回结果
return result
if __name__ == '__main__':
x, y = load_boston(return_X_y=True)
my_lr_mbsgd = LinerRegression_MiniBatch_Stoc_Grad_Desc()
x = (x - np.mean(x, axis=0)) / np.std(x, axis = 0) #Feature Scaling
my_lr_mbsgd.fit(x,y)
test_x = x[:10,:]
test_y = y[:10]
lr = linear_model.LinearRegression()
lr.fit(x, y)
estimate1 = my_lr_mbsgd.predict(test_x)
estimate2 = lr.predict(test_x)
for i in range(len(test_x)):
print("实际值:",test_y[i]," 估计值1:",estimate1[i,0],"估计值2:", estimate2[i])
#训练误差
rs=my_lr_mbsgd.predict(x)
rs=rs.reshape(len(rs),-1)
inner = np.power(( rs - np.matrix(y).T),2)
print("train error:",np.sum(inner)/(2*len(x)))
参考:
https://www.cnblogs.com/lianyingteng/p/7689748.html
https://blog.csdn.net/u012421852/article/details/79562125
https://blog.csdn.net/chenlin41204050/article/details/78220280
https://blog.csdn.net/qq_36699423/article/details/83654512
https://blog.csdn.net/qq_32864683/article/details/80368135