本次我们利用之前向量化的梯度下降法进行波士顿房价预测。
1. 线性回归模型:里面包含正规化方程训练模型和梯度下降法训练模型的方式。
import numpy as np
from sklearn.metrics import r2_score
class LinearRegression:
# 初始化LinearRegression模型
def __init__(self):
self.coef_ = None
self.interception_ = None
# theta为私有变量
self._theta = None
# 使用正规化方程
def fit_normal(self, X_train, y_train):
assert X_train.shape[0] == y_train.shape[0], \
"X_train和y_train大小必须一致"
X_b = np.hstack([np.ones((len(X_train), 1)), X_train])
self._theta = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y_train)
self.interception_ = self._theta[0]
self.coef_ = self._theta[1:]
return self
def predict(self, X_predict):
assert self.interception_ is not None and self.coef_ is not None, \
"必须先拟合才能进行预测!"
assert X_predict.shape[1] == len(self.coef_), \
"预测值的特征数必须和训练集个数一致!"
X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict])
return X_b.dot(self._theta)
# 根据测试数据集X_test和y_test确定当前模型的准确度
def score(self, X_test, y_test):
y_predict = self.predict(X_test)
return r2_score(y_test, y_predict)
def fit_gd(self, X_train, y_train, eta=0.01, n_iters=1e4):
"""
根据训练数据集X_train, y_train, 使用梯度下降法训练Linear Regression模型
:param X_train:
:param y_train:
:param eta:
:param n_iters:
:return:
"""
assert X_train.shape[0] == y_train.shape[0], "训练集X和y必须大小一致"
def J(theta, X_b, y):
"""
求代价函数
:param theta: 参数值
:param X_b:
:param y:
:return: 代价函数值
"""
try:
return np.sum((y - X_b.dot(theta)) ** 2) / len(y)
except:
return float('inf')
def dJ(theta, X_b, y):
return X_b.T.dot(X_b.dot(theta) - y) * 2. / len(X_b)
def gradient_descent(X_b, y, initial_theta, eta, n_iters=1e4, epsilon=1e-8):
theta = initial_theta
i_iter = 0
while i_iter < n_iters:
gradient = dJ(theta, X_b, y)
last_theta = theta
theta = theta - eta * gradient
if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):
break
i_iter += 1
return theta
X_b = np.hstack([np.ones((len(X_train), 1)), X_train]) # 为原先的X添加一列,(())
init_theta = np.zeros(X_b.shape[1])
self._theta = gradient_descent(X_b, y_train, init_theta, eta, n_iters)
self.interception_ = self._theta[0]
self.coef_ = self._theta[1:]
return self
2. 编写一个测试类用于测试。
(1)导入对应的包:
from sklearn import datasets
from demo1_knn.model_selection import train_test_split
from LinearRegression import LinearRegression
from sklearn.preprocessing import StandardScaler
(2)获取波士顿房价部分数据集:
def load_boston_data():
"""
加载波士顿数据集并获取相应数据
:return:
"""
boston = datasets.load_boston()
X = boston.data
y = boston.target
X = X[y < 50.0]
y = y[y < 50.0]
return X, y
(3)主函数:
if __name__ == '__main__':
X, y = load_boston_data()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_radio=0.2, seed=666)
# 使用正规化方程训练模型
reg = LinearRegression()
reg.fit_normal(X_train, y_train)
print(reg.score(X_test, y_test)) # 0.8129794056212729
# 使用梯度下降法训练模型
reg2 = LinearRegression()
# reg2.fit_gd(X_train, y_train)
reg2.fit_gd(X_train, y_train, eta=0.000001)
print(reg2.score(X_test, y_test)) # 0.27586818724477224
# 使用梯度下降法前进行数据归一化
standardScaler = StandardScaler()
standardScaler.fit(X_train)
X_train_standard = standardScaler.transform(X_train)
reg3 = LinearRegression()
reg3.fit_gd(X_train_standard, y_train)
X_test_standard = standardScaler.transform(X_test)
print(reg3.score(X_test_standard, y_test)) # 0.8129873310487505
使用梯度下降法时,最好进行数据归一化。若所有数值不在一个维度上,会影响梯度计算的结果。reg3就是在梯度下降法之前使用了数据归一化处理。