在机器学习领域,模型的泛化能力是衡量其性能的重要指标之一。然而,在实际应用中,经常会遇到两种极端情况:拟合不足(underfitting)和过拟合(overfitting)。拟合不足指的是模型过于简单,无法捕捉数据中的复杂关系;而过拟合则是指模型过于复杂,以至于学习到了数据中的噪声,导致模型在新数据上的表现不佳。本文将通过一个具体的例子,展示如何使用线性回归模型搭配多项式特征来近似非线性函数,并探讨如何通过交叉验证来评估模型的泛化能力。
线性回归是机器学习中最基本的模型之一,它假设输入特征与输出之间存在线性关系。然而,在现实世界中,很多问题的数据分布并非线性,这时候就需要引入多项式特征来增加模型的复杂度。多项式特征是通过将原始特征进行多项式变换(如平方、立方等)来生成新的特征,从而使得模型能够捕捉到更复杂的关系。
在本例中,尝试使用不同次数的多项式特征来拟合一个余弦函数的部分曲线。通过比较不同模型的拟合效果,可以直观地看到拟合不足和过拟合的现象。具体来说,当多项式次数较低时,模型过于简单,无法捕捉到数据中的复杂关系,导致拟合不足;而当多项式次数过高时,模型过于复杂,学习到了数据中的噪声,导致过拟合。
为了定量评估模型的泛化能力,使用交叉验证的方法来计算模型在验证集上的平均平方误差(MSE)。MSE是衡量模型预测误差的常用指标,其值越小,说明模型的预测效果越好。通过对比不同模型的MSE,可以判断模型是否存在拟合不足或过拟合的问题。
以下是使用Python的scikit-learn库来实现上述过程的代码示例。首先,定义了一个真实的函数,然后生成了一些随机样本,并添加了一些噪声。接着,使用不同次数的多项式特征来训练线性回归模型,并使用交叉验证来评估模型的性能。
import matplotlib.pyplot as plt
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import cross_val_score
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
def true_fun(X):
return np.cos(1.5 * np.pi * X)
np.random.seed(0)
n_samples = 30
degrees = [1, 4, 15]
X = np.sort(np.random.rand(n_samples))
y = true_fun(X) + np.random.randn(n_samples) * 0.1
plt.figure(figsize=(14, 5))
for i in range(len(degrees)):
ax = plt.subplot(1, len(degrees), i + 1)
plt.setp(ax, xticks=(), yticks=())
polynomial_features = PolynomialFeatures(degree=degrees[i], include_bias=False)
linear_regression = LinearRegression()
pipeline = Pipeline([
("polynomial_features", polynomial_features),
("linear_regression", linear_regression),
])
pipeline.fit(X[:, np.newaxis], y)
# Evaluate the models using crossvalidation
scores = cross_val_score(pipeline, X[:, np.newaxis], y, scoring="neg_mean_squared_error", cv=10)
X_test = np.linspace(0, 1, 100)
plt.plot(X_test, pipeline.predict(X_test[:, np.newaxis]), label="Model")
plt.plot(X_test, true_fun(X_test), label="True function")
plt.scatter(X, y, edgecolor="b", s=20, label="Samples")
plt.xlabel("x")
plt.ylabel("y")
plt.xlim((0, 1))
plt.ylim((-2, 2))
plt.legend(loc="best")
plt.title("Degree {}\nMSE = {:.2e} (+/- {:.2e})".format(degrees[i], -scores.mean(), scores.std()))
plt.show()
通过上述代码,可以生成不同多项式次数下的拟合曲线,并计算出对应的MSE值。这有助于直观地理解拟合不足和过拟合的概念,并学会如何使用交叉验证来评估模型的泛化能力。