简述
线性回归(Linear Regression)是机器学习中最基础且广泛的运用算法之一。
回归:统计学术语,表示变量之间的某种数量依存关系,并由此引出回归方程,回归系数
是一种用于 预测连续值的最基本的机器学习算法,它假设目标变量y和特征变量x之间存在的线性关系,并试图找到一条最佳拟合直线来描述这种关系。
y = w * x + b
其中:
y 是预测值
x 是特征变量
w 是权重 (斜率)
b 是偏置 (截距)
线性回归的目标是找到最佳的 w 和 b,使得预测值 y 与真实值之间的误差最小。常用的误差函数是均方误差 (MSE):
MSE = 1/n * Σ(y_i - y_pred_i)^2
其中:
y_i 是实际值。
y_pred_i 是预测值。
n 是数据点的数量。
我们的目标是通过调整 w 和 b ,使得 MSE 最小化。
从图来看点到红线的距离(绿线)便是截距。我们要做的就是找到一个最佳的斜率w。
数理统计中回归分析,用来确定两种或两种以上变量间相互依赖的定量关系的一种统计分析方法,其表达形式为y=wx+e,e为误差服从均值为0的正态分布,其中只有一个自变量的情况称为简单回归,多个自变量的情况叫多元回归。
注意,统计学中的回归并如线性回归非与严格直线函数完全能拟合,所以我们统计中称之为回归用以与其直线函数区别。
接下来我们看这张图
图中的横坐标X1和 X2分别代表着 两个特征 。纵坐标Y代表目标。其中红点代表的就是实际的目标值.而平面上和红点竖向相交的点代表着我们根据线性回归模型得到的点。也就是说实际得到的和预估之间是有一定误差的,这个就是误差项。 因为误差项是真实值和误差值之间的一个差距。那么肯定我们希望误差项越小越好。
然后我们对应整理成线性回归函数:
可能现在的你还没看懂
正文
1.导包
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
2.准备数据
lines = pd.read_csv('USA_Housing.csv')
lines.head()
该标签分别人均收入、房屋年龄、房间数量、区域人口、房屋面积、以及我们准备预测的房屋的具体价格。
3.处理数据
ratio = .8
split = int(len(lines) * ratio)
np.random.seed(10)
lines = np.random.permutation(lines)
train,test = lines[:split],lines[split:]
简单阐述一下代码根据80%的测试集和20%进行训练模型
- np.random.seed() 设置随机种子
- np.random.permutation() 打乱数据
介绍下np.random.permutation
- 可见传入一个int 生成一个1-【int-1】的随机序列,array长度等于int
- 传入一个array,则是将其打乱顺序返回
重点来了!
矩阵求导的知识:
看到这似乎头疼了,其实前面的都不重要,我们只需要最后的推导。
到这一步了,其实我们只需要复现Theta(LaTex我会去学的,🤭)
4.Theta的计算
# 在X矩阵最后添加一列1,代表常数项
X = np.concatenate([x_train, np.ones((len(x_train), 1))], axis=-1)
其实你们会想这行代码干啥用,but我一开始也不知道。
百度后的解释:
这行代码是将输入特征x的最后一列添加一个全1的偏置项,使得输入特征x的最后一列全部为1。这个偏置项的作用是为了能够让模型更好地拟合数据,因为在实际应用中,数据很少完全符合某个数学模型,因此需要在数学模型中引入一些偏置项来调整模型的输出结果,使其更符合实际情况。在这里,我们将全1的偏置项添加到输入特征x中,可以看作是在原有特征的基础上引入了一个常数项,使得模型可以更好地适应数据。
我的理解就是数据太少了,容易过拟合,所以加了个偏置项。
# @ 表示矩阵相乘,X.T表示矩阵X的转置,np.linalg.inv函数可以计算矩阵的逆向
theta = np.linalg.inv(X.T @ X) @ X.T @ y_train
对照公式是不是就清晰易懂了
在回到上面X1与X2,其实就一个二维的数据它的theta的维度即是(2,)
而我们当前的USA_House数据
简单的理解,当我们拟合只有一个特征我们的theta即使w维度是1,当我们多维特征则我们的theta则是一个回归系数列表。说到回归系数就可以看文章Top,theta即是回归系数。
5.回归预测
# 在测试集上使用回归系数进行预测
X_test = np.concatenate([x_test, np.ones((len(x_test), 1))], axis=-1)
y_pred = X_test @ theta
我们可以发现对比公式我们并没有y=wx+b,其实我们预测的y_pred与y的区别其实就是偏置b。
6.计算误差
# 计算预测值和真实值之间的RMSE
rmse_loss = np.sqrt(np.square(y_test - y_pred).mean())
print('RMSE:', rmse_loss)
7.推到可得Linear_Regression
import matplotlib.pyplot as plt # 导入可视化库
import numpy as np # 导入数据处理库
from sklearn import datasets # 导入sklearn自带的数据集
import csv
class LinearRegression():
def __init__(self): # 新建变量
self.w = None
def fit(self, X, y): # 训练集的拟合
X = np.insert(X, 0, 1, axis=1) # 增加一个维度
print (X.shape)
X_ = np.linalg.inv(X.T.dot(X)) # 公式求解 -- X.T表示转置,X.dot(Y)表示矩阵相乘
self.w = X_.dot(X.T).dot(y) # 返回theta的值
def predict(self, X): # 测试集的测试反馈
# 为偏置权值插入常数项
X = np.insert(X, 0, 1, axis=1) # 增加一个维度
y_pred = X.dot(self.w) # 测试集与拟合的训练集相乘
return y_pred # 返回最终的预测值
def mean_squared_error(y_true, y_pred):
#真实数据与预测数据之间的差值(平方平均)
mse = np.mean(np.power(y_true - y_pred, 2))
return mse
def main():
# 第一步:导入数据
# 加载糖尿病数据集
diabetes = datasets.load_diabetes()
# 只使用其中一个特征值(把一个422x10的矩阵提取其中一列变成422x1)
X = diabetes.data[:, np.newaxis, 2] # np.newaxis的作用就是在原来的数组上增加一个维度。2表示提取第三列数据
print (X.shape)
# 第二步:将数据分为训练集以及测试集
x_train, x_test = X[:-20], X[-20:]
print(x_train.shape,x_test.shape) # (422, 1) (20, 1)
# 将目标分为训练/测试集合
y_train, y_test = diabetes.target[:-20], diabetes.target[-20:]
print(y_train.shape,y_test.shape) # (422,) (20,)
#第三步:导入线性回归类(之前定义的)
clf = LinearRegression()
clf.fit(x_train, y_train) # 训练
y_pred = clf.predict(x_test) # 测试
#第四步:测试误差计算(需要引入一个函数)
# 打印平均值平方误差
print ("Mean Squared Error:", mean_squared_error(y_test, y_pred)) # Mean Squared Error: 2548.072398725972
#matplotlib可视化输出
# Plot the results
plt.scatter(x_test[:,0], y_test, color='black') # 散点输出
plt.plot(x_test[:,0], y_pred, color='blue', linewidth=3) # 预测输出
plt.show()
if __name__ == '__main__':
main()
8.Sklearn封装了LinearRegress
from sklearn.linear_model import LinearRegression
# 初始化线性模型
linreg = LinearRegression()
# LinearRegression的方法中已经考虑了线性回归的常数项,所以无须再拼接1
linreg.fit(x_train, y_train)
# coef_是训练得到的回归系数,intercept_是常数项
print('回归系数:', linreg.coef_, linreg.intercept_)
y_pred = linreg.predict(x_test)
# 计算预测值和真实值之间的RMSE
rmse_loss = np.sqrt(np.square(y_test - y_pred).mean())
print('RMSE:', rmse_loss)
那么一看真是白干了!
8.个人总结
- 对于数学公式确实很薄弱
- 学习一下LaTeX不然感觉自己写的文章都Low了几个档次
摘引
https://sevenold.github.io/2018/07/ml-linearRegression-python/
https://blog.youkuaiyun.com/iqdutao/article/details/109402570