基本了解
- 解决回归问题
- 思想简单,实现容易
- 许多强大线性模型的基础
- 结果具有很好的可解释性
- 蕴含机器学习中很多重要思想
简单线性回归
定义: 样本特征只有一个,我们就称之为简单线性回归,比如,我们假设房屋的价格只受到面积的影响,那么这个时候,特征就只有面 积,先假设房屋的面积和房屋的价格存在如下关系:

拟合线的目的就是使得真实值和预测值尽量的小

通过以上画图分析,要获得一个好的机器学习模型,我们要最大化的降低损失函数,这基本也是所有机器学习中的一种思路,比如:线性 回归,多项式回归,逻辑回归,SVM,神经网络等
最小二乘法公式推导

代码实现简单的线性回归
构建测试数据
import numpy as np import matplotlib.pyplot as plt x = np.array([1.,2.,3.,4.,5.]) y = np.array([1.,3.,2.,3.,5.]) # 绘制散点图 plt.scatter(x,y) plt.axis([0,6,0,6]) plt.show()

构建拟合函数
# 获取x和y的均值 x_mean = np.mean(x) y_mean = np.mean(y) # 根据公式推导获取a的值 num = 0.0 d = 0.0 for x_i,y_i in zip(x,y): num += (x_i - x_mean) * (y_i - y_mean) d += (x_i - x_mean) ** 2 a = num / d # 获取b的值 b = y_mean - a * x_mean # 构建目标函数 y_hat = a * x + b # 查看拟合程度 plt.scatter(x,y) plt.plot(x,y_hat,color="r") plt.axis([0,6,0,6]) plt.show() # 查看预测结果 x_test = 6 y_pred = a * x_test + b print("y_pred: ",y_pred) # 5.2

封装简单的线性回归
linearRegression.py import numpy as np class SimpleLinearRegression1: def __init__(self): """ 初始化a和b """ self.a_ = None self.b_ = None def fit(self,x_train,y_train): """ 训练简单线性回归模型 :param x_train: :param y_train: :return: """ assert x_train.ndim == 1, "只有一种特征维度" assert len(x_train) == len(y_train), "训练集的size必须相等" x_mean = np.mean(x_train) y_mean = np.mean(y_train) num = 0.0 d = 0.0 for x,y in zip(x_train,y_train): num += (x - x_mean) * (y - y_mean) d += (x - x_mean) ** 2 self.a_ = num / d self.b_ = y_mean - self.a_ * x_mean return self def predict(self,x_predict): """ 对数据进行预测 :param x_predict: :return: """ assert x_predict.ndim == 1, "只有一种特征维度" assert self.a_ is not None and self.b_ is not None, "必须在fit之后调用" return np.array([self._predict(x) for x in x_predict]) def _predict(self,x_single): """ 对当个数据进行预测 :param x_single: :return: """ return self.a_ * x_single + self.b_ def __repr__(self): return "SimpleLinearRegression1()" test.py reg = SimpleLinearRegression1() reg.fit(x,y) print(reg.predict(np.array([x_test]))) # [5.2] print(reg.a_) # 0.8 print(reg.b_) # 0.39999999999999947
在上面的通过代码实现了简单的线性回归,但是当数据量大起来的时候,通过循环的方式进行计算,性能是比较低的, 所以,一般情况下都是采用向量的方式进行运算

