过拟合指的是模型在训练集上表现良好,但在测试集或实际应用中表现不佳的现象。通常,过拟合是由于模型过度学习了训练集中的噪声和细节,而忽略了数据的真正趋势。这导致模型在新数据上的泛化能力较差。
假设我们有一个简单的线性回归问题,数据集包含了年龄和身高的关系。下面是一个示例代码:
import numpy as np
import matplotlib.pyplot as plt
# 生成数据集
np.random.seed(0)
X = np.random.rand(100, 1) * 10
y = 2.5 * X + np.random.randn(100, 1) * 2
# 添加噪声点
X_outliers = np.array([[15]])
y_outliers = np.array([[160]])
X = np.append(X, X_outliers, axis=0)
y = np.append(y, y_outliers, axis=0)
# 可视化数据集
plt.scatter(X, y)
plt.xlabel('Age')
plt.ylabel('Height')
plt.title('Data Distribution')
plt.show()
在上述代码中,我们生成了一个包含年龄和身高关系的数据集,并添加了一些噪声点。接下来,我们将使用线性回归模型拟合这个数据集:
from sklearn.linear_model import LinearRegression
# 训练线性回归模型
model = LinearRegression()
model.fit(X, y)
# 可视化拟合结果
plt.scatter(X, y)
plt.plot(X, model.predict(X), color='red')
plt.xlabel('Age')
plt.ylabel('Height')
plt.title('Linear Regression Fit')
plt.show()
这段代码中的过拟合原因可以通过以下几个方面来解释:
解决过拟合问题的方法通常包括:
增加训练数据量通常可以帮助模型更好地学习数据的真实关系。在这个例子中,生成更多的数据来演示这一点。
import numpy as np
import matplotlib.pyplot as plt
# 生成更多的数据
np.random.seed(0)
X_additional = np.random.rand(100, 1) * 10
y_additional = 2.5 * X_additional + np.random.randn(100, 1) * 2
# 合并原始数据和新数据
X_combined = np.concatenate((X, X_additional), axis=0)
y_combined = np.concatenate((y, y_additional), axis=0)
# 可视化数据集
plt.scatter(X_combined, y_combined)
plt.xlabel('Age')
plt.ylabel('Height')
plt.title('Data Distribution with Additional Data')
plt.show()
简化模型结构是减少过拟合的一种方法。在这里,可以降低多项式的次数来简化模型。
from sklearn.preprocessing import PolynomialFeatures
# 使用更低次数的多项式拟合数据
polynomial_features = PolynomialFeatures(degree=1)
X_poly = polynomial_features.fit_transform(X_combined)
# 训练线性回归模型
model = LinearRegression()
model.fit(X_poly, y_combined)
# 绘制拟合结果
plt.scatter(X_combined, y_combined)
plt.plot(X_combined, model.predict(X_poly), color='red')
plt.xlabel('Age')
plt.ylabel('Height')
plt.title('Linear Regression Fit with Simplified Model')
plt.show()
通过引入正则化项,可以惩罚模型的复杂度,防止过拟合。这里使用L2正则化。
from sklearn.linear_model import Ridge
# 使用Ridge回归进行正则化
ridge_model = Ridge(alpha=0.1) # 设置正则化参数alpha
ridge_model.fit(X_poly, y_combined)
# 绘制拟合结果
plt.scatter(X_combined, y_combined)
plt.plot(X_combined, ridge_model.predict(X_poly), color='green')
plt.xlabel('Age')
plt.ylabel('Height')
plt.title('Ridge Regression Fit with Regularization')
plt.show()
使用交叉验证可以评估模型在不同数据集上的性能,从而更好地评估其泛化能力。
from sklearn.model_selection import cross_val_score
# 使用交叉验证评估模型性能
scores = cross_val_score(model, X_poly, y_combined, cv=5)
print("Linear Regression Cross-Validation Scores:", scores)
ridge_scores = cross_val_score(ridge_model, X_poly, y_combined, cv=5)
print("Ridge Regression Cross-Validation Scores:", ridge_scores)
欠拟合指的是模型无法在训练集上学习数据的趋势,表现为模型过于简单,无法捕获数据的复杂性。这导致模型在训练集和测试集上都表现不佳。
继续使用上述年龄和身高的数据集,考虑一个过于简单的模型,比如使用线性模型拟合非线性关系的数据:
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline
# 创建线性模型
model = make_pipeline(PolynomialFeatures(1), LinearRegression())
# 训练模型
model.fit(X, y)
# 可视化拟合结果
plt.scatter(X, y)
plt.plot(X, model.predict(X), color='red')
plt.xlabel('Age')
plt.ylabel('Height')
plt.title('Underfitting: Linear Model')
plt.show()
在这个案例中,我们尝试使用一个过于简单的线性模型来拟合非线性关系的数据,这导致了欠拟合的问题。让我们详细讲解一下欠拟合的原因:
可以增加多项式的次数,使用更高阶的多项式特征来拟合数据的非线性关系。这样可以增加模型的灵活性,更好地适应数据。
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
import numpy as np
import matplotlib.pyplot as plt
# 创建多项式特征转换器
poly_features = PolynomialFeatures(degree=5) # 选择更高阶的多项式
# 将原始特征转换为多项式特征
X_poly = poly_features.fit_transform(X)
# 创建线性回归模型
model = LinearRegression()
# 训练模型
model.fit(X_poly, y)
# 绘制拟合结果
plt.scatter(X, y)
plt.plot(X, model.predict(X_poly), color='red', label='Polynomial Regression (Degree 5)')
plt.xlabel('Age')
plt.ylabel('Height')
plt.title('Polynomial Regression Fit (Degree 5)')
plt.legend()
plt.show()
可以添加更多的特征,例如原始特征的多项式特征、交叉特征等,以提供更多的信息来拟合数据。
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
import numpy as np
import matplotlib.pyplot as plt
# 创建多项式特征转换器
poly_features = PolynomialFeatures(degree=2) # 选择更高阶的多项式
# 将原始特征转换为多项式特征
X_poly = poly_features.fit_transform(X)
# 创建线性回归模型
model = LinearRegression()
# 训练模型
model.fit(X_poly, y)
# 绘制拟合结果
plt.scatter(X, y)
plt.plot(X, model.predict(X_poly), color='red', label='Polynomial Regression (Degree 2)')
plt.xlabel('Age')
plt.ylabel('Height')
plt.title('Polynomial Regression Fit (Degree 2)')
plt.legend()
plt.show()
可以尝试使用其他算法来处理非线性数据,例如决策树、支持向量机等。
from sklearn.tree import DecisionTreeRegressor
# 创建决策树回归模型
model = DecisionTreeRegressor(max_depth=5) # 设置树的最大深度
# 训练模型
model.fit(X, y)
# 绘制拟合结果
plt.scatter(X, y)
plt.plot(X, model.predict(X), color='red', label='Decision Tree Regression')
plt.xlabel('Age')
plt.ylabel('Height')
plt.title('Decision Tree Regression Fit')
plt.legend()
plt.show()
如果使用了带有正则化的模型,可以尝试调整正则化参数来提高模型的灵活性。
from sklearn.linear_model import Ridge
# 创建岭回归模型
model = Ridge(alpha=0.1) # 设置正则化参数alpha
# 训练模型
model.fit(X_poly, y)
# 绘制拟合结果
plt.scatter(X, y)
plt.plot(X, model.predict(X_poly), color='red', label='Ridge Regression (alpha=0.1)')
plt.xlabel('Age')
plt.ylabel('Height')
plt.title('Ridge Regression Fit (alpha=0.1)')
plt.legend()
plt.show()