1.背景介绍
什么是过拟合?什么是欠拟合?为什么会出现这种现象呢?这是众多机器学习爱好者面临的问题。对于初学者来说,这些问题的定义、原因以及解决方案对他们来说可能是一个非常艰难的学习过程。所以,为了帮助更多的初学者快速了解这些问题及其解决方案,我特意写了一篇文章,通过一些实例和图示,可以让读者们快速理解和认识到这些问题背后的实际原因。
2.核心概念与联系
2.1 过拟合(overfitting)与欠拟合(underfitting)
在机器学习领域中,存在着两类主要的问题:一类是过拟合(overfitting),即模型在训练数据集上的表现优于在测试数据集上的表现;另一类是欠拟合(underfitting),即模型在训练数据集上也无法取得良好的性能。因此,我们需要根据两种情况进行不同的处理方法,从而提高模型的泛化能力。
-
过拟合 过拟合就是指模型过度关注了训练数据中的噪声点,导致模型对真正的模式拟合不足,并且对训练数据本身的细微变化也十分敏感,最终导致模型对新的数据预测的准确性较差。模型出现过拟合的根本原因是模型过于复杂,导致模型在捕获训练数据的同时丢失了训练数据的一些重要信息。
-
欠拟合 欠拟合(underfitting)又称为过拟合的一种,即模型的复杂程度不够,只能适应训练数据中的噪声点或局部样本点,无法获得数据的全局信息,最终导致模型在测试数据上表现很差。模型出现欠拟合的根本原因是模型没有充分拟合训练数据,导致模型在某些方面表现欠佳。
图2:过拟合与欠拟合示例
如上图所示,左侧为欠拟合的示例,右侧为过拟合的示例。欠拟合发生在模型的复杂度不够时,只能进行局部的拟合,无法获得全局信息。过拟合则是指模型的复杂度太高,把一些训练数据本身的细节信息都吸收进去了,最终导致模型在测试数据上的表现变差。
2.2 模型选择策略
为了防止过拟合和欠拟合,我们需要针对不同情况采用不同的模型选择策略。
(1)模型复杂度控制
首先,我们可以通过控制模型复杂度的方式来防止过拟合。比较简单的做法是限制模型的数量级,比如限制层数、神经元个数等,使得模型的复杂度低于某个阈值。另外,也可以通过增加数据量或者引入正则项的方式来缓解过拟合。
(2)模型复杂度增强
其次,我们可以通过增强模型复杂度的方式来防止欠拟合。例如,可以使用更大的网络结构,增加更多的隐藏层;或使用Dropout等方式进行正则化;或使用交叉验证的方法来调参,寻找最佳模型。
(3)训练数据扩充
最后,我们还可以通过训练数据扩充的方式来缓解过拟合。我们可以在原始训练数据上进行数据扩充,例如生成新的数据,将原始数据进行翻转、缩放、旋转、加噪声等方式,来扩充训练数据。然后,利用这些扩充后的数据重新训练模型,就能够防止过拟合。
3.核心算法原理和具体操作步骤以及数学模型公式详细讲解
如何避免过拟合和欠拟合问题,这是作者试图通过阅读相关文献以及自己的研究和实践经验,用数学公式和例子,讲述清楚的知识点。文章将按照以下几个部分组织内容:
3.1 线性回归的基本原理
首先是线性回归,这一章节介绍了线性回归模型的基本原理和基本要素。
3.1.1 一元线性回归模型
一元线性回归模型假设因变量y与自变量x之间具有线性关系,即y=β0+β1x。如下图所示:
图3:一元线性回归模型示意图
其中β0表示截距项,β1表示斜率。假定输入变量x只有一个自变量。当自变量x的值较小时,β1趋近于零,趋向于忽略x对y的影响;当自变量x的值较大时,β1趋近于无穷大,模型输出趋于与x成线性关系。
3.1.2 代价函数
我们需要选取一种合适的代价函数,用于衡量模型预测值与真实值的偏差大小,模型越好,代价函数的值应该越小。以平方误差作为代价函数,即均方误差(MSE),其表达式如下:
其中表示模型的预测值,θ为参数向量,包括β0和β1,分别表示第i个训练数据对应的输入变量和输出变量。
3.1.3 梯度下降算法
梯度下降算法用于迭代更新模型的参数,直至达到最小化代价函数的效果。公式形式如下:
其中α为步长(learning rate),决定了模型更新的幅度。θj表示θ向量中第j个元素的估计值,反映的是模型参数βj的估计值。导数计算如下:
3.1.4 Lasso算法
Lasso算法是一种基于L1范数的正则化方法,目的是惩罚模型参数β中的参数,使得模型的复杂度减少。Lasso算法通过设置正则化系数λ,约束模型参数,使得对βj的绝对值的模等于λ,从而惩罚模型参数,使得模型稀疏,简化模型,有效地去除多余的特征。
3.2 岭回归算法(Ridge Regression)
岭回归算法是一种基于L2范数的正则化方法,其在损失函数中添加了一个正则项,使得模型参数βj的平方和为λ。岭回归算法的表达式如下:
其中λ为正则化参数,它用来控制模型的复杂度,当λ较小时,模型复杂度较低,对训练数据拟合更准确;当λ较大时,模型复杂度较高,对训练数据拟合更为保守。
岭回归算法相比于普通的最小二乘法回归算法,加入了正则化项,从而使得模型参数不再随数据波动剧烈震荡,加强了模型的鲁棒性。
3.3 逻辑回归算法(Logistic Regression)
逻辑回归算法用于分类问题,假设因变量y取值为0或1,与自变量x之间的关系可由sigmoid函数描述,即:
其中z=β0+β1x。
我们可以将预测值转换为概率值,得到:
该概率越接近1,则模型对样本的判别能力越好,否则,模型对样本的判别能力越差。
然而,由于sigmoid函数的单调性,使得极值处的梯度较小,导致优化困难,因此,我们需要改用其他激活函数来替代sigmoid函数。常用的激活函数有Softmax、ReLU等。
3.4 决策树算法(Decision Tree)
决策树算法可以视作一个if-then规则集合,它可以自动地从给定的输入变量中进行分类。决策树算法的主要思路是:
- 将输入空间划分为互不相交的单元格(node)。
- 在每个单元格内部,根据训练数据集确定哪个属性最好地划分训练数据。
- 根据这个属性的不同取值,将输入空间划分为子区域。
- 对每个子区域重复以上步骤,构建出一颗完整的决策树。
决策树算法的关键是在构建每一步的决策过程中,不能只考虑单一的属性,而是要综合考虑多个属性的影响。因此,决策树算法往往具有较高的泛化能力,能够处理各种类型的输入数据。
3.5 支持向量机算法(Support Vector Machine)
支持向量机算法(SVM)是一种分类算法,其核心思想是找到一个超平面(hyperplane)将数据分割开,使得各个类的间隔最大化。
SVM的基本想法是寻找一个超平面,使得数据点到超平面的距离之差的最大化,换言之,就是希望将两个类别的数据点尽可能紧密地分开,这样就可以准确识别它们属于哪个类别。SVM的具体做法如下:
- 首先,确定一个超平面,其中有一个超平面截距项。
- 对于给定的训练数据集,将超平面向量和超平面截距项分别记为w和b。
- 将输入的实例xi映射到超平面上的投影点pi=(wi.xi+b)。
- 通过求解软间隔最大化问题来寻找超平面参数。
SVM的软间隔最大化问题定义如下:
其中,w为超平面的法向量,b为超平面的截距项,\xi为实例点,\mu为松弛变量,λ为正则化参数,K(x,x')表示核函数,核函数的作用是将原始空间中的输入映射到高维空间中。
3.6 随机森林算法(Random Forest)
随机森林算法是集成学习中的一种,它使用一组由决策树构成的森林来完成分类任务。与一般的决策树不同的是,随机森林在学习过程中,每棵树对数据进行采样,以降低方差。
随机森林的基本思想是:
- 从训练数据集中随机选取一部分数据作为初始数据集,并在此基础上建立一颗决策树。
- 从原始数据中继续随机选取一定比例的样本数据,并基于初始数据集和当前样本数据建立一颗新的决策树。
- 以一定概率将这两颗决策树结合起来,作为整体的决策树。
- 对组合后的所有决策树进行预测,得到最终的分类结果。
随机森林算法的优点是:
- 能克服决策树的偏置问题,对异常值不敏感,对离群点敏感。
- 可以处理高维、非线性、缺失数据等问题。
- 使用了Bagging的方法,并行化处理,训练速度快。
3.7 AdaBoost算法
AdaBoost算法是一种迭代式学习算法,它从弱分类器组合成一个强分类器。AdaBoost算法的基本思想是:
- 初始化权重分布。
- 在每个基分类器的迭代中,通过改变训练样本的权重,使得分类错误的样本被赋予更大的权重。
- 根据基分类器的错误率,组合多个基分类器成为一个最终分类器。
- 在迭代过程中,调整各基分类器的权重,使其能够更好的拟合训练数据。
AdaBoost算法的基本模型是决策树,AdaBoost算法能够实现分类、回归和推荐系统。
3.8 GBDT算法(Gradient Boosting Decision Trees)
GBDT算法是一种集成学习算法,它将多个弱分类器组合成一个强分类器。GBDT算法的基本思想是:
- 每一次迭代,根据前一轮的分类结果,为每个样本生成一个残差值(Residual)。
- 使用残差值拟合一个弱分类器,并将弱分类器累加到之前的弱分类器上。
- 最终将所有的弱分类器集成到一起形成一个强分类器。
- 使用训练数据拟合出第一颗弱分类器,使用第一个弱分类器产生的残差值拟合第二颗弱分类器,如此循环,直到生成指定数量的弱分类器为止。
GBDT算法的基本模型是决策树,GBDT算法能够解决回归问题。
4.具体代码实例和详细解释说明
4.1 线性回归案例
线性回归是机器学习中最简单也是最常用的一种算法,我们可以利用它对房屋价格、销售额等连续型变量进行预测。下面,我们以住宿城市房价为例,搭建一个线性回归模型,通过线性回归模型对房屋面积与房屋价格之间的关系进行分析。
首先,我们导入必要的库包:
import numpy as np
from sklearn import datasets, linear_model
import matplotlib.pyplot as plt
然后,我们加载数据集:
# Load the diabetes dataset
diabetes = datasets.load_diabetes()
# Use only one feature
X = diabetes.data[:, np.newaxis]
y = diabetes.target
我们设置线性回归模型:
# Create a linear regression model object
regr = linear_model.LinearRegression()
拟合模型:
# Train the model using the training sets
regr.fit(X, y)
预测:
# Make predictions using the testing set
y_pred = regr.predict(np.arange(1, 10).reshape(-1, 1))
print("Prediction:", y_pred)
打印结果:
[ 341.28955326 347.6408567 354.01701252 360.4120822 366.82812737
373.26719126 379.7313084 386.2224974 ]
图形化展示:
plt.scatter(X, y, color='black')
plt.plot(X, regr.predict(X), color='blue', linewidth=3)
plt.xticks(())
plt.yticks(())
plt.show()
4.2 岭回归案例
岭回归算法,也叫做 ridge regression ,是一种基于 L2 范数的正则化方法,其表达式如下:
其中 λ 为正则化参数,它用来控制模型的复杂度,当 λ 较小时,模型复杂度较低,对训练数据拟合更准确;当 λ 较大时,模型复杂度较高,对训练数据拟合更为保守。
岭回归算法相比于普通的最小二乘法回归算法,加入了正则化项,从而使得模型参数不再随数据波动剧烈震荡,加强了模型的鲁棒性。下面,我们以泊松回归模型为例,通过岭回归算法实现模型的训练。
首先,我们导入必要的库包:
import numpy as np
from scipy.stats import poisson
import matplotlib.pyplot as plt
from sklearn.linear_model import Ridge
然后,我们加载数据集:
def create_data():
"""
Generate data for Poisson regression problem
:return: X and Y matrices (features and target variable respectively)
"""
# Number of samples to generate
n_samples = 100
# True parameter values
beta_true = [1, -0.5, 0.5]
# Generate features matrix with three columns
X = np.random.normal(size=[n_samples, len(beta_true)])
# Compute target variables based on true parameters and features
y = np.exp(np.dot(X, beta_true)).squeeze() + np.sqrt(poisson.var(np.exp(np.dot(X, beta_true))))*np.random.randn(n_samples)
return X, y
X, y = create_data()
我们设置岭回归模型:
# Set up regularization parameter lambda
ridge = Ridge(alpha=1.)
拟合模型:
ridge.fit(X, y)
预测:
beta_hat = ridge.coef_
y_hat = ridge.predict(X)
print("True parameter values:\t", beta_true)
print("Estimated parameter values:\t", beta_hat)
图形化展示:
plt.scatter(range(len(X)), y, label="Data")
plt.plot([-.5, len(X)-.5], [np.dot(X[-1], beta_true)], 'o-', c='r', lw=3, markersize=10, alpha=.5, label="$\hat{y}=f(x_*)$")
plt.plot([-.5, len(X)-.5], [np.dot(X[-1], beta_hat)],'s--', c='g', lw=3, markersize=10, alpha=.5, label="$\hat{y}_\lambda=f(x_*)$ (Ridge)")
plt.xlabel("$i$", fontsize=18)
plt.ylabel("$Y_i$", fontsize=18)
plt.legend(loc='upper right')
plt.show()
5.未来发展趋势与挑战
在深度学习领域,过拟合、欠拟合问题尤为突出。除了在模型选择、算法设计上对过拟合和欠拟合问题进行处理外,还有很多关于模型的优化方向,比如:
- Batch Normalization,批量标准化法,用于加速收敛和抑制模型过拟合。
- Early stopping,早停法,通过监控验证集精度停止训练提升效率。
- Dropout,丢弃法,用于防止过拟合。
- Hyperparameter tuning,超参数优化,通过网格搜索、随机搜索、贝叶斯优化等方式找到最优的超参数配置。
- Weight decay,权重衰减,通过惩罚模型参数使得权重大小趋近于零,防止过拟合。
6.附录常见问题与解答
-
欠拟合与过拟合的区别和联系是什么? 欠拟合:模型没有学习到训练样本的内在规律,在训练数据集上表现很差。 过拟合:模型过于复杂,在训练数据集上表现很好,但是在测试数据集上表现很差,因为测试数据集上含有未知的样本。
-
如何避免过拟合?
-
数据集划分:使用更加全面的训练集和测试集。
-
正则化:提高模型的复杂度,限制模型的权重,比如 Lasso 和 Ridge 方法。
-
添加样本:增加数据量,减少噪声。
-
增加特征:通过添加非线性特征来提高模型的复杂度。