线性回归(正规方程法,梯度下降法,R_square测试),以房价预测为例
线性回归:对于存在线性关系的数据(如房价与房间数,楼层数等之间的关系),根据已知数据拟合出其线性关系(求出表示房间数,楼层数x与房价y的关系的函数)
可以用正规方程法,梯度下降法解决线性回归问题。正规方程法时间复杂度比梯度下降法高很多。
正规方程法
线性回归中需要通过训练已有数据拟合出的目标函数
如何拟合出目标函数?使损失函数尽量小
一顿数学化简后得出正规方程解
代码
首先初始化
import numpy as np
from sklearn.metrics import r2_score
class LinearRegression:
def __init__(self):
self.coef_=None
self.interception_=None #偏移量,常数,即theta[0]
self._theta=None
正规方程解(开始训练过程)
def fit_normal(self,X_train,y_train):
assert X_train.shape[0]==y_train.shape[0]
X_b=np.hstack([np.ones((len(X_train),1)),X_train]) #将要训练的x以矩阵形式传入,加一列常数项的系数,全为1,对应偏移量,方便向量化计算
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
训练结束,代入待预测的特征值,返回所求y
def predict(self,X_predict):
assert self.intercept_ 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]) #将要预测的x加一列,全为1
return X_b.dot(self._theta)
R_Square测试准确性(直接用sklearn里已有的函数)
手动实现及原理见梯度下降法代码
这里把数据集所有数据拿来训练了,没有留出测试数据,数据集的分割详见阶梯下降算法
def score(self,X_test,y_test):
y_predict=self.predict(X_test)
return r2_score(y_test,y_predict)
def __repr__(self):
return "LinearRegression()"
最后导入数据集
首先数据预处理一番
import numpy as np
import matplotlib .pyplot as plt
from sklearn.datasets import load_boston
boston=load_boston() #sklearn的自带数据
X_train=boston.data #调用库自带数据集
y_train=boston.target
X_train=X_train[y_train<50.0] #排除训练数据中比较奇怪而特殊,影响结果的数据
y_train=y_train[y_train<50.0]
print("训练数据的维度:",boston.data.shape)
#实例化类 LinearRegression
modle=LinearRegression()
modle.fit_normal(X_train,y_train)
print(modle.coef_) #拟合出所求函数
print(modle.interception_)
批量梯度下降法
导入需要的包
import numpy as np
import matplotlib .pyplot as plt
损失函数
def j(theta,X_b,y): #损失函数
try:
return np.sum((y-X_b.dot(theta))**2)/len(X_b)
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_decent(X_b,y,initial_theta,eta,n_iters=1e4,epsilon=1e-8): #eta:学习率
theta=initial_theta
i_iter=0 #i_iter:次数
while i_iter<n_iters: #限制次数10000次
gradient=dj(theta,X_b,y) #求梯度(偏导数)
last_theta=theta #记录进行算法前的theta,用于算完比,两次之间差距很小说明找到目标了
theta=theta-eta*gradient #梯度下降法的核心
if(abs(j(theta,X_b,y)-j(last_theta,X_b,y))<epsilon): #代入函数本身,两次下降函数值间距小于10的-8次方就算足够精确了,找到结果
break
i_iter+=1 #记下次数
return theta
导入波士顿房价预测数据集
并进行数据预处理
from sklearn.datasets import load_boston
boston=load_boston() #sklearn的自带数据导入
X_b = boston.data
initial_theta=np.zeros(X_b.shape[1]+1) #初始化theta(0)theta的大小是x的13个特征再+1个偏移量
#shape[1] 0.1.2.3代表第几维的维数
y=boston.target
eta=0.01 #学习率取0.01比较合适
对数据归一化,避免因训练数据过大过小造成结果不准确
from sklearn.preprocessing import StandardScaler #归一化所需的包
StandardScaler=StandardScaler()
StandardScaler.fit(X_b) #归一化
X_b=StandardScaler.transform(X_b)
X_b=np.hstack([np.ones((len(X_b),1)),X_b]) #给x加一列(全为1),对应theta的偏移量,方便向量化运算
分割数据,分为训练数据和测试数据
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test=train_test_split(X_b,y) #最好加一个种子,让随机分割的数据可以重复利用。然鹅我没加种子
print("训练数据量:",x_train.shape)
print("测试数据量:",x_test.shape)
#调用算法,求出theta
theta=gradient_decent(X_b,y,initial_theta,eta)
print("theta的维度:",theta.shape)
#开始预测!
def predict(X_predict):
return X_predict.dot(theta) # 返回预测的结果y
y_predict=predict(x_test)
R_square法测试准确度
def mse(y_true,y_predict): #公式,其实有函数可以直接求MSE
#assert len(y_true)==len(y_predict)
return np.sum((y_true-y_predict).dot((y_true-y_predict).T))/len(y_true)
def R_Square(y_true,y_predict):
return 1-mse(y_true,y_predict)/np.var(y_true)
Rsquare=R_Square(y_test,y_predict)
print("算法准确度:",Rsquare)