线性回归module封装
两个类分别实现最小二乘法及梯度下降拟法拟合
import numpy as np
#最小二乘法拟合
class OSLlinearregression:
def _ols(self, x, y):
'''最小二乘法估计w'''
return np.linalg.pinv((x.T).dot(x)).dot(x.T).dot(y)
def preprocess_data_X(self, X):
'''数据预处理,扩展X 第一列为1'''
m, n = X.shape
tmp = np.ones(m).reshape(-1,1)
X_ = np.hstack([tmp, X]) #将全1列 放到第一列
return X_
def train(self, X_train, Y_train):
'''训练模型'''
X_train = self.preprocess_data_X(X_train)
self.w = self._ols(X_train, Y_train)
def predict(self, X):
X = self.preprocess_data_X(X)
return np.matmul(X, self.w)
# 梯度下降算法拟合
class GDLinearRegression():
def __init__(self, n_iter = 20, eta = 1e-3, tol = None):
'''模型参数初始化'''
self.n_iter = n_iter # 迭代次数
self.eta = eta # 学习率
self.tol = tol # 误差变化阈值
self.w = None # 模型参数w
def _loss(self, y, y_pred):
'''计算损失值'''
return np.sum((y_pred - y)**2) /(2 * y.size)
def _gradient(self, X, y, y_pred):
'''计算梯度'''
return np.dot(y_pred - y, X) /y.size
def _predict(self, X, w):
'''内部接口,即为假设函数H(x)'''
return np.dot(X, w)
def preprocess_data_X(self, X):
'''数据预处理,添加全1列到首列'''
m, n = X.shape
temp = np.ones(m).reshape(m,1)
X_ = np.hstack([temp, X])
return X_
def _gradient_dexcent(self, w, X, y):
'''梯度下降算法'''
# 若指定tol 则启用早期停止法
if self.tol is not None:
loss_old = np.inf # np.inf 表示无穷大
#用梯度下降算法,最多迭代n_iter次
for step_i in range(self.n_iter):
y_pred = self._predict(X, w)
loss = self._loss(y,y_pred)
print(str(step_i) + 'Loss:' + str(loss) )
#早期停滞法
if self.tol is not None:
#如果当前损失值下降小于阈值,则停止迭代
if (loss_old - loss) < self.tol:
break
loss_old = loss
grad = self._gradient(X, y, y_pred)
w = w - self.eta * grad
def train(self, X_train, Y_train):
X_train = self.preprocess_data_X(X_train)
m, n = X_train.shape
self.w = np.random.random(n) * 0.05
self._gradient_dexcent(self.w, X_train, Y_train)
def predict(self,X):
X = self.preprocess_data_X(X)
return np.dot(X,self.w)
线性回归的实战项目
使用以上的OLSLinearRegression和GDLinearRegression预测红酒口感。
数据集下载地址
数据集中包含1599条数据,其中每一行包含红酒的11个化学特征以及专家评定的口感值。虽然口感值只是3~8的整数,但我们依然把该问题当作回归问题处理,而不是当作包含6种类别(3~8)的分类问题处理。如果当作分类问题,则预测出的类别间无法比较好坏,例如我们不清楚第1类口感是否比第5类口感好,但我们明确知道5.3比4.8口感好。
import numpy as np
from linear_regression import GDLinearRegression, OSLlinearregression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error
#调用Numpy的genfromtxt函数加载数据集
data = np.genfromtxt('winequality-red.csv', delimiter=';', skip_header=True)
#将原始数据X、Y分开
X = data[:,:-1]
y = data[:,-1]
# 对数据集进行切割 切割为训练集、测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.4)
# 创建OSL模型并训练
ols_lr = OSLlinearregression()
ols_lr.train(X_train, y_train)
# 利用拟合出的模型计算测试集的预测值
y_osl_pred =ols_lr.predict(X_test)
# 调用sklearn中的算法计算均方误差
mse = mean_squared_error(y_test, y_osl_pred)
print('最小二乘法拟合结果:')
print('均方误差为:'+str(mse))
# 调用sklearn中的算法计算平均绝对误差
mae = mean_absolute_error(y_test, y_osl_pred)
print('平均绝对误差:'+str(mae))
# 创建GD模型并训练
gd_lr = GDLinearRegression(n_iter=500, eta=0.01)
gd_lr.train(X_train, y_train)
# 利用拟合出的模型计算测试集的预测值
y_gd_pred =gd_lr.predict(X_test)
# 调用sklearn中的算法计算均方误差
mse = mean_squared_error(y_test, y_gd_pred)
print('梯度下降拟合结果')
print('均方误差为:'+str(mse))
# 调用sklearn中的算法计算平均绝对误差
mae = mean_absolute_error(y_test, y_gd_pred)
print('平均绝对误差:'+str(mae))