向量化运算代码实现
linearRegression.py class SimpleLinearRegression2: """ 通过向量化运算来实现简单的线性回归 """ def __init__(self): """ 初始化a和b """ self.a_ = None self.b_ = None def fit(self,x_train,y_train): """ 向量化运算 :param x_train: :param y_train: :return: """ assert x_train.ndim == 1, "只有一种特征维度" assert len(x_train) == len(y_train), "训练集的size必须相等" x_mean = np.mean(x_train) y_mean = np.mean(y_train) self.a_ = (x_train - x_mean).dot(y_train - y_mean) / (x_train - x_mean).dot(x_train - x_mean) self.b_ = y_mean - self.a_ * x_mean return self def predict(self,x_predict): """ 对数据进行预测 :param x_predict: :return: """ assert x_predict.ndim == 1, "只有一种特征维度" assert self.a_ is not None and self.b_ is not None, "必须在fit之后调用" return np.array([self._predict(x) for x in x_predict]) def _predict(self,x_single): """ 对当个数据进行预测 :param x_single: :return: """ return self.a_ * x_single + self.b_ def __repr__(self): return "SimpleLinearRegression2()" test.py import numpy as np x = np.array([1., 2., 3., 4., 5.]) y = np.array([1., 3., 2., 3., 5.]) # 对比两种结果的 reg1 = SimpleLinearRegression1() reg1.fit(x,y) print("for style result: ",reg1.predict(np.array([6]))) # for style result: [5.2] reg2 = SimpleLinearRegression2() reg2.fit(x,y) print("vect style result: ",reg2.predict(np.array([6]))) # vect style result: [5.2] # 针对两种实现方案进行性能对比 m = 1000000 big_x = np.random.random(size=m) # 通过np.random.normal(size=m)来添加噪点 big_y = big_x * 2 + 3 + np.random.normal(size=m) ftime = time.time() reg1.fit(big_x,big_y) print("reg1 speed time: ",time.time() - ftime) # reg1 speed time: 1.7602946758270264 vtime = time.time() reg2.fit(big_x,big_y) print("reg2 speed time: ",time.time() - vtime) # reg2 speed time: 0.01894664764404297
衡量线性回归的指标

代码实现MSE,RMSE,MAE
metrics.py def mean_squared_error(y_true, y_predict): """计算y_true和y_predict之间的MSE""" assert len(y_true) == len(y_predict), \ "the size of y_true must be equal to the size of y_predict" return np.sum((y_true - y_predict)**2) / len(y_true) def root_mean_squared_error(y_true, y_predict): """计算y_true和y_predict之间的RMSE""" return sqrt(mean_squared_error(y_true, y_predict)) def mean_absolute_error(y_true, y_predict): """计算y_true和y_predict之间的MAE""" return np.sum(np.absolute(y_true - y_predict)) / len(y_true) # 使用波斯顿房价数据 import numpy as np import matplotlib.pyplot as plt from sklearn import datasets # 使用波斯顿房价数据 boston = datasets.load_boston() # 使用房间数RM特征 print(boston.feature_names) x = boston.data[:,5] y = boston.target # 查看数据分布 plt.scatter(x,y) plt.show()

发现有很多数据都是边界,边界的数据往往都是由于在收集数据的时候做了一些处理,所以要去掉边界的数据
将数据进行清洗后,数据如图:

使用向量化线性回归
from sklearn.model_selection import train_test_split x_train, x_test, y_train, y_test = train_test_split(x50, y50) # 使用向量化的线性回归 reg = SimpleLinearRegression2() reg.fit(x_train,y_train) # 绘制拟合直线 plt.scatter(x_train,y_train) plt.plot(x_train,reg.predict(x_train),color="r") plt.show()

查看测试数据分布
plt.scatter(x_train,y_train) plt.scatter(x_test,y_test,color="y") plt.plot(x_train,reg.predict(x_train),color="r") plt.show()

使用评价标准,查看数据结果
y_predict = reg.predict(x_test) print("mse: ",mean_squared_error(y_test,y_predict)) # mse: 34.691231086414206 print("rmse: ",root_mean_squared_error(y_test,y_predict)) # rmse: 5.889926237773628 print("mae: ",mean_absolute_error(y_test,y_predict)) # mae: 4.273136087045032 # 使用sklearn的mse和mae from sklearn.metrics import mean_absolute_error,mean_squared_error print("sklearn mse: ",mean_squared_error(y_test,y_predict)) # sklearn mse: 34.691231086414206 print("sklearn mae: ",mean_absolute_error(y_test,y_predict)) # sklearn mae: 4.273136087045032
使用R Square来评价回归算法
解释图

