审稿人:你以为100%准确率是好事吗?恰恰相反,都overfitting了!

文摘   2025-01-02 09:11   荷兰  

过拟合是数据分析和模型学习中的一种常见现象,指模型在训练数据上表现出色,但在新数据(如验证集或测试集)上表现较差。过拟合的模型往往错误地解释了训练数据中的噪声和随机波动,但这些特性并不具有普遍性。尽管导致过拟合的原因很多,但是最直观的原因其实数数据集太少,但很多时候也很难重新返回做实验,学生还要面临试验进度的压力,那么这个时候有哪些方法可以挽救那些过拟合的模型呢?

今天的更新我们将最精准的介绍使用R语言如何检测和挽救过拟合的模型

如何在 R 语言中检测过拟合?

检测过拟合的关键是比较模型在训练数据和验证/测试数据上的表现。以下是具体步骤:

1. 分离训练集和测试集

# 分割数据集
set.seed(123)
data <- mtcars
index <- sample(1:nrow(data), 0.8 * nrow(data))
train_data <- data[index, ]
test_data <- data[-index, ]

2. 训练回归模型

# 构建回归模型
model <- lm(mpg ~ ., data = train_data)
summary(model)

##
## Call:
## lm(formula = mpg ~ ., data = train_data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -3.8774 -1.3957 -0.0511 0.8254 4.5637
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 21.48672 21.70872 0.990 0.3391
## cyl -1.02280 1.35957 -0.752 0.4643
## disp 0.02220 0.02531 0.877 0.3952
## hp -0.01921 0.02852 -0.674 0.5114
## drat 0.22504 1.89085 0.119 0.9070
## wt -4.60044 2.37145 -1.940 0.0728 .
## qsec 0.83809 0.80049 1.047 0.3129
## vs 0.76966 2.46407 0.312 0.7594
## am 2.38345 2.51892 0.946 0.3601
## gear -0.14113 1.77632 -0.079 0.9378
## carb 0.29213 1.01352 0.288 0.7774
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 2.85 on 14 degrees of freedom
## Multiple R-squared: 0.8854, Adjusted R-squared: 0.8035
## F-statistic: 10.82 on 10 and 14 DF, p-value: 5.62e-05

3. 计算训练和测试误差

# 训练集上的预测误差
train_predictions <- predict(model, newdata = train_data)
train_error <- mean((train_predictions - train_data$mpg)^2)

# 测试集上的预测误差
test_predictions <- predict(model, newdata = test_data)
test_error <- mean((test_predictions - test_data$mpg)^2)

# 比较误差
cat("训练误差:", train_error, "\n")

## 训练误差: 4.547055

cat("测试误差:", test_error, "\n")

## 测试误差: 6.70686

4. 可视化残差图

通过残差图直观了解模型的拟合情况:

# 残差图
plot(train_predictions, train_data$mpg - train_predictions,
main = "残差图", xlab = "预测值", ylab = "残差")
abline(h = 0, col = "red")


2. 如何挽救过拟合?

以下是三种常用方法来解决回归模型的过拟合问题:

2.1:简化模型

通过移除无关或贡献较小的变量,减少模型的复杂度:

# 使用逐步回归简化模型
library(MASS)
simplified_model <- stepAIC(model, direction = "both")

summary(simplified_model)

##
## Call:
## lm(formula = mpg ~ cyl + wt + qsec, data = train_data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -3.7011 -0.9383 -0.4928 0.4565 5.2032
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 29.0418 8.7748 3.310 0.003334 **
## cyl -1.1363 0.6673 -1.703 0.103340
## wt -3.8857 1.0166 -3.822 0.000993 ***
## qsec 0.5921 0.4151 1.426 0.168428
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 2.492 on 21 degrees of freedom
## Multiple R-squared: 0.8686, Adjusted R-squared: 0.8498
## F-statistic: 46.26 on 3 and 21 DF, p-value: 1.979e-09

2.2:正则化

使用正则化技术(例如岭回归或套索回归)来约束模型的复杂度:

# 岭回归示例
library(glmnet)

x <- model.matrix(mpg ~ ., train_data)[, -1]
y <- train_data$mpg
ridge_model <- cv.glmnet(x, y, alpha = 0) # alpha = 0 表示岭回归

plot(ridge_model)

best_lambda <- ridge_model$lambda.min
cat("最佳 lambda 值:", best_lambda, "\n")

## 最佳 lambda 值: 3.902739

# 在测试集上的预测
x_test <- model.matrix(mpg ~ ., test_data)[, -1]
ridge_predictions <- predict(ridge_model, s = best_lambda, newx = x_test)
ridge_error <- mean((ridge_predictions - test_data$mpg)^2)
cat("岭回归测试误差:", ridge_error, "\n")

## 岭回归测试误差: 4.657362

2.3:交叉验证

通过交叉验证选择最佳模型和超参数:

library(caret)

train_control <- trainControl(method = "cv", number = 5)
cv_model <- train(mpg ~ ., data = train_data, method = "lm", trControl = train_control)
print(cv_model)

## Linear Regression
##
## 25 samples
## 10 predictors
##
## No pre-processing
## Resampling: Cross-Validated (5 fold)
## Summary of sample sizes: 20, 20, 18, 21, 21
## Resampling results:
##
## RMSE Rsquared MAE
## 3.489824 0.7471681 2.830507
##
## Tuning parameter 'intercept' was held constant at a value of TRUE


小结

过拟合是模型过于复杂,导致训练数据表现优异但测试数据表现不佳。首推使用正则化技术(如岭回归或套索回归)而不是简单的线性模型。或者采用交叉验证确保模型泛化能力。相信通过这些方法,你的数据集还可以抢救。

感谢关注,你的支持是我不懈的动力!

科研代码
专注R和Python的数据分析。
 最新文章