系统学习-线性回归
- 前言
- 线性回归介绍
- 误差函数
- 梯度下降
- 梯度下降示例
- 回归问题常见的评价函数
- 1. MAE, mean absolutely error
- 2. MSE, mean squared error
- 3. R square (决定系数或R方)
- 机器学习建模流程
- 模型正则化
- 拓展阅读
- 作业
链接: 2.系统学习-逻辑回归
前言
线性回归是一种应用非常广泛的回归模型:销量预测、网站流量、生物指标预测等。其中包含的一些知识点例如:梯度下降、L1/L2正则化等在其他机器学习、深度学习模型中也会应用,需要认真掌握。本章会以房价预测案例介绍机器学习建模流程。
链接: Kaggle房价预测竞赛
学习目标:
- 线性回归定义
- 梯度下降法求解回归系数
- 常用的回归任务评价指标
- 机器学习建模流程
- 【选修拓展阅读】:过拟合、正则化,多重共线性
- 完成课后QA及代码作业
线性回归介绍
回归分析是一种预测性的回归建模技术,它研究的是因变量(目标)和自变量(特征)之间的关系,用于预测各种连续变量的值,例如通过父亲的身高、母亲的身高、家庭收入等预测同学的身高,通过地段、面积等预测房屋价格。 线性回归基于简单的假设: 假设自变量和因变量之间的关系是线性的, 即因变量可以表示为自变量中元素的加权和。
我们把特征表示为向量x =(x1,x2,…,xm)项 ,加权权重表示为向量 w=(w1,w2,…,wm),线性回归模型可以表示为:
y = w T x + b y = w^T x + b y=wTx+b
为了方便表示,我们把偏置项也移动到特征里,作为x0 ,且其值总为1,也为偏置项增加一个权重 ,那么线性回归可以表示为:
y = w T x y = w^T x y=wTx
这样就简洁多了,现在问题来了,如何求解影响权重 呢,因为影响因素的值我们是已知的,只要知道权重,我们就可以通过模型得到一个预测结果。
误差函数
一个很自然的想法是,我们首先定义个误差函数,去求解这个误差函数最小的时候所对应的 就可以了。其中对于一个回归问题,我们通常采用MSE (Mean Square Error )作为误差函数:
MSE = 1 n ∑ i = 1 n ( y true ( i ) − w T x ( i ) ) 2 . \text{MSE} = \frac{1}{n} \sum_{i=1}^{n} \left( y_{\text{true}}^{(i)} - w^T x^{(i)} \right)^2. MSE=n1i=1∑n(ytrue(i)−wTx(i))2.
梯度下降
链接: 梯度下降直观理解小视频
梯度是函数关于参数的徧导数,这里以我们的MSE函数为例,grad,
表示函数的某处最小值到最大值的指向与最大值与最小值的差异程度。那么意味着梯度不仅告诉我们,函数变大的方向,也告诉了我们变大的程度。我们的函数(MSE)是越小越好,那么我们只要朝着梯度的反方向迈进就可以了。
在上图中,我们绘制了一个函数 func(x1,x2),其中底部的两个坐标为 ,纵轴坐标为函数对应的取值,底部的箭头是在不同 取值下的梯度。可以看到,梯度总是指向让函数取值变大的方向,梯度的箭头越长意味着变化越大。因此,我们只需要让 的取值,不断朝着梯度的反方向更新,就可以一步步走向函数的最低点。
利用求导公式可知,梯度等于:
∂ MSE ∂ w i = − 1 n ∑ j = 1 n 2 ⋅ ( y true ( j ) − w T x ( j ) ) ⋅ x i ( j ) . \frac{\partial \text{MSE}}{\partial w_i} = -\frac{1}{n} \sum_{j=1}^{n} 2 \cdot \left( y_{\text{true}}^{(j)} - w^T x^{(j)} \right) \cdot x_i^{(j)} . ∂wi∂MSE=−n1j=1∑n2⋅(ytrue(j)−wTx(j))⋅xi(j).
那么,在线性回归中,我们可以沿着梯度的反方向进行更新:
w i = w i − learning_rate ⋅ ∂ MSE ∂ w i . w_i = w_i - \text{learning\_rate} \cdot \frac{\partial \text{MSE}}{\partial w_i} . wi=wi−learning_rate⋅∂wi∂MSE.
梯度下降示例
下面我们就利用梯度下降,来解决一个房价预测的问题。
import numpy as np x = np.array([1, 2, 1.2, 1.5])
y = x * 2 + np.random.randn(4) print("假设我们有一组房屋的面积数据:")
print(x)
print("其对应的房屋价格:")
print(y)
import matplotlib.pyplot as plt
%matplotlib inline
# 房屋面积和房价可以从散点图看出具备某种线性关系plt.scatter(x, y)
plt.xlabel("house area")
plt.ylabel("house price")
# 定义我们的误差函数def mse(y_true, y_pred): return np.mean((y_true - y_pred) ** 2) #隐藏了累加和除以 n 的细节# 定义梯度的计算公式def grad(y_true, w, x): return np.mean(2 * (y_true - w*x) * -x) # 定义梯度下降迭代过程def grad_decent(y_true, w, x, learning_rate): w = w - learning_rate * grad(y_true, w, x) return w
w = np.random.rand() # w赋值一个随机初始值learning_rate = 0.001
num_iteration = 2000
loss = []
for step in range(num_iteration): w = grad_decent(y, w, x, learning_rate) loss_step = mse(y, w*x) loss.append(loss_step)
plt.plot(loss)
plt.xlabel("#iteration")
plt.ylabel("mse_loss")
plt.scatter(x, y, label="true")
plt.scatter(x, w*x, label="predict", marker="^")
plt.legend()
回归问题常见的评价函数
1. MAE, mean absolutely error
MAE = 1 n ∑ i = 1 n ∣ y true ( i ) − y pred ( i ) ∣ . \text{MAE} = \frac{1}{n} \sum_{i=1}^n \left| y_{\text{true}}^{(i)} - y_{\text{pred}}^{(i)} \right| . MAE=n1i=1∑n ytrue(i)−ypred(i) .
计算简单,但是在0处不可导,所以在使用梯度下降需要特殊处理,值越大则误差越大,值域在0到正无穷大。
我们用 来计算一下之前的预测误差:
y_pred = w * x
from sklearn.metrics import mean_absolute_error as mae
mae(y, y_pred)
2. MSE, mean squared error
在梯度下降已经介绍,这里直接计算:
from sklearn.metrics import mean_squared_error as mse
mse(y, y_pred)
领域基于MSE,也有一些衍生指标,比如RMSE,MSE,就是对 开根号,这里不再详述。
3. R square (决定系数或R方)
统计领域常用,但是在机器学习领域用的很少的一种回归评价指标,值域在负无穷大到1,越接近1越好,代表预测值对真实值解释程度越高。
R 2 = 1 − 残差平方和 总平方和 . R^2 = 1 - \frac{\text{残差平方和}}{\text{总平方和}} . R2=1−总平方和残差平方和.
残差平方和 = ∑ i = 1 n ( y true ( i ) − y pred ( i ) ) 2 . \text{残差平方和} = \sum_{i=1}^n \left( y_{\text{true}}^{(i)} - y_{\text{pred}}^{(i)} \right)^2 . 残差平方和=i=1∑n(ytrue(i)−ypred(i))2.
总平方和 = ∑ i = 1 n ( y true ( i ) − y ˉ ) 2 . \text{总平方和} = \sum_{i=1}^n \left( y_{\text{true}}^{(i)} - \bar{y} \right)^2 . 总平方和=i=1∑n(ytrue(i)−yˉ)2.
from sklearn.metrics import r2_score as r2 r2(y, y_pred)
机器学习建模流程
我们以Kaggle房价预测竞赛为例,利用线性回归,搭建一套完整的机器学习建模流程。
- 加载数据&分析
- 数据处理
- 特征工程
- 数据划分
- 模型训练
- 模型评估
# 加载数据
import pandas as pdtrain = pd.read_csv("./house-prices-advanced-regression-techniques/train.csv")
test = pd.read_csv("./house-prices-advanced-regression-techniques/test.csv")
sample_submission = pd.read_csv("./house-prices-advanced-regression-techniques/sample_submission.csv")# 查看数据形状
print("Train shape:", train.shape) # (1460, 81)
print("Test shape:", test.shape) # (1459, 80)# 查看前几行
print(train.head())
print(test.head())# 提取目标变量 SalePrice
target = train['SalePrice'].values
test_ids = test['Id'].values# 删除不必要的列
train.drop(['SalePrice', 'Id'], axis=1, inplace=True)
test.drop(['Id'], axis=1, inplace=True)# 合并训练和测试数据,方便统一处理
data = pd.concat([train, test], axis=0).reset_index(drop=True)# 检查数据类型
print(data.dtypes.value_counts())# 丢弃缺失比例>80% 的特征
data.drop(data.isnull().mean()[data.isnull().mean() >0.8].index.tolist(), axis=1,inplace=True) # 处理缺失值:数值型用中位数填充,类别型用 "NULL" 填充
data.loc[:, data.dtypes != 'object'] = data.loc[:, data.dtypes != 'object'].fillna(data.loc[:, data.dtypes != 'object'].median()
)
data.loc[:, data.dtypes == 'object'] = data.loc[:, data.dtypes == 'object'].fillna("NULL")# 确保没有缺失值
print("缺失值总数:", data.isnull().sum().sum())# 对目标变量进行对数变换
import numpy as np
import seaborn as sns
import matplotlib.pyplot as pltsns.displot(target)
sns.displot(np.log1p(target))# 恢复对数化后的目标值
sns.displot(np.expm1(np.log1p(target)))# 对类别型特征进行 OneHot 编码
from sklearn.preprocessing import OneHotEncodercat_feature = OneHotEncoder().fit_transform(data[data.columns[data.dtypes == 'object']])
print("类别特征形状:", cat_feature.shape)# 对数值型特征进行标准化
from sklearn.preprocessing import StandardScalernum_feature = StandardScaler().fit_transform(data[data.columns[data.dtypes != 'object']])
print("数值特征均值:", num_feature.mean(0))
print("数值特征标准差:", num_feature.std(0))# 合并类别特征和数值特征
feature = np.concatenate([cat_feature.todense(), num_feature], axis=1)
print("合并后特征形状:", feature.shape)# 划分训练和测试数据
num_train = len(train)
train_feature = feature[:num_train]
test_feature = feature[num_train:]# 对目标变量标准化
from sklearn.preprocessing import StandardScalertarget_log1p = np.log1p(target)
scaler = StandardScaler()
target_log1p_scale = scaler.fit_transform(target_log1p.reshape(-1, 1))# 模型训练
from sklearn.linear_model import Ridgemodel = Ridge()
model.fit(train_feature, target_log1p_scale)# 模型预测
def predict(model, feature):pred = model.predict(feature)pred = scaler.inverse_transform(pred)pred = np.expm1(pred)return predtrain_pred = predict(model, train_feature)# 计算均方误差
from sklearn.metrics import mean_squared_error as msetrain_mse = np.sqrt(mse(target, train_pred))
print("训练集均方误差:", train_mse)# 测试集预测
test_pred = predict(model, test_feature)# 保存结果
sample_submission["SalePrice"] = test_pred.reshape(-1)
sample_submission.to_csv("submission.csv", index=False)
模型正则化
L1&L2 正则化
通过在误差函数中添加关于参数的1阶或2阶模,达到限制模型能力的作用。
L 1 = MSE + ∑ ∣ w i ∣ . L1 = \text{MSE} + \sum |w_i| . L1=MSE+∑∣wi∣.
L 2 = MSE + ∑ w i 2 . L2 = \text{MSE} + \sum w_i^2 . L2=MSE+∑wi2.
其中L1正则化线性回归叫做Lasso
,
L2正则化线性回归叫做Ridge.在sklearn中可以很方便的调用。
from sklearn.linear_model import Ridge, Lasso, LinearRegression
L1&L2如何发挥作用?
拓展阅读
链接: 欠拟合、过拟合及如何防止过拟合
链接: 机器学习中常常提到的正则化到底是什么意思?
链接: 多重共线性问题
作业
- 回答L1与L2正则化的线性回归分别具备什么特性?
- 注册Kaggle平台,阅读文档了解Kaggle平台使用,参加Kaggle房价预测竞赛,分别采用普通LinearRegression/Ridge(L2正则化线性回归)/Lasso(L1正则化线性回归)进行建模,尝试构造更多的
特征,对比三种模型精度,最优模型Kaggle提交得分低于0.14