线性回归
- 最小二乘法
- 梯度下降法
最小二乘法
-
数学原理
-
model:
m个sample,每个sample有n个特征,引入以下几个记号
我们有:
-
均方差:MES
梯度:
- 注意:E的梯度是一个向量函数,是一个列向量
-
最小二乘:
-
-
在编程中遇到的问题
-
python 面向对象编程-类的创建
- 用class 创立类,调用类的方法之前先创建类的实例;默认类的构建函数init函数参数为空,如果自己定义init注意传参数
- py和cpp不同,self相当于this指针;没有private,public声明,通过命名法区别类的私有函数和公有函数,代表是private的函数
-
python导入数据集
-
这里使用的是numpy.genfromtxt()函数
genfromtxt(‘path’;delimiter’分割字符’还有很多参数)
-
-
用numpy处理数组
- 矩阵切片:[ : , : ]“,”前表示行的切片
-
划分数据集
- 用到sklearn.model_selection.train_test_split
-
import numpy as np
#最小二乘法
class olsLinearRegression:
# X预处理
def _preprocessing(self,X):
m,n = X.shape
X_ = np.empty((m,n+1))
X_[:,1:] = X
X_[:,0] = 1
return X_
#求self.w
def _ols(self,X,y):
temp = np.linalg.inv(np.matmul(X.T,X))
temp_ = np.matmul(X.T,y)
return np.matmul(temp,temp_)
#训练model
def train(self,X,y):
X = self._preprocessing(X)
self.w = self._ols(X,y)
#做预测
def predict(self,X):
X = self._preprocessing(X)
return np.matmul(X,self.w)
#导入数据集
data = np.genfromtxt('E:\winequality-red.csv',delimiter = ';',skip_header = True)
X = data[:,:-1]
y = data[:,-1]
#划分数据集
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size = 0.3)
#创建类的实例
ols = olsLinearRegression()
#训练模型并得到预测结果
ols.train(X_train,y_train)
y_pred = ols.predict(X_test)
#性能指标:均方差误差
from sklearn.metrics import mean_squared_error
mes = mean_squared_error(y_pred,y_test)
print(mes)
梯度下降
梯度下降的假设:凸函数,可微函数
- 不是凸函数存在局部最优解
- 不可微,无法获得封闭解
为什么有梯度下降
- 不是所有的问题都是凸优化问题,换而言之,不是所有的问题只有一个(极大/极小)值
- 当
不可逆,
无零解,这时就要用到梯度下降了
梯度下降的概念
- 沿着某个点
处梯度的反方向梯度下降
- 学习率:步长,
- 步长太小:收敛速度慢
- 步长太大:之字形收敛
隐含的问题
局部最优解
-
收敛速度
因此可以通过数据的标准化
减小这种影响,其中:
-
也可以用变化学习率,选择最优学习率,这里不赘述,只呈现最基本的
其实变化学习率的想法是很自然的,因为函数的梯度在不同点通常是不同的,梯度大的时候,相应的学习率应该小
-
的初始化与样本点
的选取
批量梯度下降:
-
首先我们必须清楚梯度是怎么下降的
如果我们用的公式
梯度依赖于整个样本空间,那么我们称这种方法为:批量梯度下降法
一定能够求到求到全局最优解,但当样本数很多的时候,这种方法的效率比较低
随机梯度下降:
如果我们每步只使用一个样本来计算梯度;参数更新公式:
,梯度依赖于单个样本处的梯度
迭代一轮得到一个更新的参数向量,每轮迭代都要用到每一个样本点,适用于迭代次数远小于样本数的情况。注意不是每一轮迭代都是朝最优解方向走的,但总体趋势是趋近于最优解
-
原则上:校验每一轮更新结束后的
,如果损失函数值稳定,训练结束,故需要设定阈值。又由于整体趋势是趋近于全局最优解的
一般是设置最大迭代次数(超参数)
思想:损失一部分精度(不适用精确的梯度),增加迭代次数;
评价:在非凸优化问题上,更容易跳过局部最优解,求得全局最优解;凸优化往往会损失一部分精度,但速度快
**小批量梯度下降 **
- 如果我们一次用k个样本点梯度的均值作为梯度来更新,那么这种方式就是小批量梯度下降
- 评价:介于批量梯度下降与随机梯度下降之间,同时具备二者的的优缺点,比较常用
#基于梯度下降实现线性回归
import numpy as np
class GDLinearRegression:
#创建构造函数
def __init__(self,n_iter = 300,eta = 1e-2,tol = None):
#训练迭代次数
self.n_iter = n_iter
#学习率
self.eta = eta
#误差变化阈值
self.tol = tol
#模型参数w(训练时初始化)
self.w = None
#预处理
def _preprocessing(self,X):
m,n = X.shape
X_ = np.empty((m,n+1))
X_[:,0] = 1
X_[:,1:] = X
return X_
#损失函数
def _loss(self,y,y_pred):
return np.sum((y-y_pred)**2)/y.size
#计算梯度
def _gradient(self,X,y,y_pred):
return np.matmul(y_pred-y,X)/y.size
#梯度下降
def _gradient_decent(self,w,X,y):
#如果用户指定阈值,启用早期停止法
if self.tol is not None:
loss_old = np.inf
#迭代次数
for step_i in range(self.n_iter):
#做预测
y_pred = self._predict(X,w)
#计算损失
loss = self._loss(y,y_pred)
print("%4i Loss:%s"%(step_i,loss))
#早期停止法
if self.tol is None:
# 如果损失值小于阈值终止迭代
if loss_old - loss <self.tol:
break
less_old = loss
#计算梯度
grad = self._gradient(X,y,y_pred)
w -= self.eta*grad
#做训练
def train(self,X_train,y_train):
X_train = self._preprocessing(X_train)
#初始化参数向量w//这里_作为一个临时的名字,后面不会在用这个变量
_,n = X_train.shape
self.w = np.random.random(n)*0.05
#执行梯度下降训练
self._gradient_decent(self.w,X_train,y_train)
#做预测的内部接口函数//对data的每个数据都进行预测
def _predict(self,X,w):
return np.matmul(X,w)
#做预测
def predict(self,X):
X = self._preprocessing(X)
return self._predict(X,self.w)
#导入数据集
data = np.genfromtxt('E:\winequality-red.csv',delimiter = ';',skip_header = True)
X = data[:,:-1]
y = data[:,-1]
#划分数据集
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size = 0.3)
#对X进行列标准化,优化梯度下降
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
'''
#计算特征的均值和标准差
ss.fit(X_train)
StandardScaler(copy = True,with_mean = True,with_std = True)
'''
#标准化
X_train_std = ss.fit_transform(X_train)
X_test_std = ss.fit_transform(X_test)
#创建类的实例
GDS = GDLinearRegression(n_iter = 3700,eta = 0.01,tol = 0.000001)
#训练模型
GDS.train(X_train_std,y_train)
y_pred = GDS.predict(X_test_std)
from sklearn.metrics import mean_squared_error
mes = mean_squared_error(y_pred,y_test)
ptint(mes)
将两个模型放在一起,更容易看到梯度下降的优化效果
import numpy as np
#最小二乘法
class olsLinearRegression:
# X预处理
def _preprocessing(self,X):
m,n = X.shape
X_ = np.empty((m,n+1))
X_[:,1:] = X
X_[:,0] = 1
return X_
#求self.w
def _ols(self,X,y):
temp = np.linalg.inv(np.matmul(X.T,X))
temp_ = np.matmul(X.T,y)
return np.matmul(temp,temp_)
def train(self,X,y):
X = self._preprocessing(X)
self.w = self._ols(X,y)
def predict(self,X):
X = self._preprocessing(X)
return np.matmul(X,self.w)
class GDLinearRegression:
#创建构造函数
def __init__(self,n_iter = 200,eta = 1e-2,tol = None):
#训练迭代次数
self.n_iter = n_iter
#学习率
self.eta = eta
#误差变化阈值
self.tol = tol
#模型参数w(训练时初始化)
self.w = None
#预处理
def _preprocessing(self,X):
m,n = X.shape
X_ = np.empty((m,n+1))
X_[:,0] = 1
X_[:,1:] = X
return X_
#损失函数
def _loss(self,y,y_pred):
return np.sum((y-y_pred)**2)/y.size
#计算梯度
def _gradient(self,X,y,y_pred):
return np.matmul(y_pred-y,X)/y.size
#梯度下降
def _gradient_decent(self,w,X,y):
#如果用户指定阈值,启用早期停止法
if self.tol is not None:
loss_old = np.inf
#迭代次数
for step_i in range(self.n_iter):
#做预测
y_pred = self._predict(X,w)
#计算损失
loss = self._loss(y,y_pred)
print("%4i Loss:%s"%(step_i,loss))
#早期停止法
if self.tol is None:
# 如果损失值小于阈值终止迭代
if loss_old - loss <self.tol:
break
less_old = loss
#计算梯度
grad = self._gradient(X,y,y_pred)
w -= self.eta*grad
#做训练
def train(self,X_train,y_train):
X_train = self._preprocessing(X_train)
#初始化参数向量w//这里_作为一个临时的名字,后面不会在用这个变量
_,n = X_train.shape
self.w = np.random.random(n)*0.05
#执行梯度下降训练
self._gradient_decent(self.w,X_train,y_train)
#做预测的内部接口函数//对data的每个数据都进行预测
def _predict(self,X,w):
return np.matmul(X,w)
#做预测
def predict(self,X):
X = self._preprocessing(X)
return self._predict(X,self.w)
data = np.genfromtxt('E:\winequality-red.csv',delimiter = ';',skip_header = True)
X = data[:,:-1]
y = data[:,-1]
#划分数据集
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size = 0.3)
#创建类的实例
ols = olsLinearRegression()
ols.train(X_train,y_train)
y_pred = ols.predict(X_test)
#对X进行列标准化,优化梯度下降
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
'''
#计算特征的均值和标准差
ss.fit(X_train)
StandardScaler(copy = True,with_mean = True,with_std = True)
'''
#标准化
X_train_std = ss.fit_transform(X_train)
X_test_std = ss.fit_transform(X_test)
#创建类的实例
GDS = GDLinearRegression(n_iter = 3700,eta = 0.001,tol = 0.000001)
#训练模型
GDS.train(X_train_std,y_train)
y_pred_gds = GDS.predict(X_test_std)
#性能指标:均方差误差
from sklearn.metrics import mean_squared_error
mes = mean_squared_error(y_pred,y_test)
print("OLS mes ")
print(mes)
mes_ = mean_squared_error(y_pred_gds,y_test)
print(mes_)