前言
与KNN分类任务预测的输出为离散型不同. 在机器学习中,回归任务是用于预测连续数值型变量的任务。回归任务在很多领域都有着广泛的应用.
简单的线性回归
在一个回归问题中,很显然模型选择和好坏会直接关系到将来预测结果的接近程度.即寻找到一条直线,最大的“拟合”样本特征和样本标记输出的关系.
如图所示,黑点是样本特征.蓝色直接为最大“拟合”直线
y
=
a
x
+
b
y=ax+b
y=ax+b
公式中的参数a,b即《什么是机器学习》提到的模型参数,线性回归算法即为参数学习.
损失函数
对于第一个样本点 [ x ( i ) , y ( i ) ] [x^{(i)},y^{(i)}] [x(i),y(i)],根据直线方程
- 预测值为: y ^ ( i ) = a x ( i ) + b \hat y^{(i)}=ax^{(i)}+b y^(i)=ax(i)+b
- 用最小二乘法定义误差: ∑ i = 1 m ( y ( i ) − a x ( i ) − b ) 2 \displaystyle\sum_{i=1}^m (y^{(i)}-ax^{(i)}-b)^2 i=1∑m(y(i)−ax(i)−b)2
对loss function 求偏导得到(微分中值定理:值大最时导数为0):
计算技巧: 可以把a的计算转换成向量点乘的方式
即: ∑ i = 1 m ( x ( i ) − x ˉ ) ( y ( i ) − y ˉ ) \displaystyle\sum_{i=1}^m (x^{(i)}-\bar x) (y^{(i)}-\bar y) i=1∑m(x(i)−xˉ)(y(i)−yˉ)转成向量
[ x ( 1 ) − x ˉ x ( 2 ) − x ˉ . . . x ( m ) − x ˉ ] ∗ [ y ( 1 ) − x ˉ y ( 2 ) − x ˉ . . . y ( m ) − x ˉ ] \begin{bmatrix} x^{(1)} - \bar x \\ x^{(2)} - \bar x \\ ... \\ x^{(m)} - \bar x \end{bmatrix} * \begin{bmatrix} y^{(1)} - \bar x & y^{(2)} - \bar x & ... & y^{(m)} - \bar x \end{bmatrix} x(1)−xˉx(2)−xˉ...x(m)−xˉ ∗[y(1)−xˉy(2)−xˉ...y(m)−xˉ]计算效率显著提升,因为CPU对向量运算有优化.
如何评价一模型的好坏
衡量标准 : ∑ i = 1 m ( y t e s t ( i ) − y ^ t e s t ( i ) ) 2 衡量标准:\displaystyle\sum_{i=1}^m (y_{test}^{(i)}-\hat y_{test}^{(i)})^2 衡量标准:i=1∑m(ytest(i)−y^test(i))2
如果m很大,误差很小,但是累计起来很大
- 均方误差(MSE): 1 m ∑ i = 1 m ( y t e s t ( i ) − y ^ t e s t ( i ) ) 2 \frac 1 m \displaystyle\sum_{i=1}^m (y_{test}^{(i)}-\hat y_{test}^{(i)})^2 m1i=1∑m(ytest(i)−y^test(i))2
- 均方根误差(RMSE): 1 m ∑ i = 1 m ( y t e s t ( i ) − y ^ t e s t ( i ) ) 2 \sqrt {\frac 1 m \displaystyle\sum_{i=1}^m (y_{test}^{(i)}-\hat y_{test}^{(i)})^2} m1i=1∑m(ytest(i)−y^test(i))2
- 平均绝对值误差(MAE): 1 m ∑ i = 1 m ∣ y t e s t ( i ) − y ^ t e s t ( i ) ∣ \frac 1 m \displaystyle\sum_{i=1}^m |y_{test}^{(i)}-\hat y_{test}^{(i)}| m1i=1∑m∣ytest(i)−y^test(i)∣
RMSE > MAE,因此RMSE 作为误差标准,能够更好的减小误差.
但是以上的指标都带着单位,这意味着我们无法对不同的模型进行比较,因此我们需要一种没有单位的指标 R Squared(
R
2
R^2
R2)
案例代码
我们将使用scikit-learn内置的波士顿房价数据集。波士顿房价数据集是一个经典的机器学习数据集,包含506个样本,每个样本有13个特征,如犯罪率、房产税率等。我们的目标是根据这些特征预测房屋价格
import numpy as np
import pandas as pd
## 准备数据, 因为官方内置函数load_boston在1.2版本移除了
data_url = "http://lib.stat.cmu.edu/datasets/boston"
raw_df = pd.read_csv(data_url, sep=r"\s+", skiprows=22, header=None)
X = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :3]])
y = raw_df.values[1::2, 2]
## 选择回归器,将使用线性回归作为我们的回归器
from sklearn.linear_model import LinearRegression
reg = LinearRegression()
## 拆分数据集,我们通常将数据集拆分为训练集和测试集。训练集用于训练模型,测试集用于评估模型的性能。我们将数据集拆分为70%的训练集和30%的测试集。
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 特征工程-标准化
from sklearn.preprocessing import StandardScaler
transfer = StandardScaler()
X_train = transfer.fit_transform(X_train)
X_test = transfer.fit_transform(X_test)
## 训练回归器
reg.fit(X_train, y_train)
## 评估回归器:当回归器训练完成后,我们需要使用测试集来评估回归器的性能。我们可以使用predict()函数对测试集进行预测,并使用score()函数计算回归器的性能指标,如均方误差、R平方等
y_pred = reg.predict(X_test)
mse = np.mean((y_pred - y_test) ** 2)
r2 = reg.score(X_test, y_test)
print("Mean Squared Error: ", mse)
print("R Squared: ", r2)
多元线性回归
我们将一元变量推广到多原变量,设多元函数式为
我们使用线性代数的向量概念对该式进行整理,记
w
0
=
b
w_0=b
w0=b,那么此时,我们构造一个权重向量
w
w
w和特征向量
x
x
x
那么此时,我们上述的多元函数式则可以写成
f
(
x
)
=
w
T
x
f(x)=w^Tx
f(x)=wTx.损失函数写成如下形式
对L(w)化简:
对L(w)求偏导:
使用(求导)正规方程需要注意的问题:
- 正规方程仅适用于线性回归模型,不可乱用;
- 若 X T X X^TX XTX为奇异矩阵则无法求其逆矩阵
- 使用正规方程时应该注意当特征数量规模大于10000时, ( X T X ) − 1 (X^TX)^{-1} (XTX)−1求其逆矩阵的时间复杂度会很高
梯度下降法
梯度下降法是用来计算函数最小值的。它的思路很简单,想象在山顶放了一个球,一松手它就会顺着山坡最陡峭的地方滚落到谷底:
由导数知识我们不难发现,要使损失函数L(w)的值减小,我们只需让回归系数向与当前位置偏导数符号相反的方向更新即可,如下图所示:
于是,我们可以得到最基本的梯度下降算法的更新步骤:
其中,超参数
η
\eta
η代表学习速率(learning_rate),即单次更新步长。
η
\eta
η值的选择需谨慎,如果太小更新速率太慢则很难到达;如果太大则容易直接越过极值点。
寻找合适的步长
η
\eta
η是个手艺活,在工程中可以将上图画出来,根据图像来手动调整
- f ( x ) f(x) f(x)往上走(红线),自然是 η \eta η过大,需要调低
- f ( x ) f(x) f(x)一开始下降特别急,然后就几乎没有变化(棕线),可能是 η \eta η较大,需要调低
- f ( x ) f(x) f(x)几乎是线性变化(蓝线),可能是 η \eta η过小,需要调高
另一个问题,并不是函数都有唯一的极值,有可能找到的是:局部最优解
解决方法: 多运行几次,随机初始点
由于不同特征的单位不同,梯度下降的方向也会受到一些数据偏大或者偏小的数字的影响,导致数据溢出,或者无法收敛到极小值。
解决方法: 数据归一化
小批量梯度下降(MBGD)
案例代码
from sklearn.linear_model import SGDRegressor
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
import numpy as np
import pandas as pd
# 导入必要的库
data_url = "http://lib.stat.cmu.edu/datasets/boston"
raw_df = pd.read_csv(data_url, sep=r"\s+", skiprows=22, header=None)
X = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :3]])
y = raw_df.values[1::2, 2]
# 将数据分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 特征工程-标准化
from sklearn.preprocessing import StandardScaler
transfer = StandardScaler()
X_train = transfer.fit_transform(X_train)
X_test = transfer.fit_transform(X_test)
# 使用指定参数创建SGDRegressor
sgd_regressor = SGDRegressor(loss="squared_error", fit_intercept=True,max_iter=100000, learning_rate='invscaling', eta0=0.01)
# 将模型拟合到训练数据
sgd_regressor.fit(X_train, y_train)
# 在测试集上进行预测
y_pred = sgd_regressor.predict(X_test)
# 计算均方误差
mse = mean_squared_error(y_test, y_pred)
print("均方误差:", mse)
- loss=“squared_loss”: 此参数指定用于优化的损失函数。在线性回归中,通常使用平方损失,最小化残差的平方和。
- fit_intercept=True: 将该参数设置为True允许模型对数据进行拟合,引入截距项(偏置),这在数据没有零中心分布时是必要的。
- learning_rate=‘invscaling’: 学习率决定了优化过程中每次迭代的步长。'invscaling’会随着时间调整学习率,这在实现收敛时可能更有优势。
- eta0=0.01: 当使用’invscaling’学习率时,此参数设置了初始学习率。
主要参考
《机器学习实战 原理/代码:Linear-Regression(线性回归)》
《scikit-learn:回归任务》
《非常详细的线性回归原理讲解》
《什么是梯度下降法?》