代码实现
metrics.py def r2_score(y_true, y_predict): """计算y_true和y_predict之间的R Square""" return 1 - mean_squared_error(y_true, y_predict)/np.var(y_true) from metrics import r2_score from sklearn import datasets from sklearn.model_selection import train_test_split from simpleLinearRegression import SimpleLinearRegression2 boston = datasets.load_boston() x = boston.data[:,5] # 只使用房间数量这个特征 y = boston.target x = x[y < 50.0] y = y[y < 50.0] x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=1) reg = SimpleLinearRegression2() reg.fit(x_train,y_train) # 获取预测结果值 y_predict = reg.predict(x_test) # 计算r2_score my_r2_score = r2_score(y_test,y_predict) print("my r2_score: ",my_r2_score) # my r2_score: 0.46490598547963957 # 使用sklearn的r2_score from sklearn.metrics import r2_score sk_r2_score = r2_score(y_test,y_predict) print("sk r2_score: ",sk_r2_score) # sk r2_score: 0.46490598547963957 # 添加score评分标准为r2_score my_score = reg.score(x_test,y_test) print("my score: ",my_score) # my score: 0.46490598547963957
多元线性回归
简单说就是有很多特征值的样本数据,使用线性回归来解决问题,就叫做多元线性回归
多元线性回归的引入:

从以上示意图中,可知,我们的目标就是求出所有的θ值,使得误差尽可能的小,公式推导流程

针对以上说的,不需要进行归一化处理,那是因为我们进行数据计算的时候,也就是在求θ的过 程中是不存在量纲的问题的,它只是一个系数
使用正规化方程实现多元线性回归算法
import numpy as np from metrics import r2_score class LinearRegression: def __init__(self): """ 初始化系数,截距,θ """ self.coef_ = None # 系数 self.intercept_ = None # 截距 self._theta = None # θ def fit_normal(self,X_train,y_train): """ 通过正规化方程来训练我们的模型 :param X_train: :param y_train: :return: """ assert X_train.shape[0] == y_train.shape[0], "训练数据size必须一致" # 添加值为1的列到X_train中 X_b = np.hstack([np.ones((len(X_train),1)),X_train]) # 通过np.linalg.inv对θ求逆 就是-1 self._theta = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y_train) # 获取截距 self.intercept_ = self._theta[0] # 获取系数 self.coef_ = self._theta[1:] return self def predict(self,X_predict): assert self.intercept_ is not None and self.coef_ is not None, "必须在fit之后调用" 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) 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()" test.py from sklearn import datasets from sklearn.model_selection import train_test_split boston = datasets.load_boston() X = boston.data y = boston.target X = X[y < 50.0] y = y[y < 50.0] X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1) reg = LinearRegression() reg.fit_normal(X_train,y_train) print("系数: ",reg.coef_) print("截距: ",reg.intercept_) # 查看得分 score = reg.score(X_test,y_test) print("r2_score: ",score) # r2_score: 0.7701796876962049
使用sklearn中的线性回归
from sklearn import datasets from sklearn.model_selection import train_test_split from sklearn.linear_model import LinearRegression boston = datasets.load_boston() X = boston.data y = boston.target X = X[y < 50.0] y = y[y < 50.0] X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1) reg = LinearRegression() reg.fit(X_train,y_train) # 查看系数 print("系数: ",reg.coef_) # 查看截距 print("截距: ",reg.intercept_) # 查看得分 score = reg.score(X_test,y_test) # 截距: 37.31584434945723 print("得分: ",score) # 得分: 0.7701796876961614 # 通过KNN来处理回归问题 from sklearn.neighbors import KNeighborsRegressor knn_reg = KNeighborsRegressor() knn_reg.fit(X_train,y_train) print("knn socre: ",knn_reg.score(X_test,y_test)) # knn socre: 0.5751206088954607
总结
-
典型的参数学习,而knn属于非参数学习
-
只能解决回归问题,虽然在很多分类的中,线性回归是基础(比如逻辑回归)
-
需要数据需求进行假设,也就是数据和结果之间存在线性关系
-
对数据具有很强的解释性
浙公网安备 33010602011771号