library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.2.1 ✔ readr 2.1.6
## ✔ forcats 1.0.1 ✔ stringr 1.6.0
## ✔ ggplot2 4.0.2 ✔ tibble 3.3.1
## ✔ lubridate 1.9.5 ✔ tidyr 1.3.2
## ✔ purrr 1.2.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
ZEEL <- read.csv("ZEEL.csv")
model <- lm(
Close ~ `Prev.Close` + Open + High + Low + Volume,
data = ZEEL
)
summary(model)
##
## Call:
## lm(formula = Close ~ Prev.Close + Open + High + Low + Volume,
## data = ZEEL)
##
## Residuals:
## Min 1Q Median 3Q Max
## -92.735 -1.512 -0.285 1.253 67.805
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.500e-01 1.329e-01 3.387 0.000712 ***
## Prev.Close -6.050e-02 1.145e-02 -5.285 1.31e-07 ***
## Open -4.981e-01 1.390e-02 -35.830 < 2e-16 ***
## High 7.368e-01 9.363e-03 78.689 < 2e-16 ***
## Low 8.209e-01 7.854e-03 104.523 < 2e-16 ***
## Volume 2.585e-08 8.287e-09 3.119 0.001823 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 4.843 on 5300 degrees of freedom
## Multiple R-squared: 0.9992, Adjusted R-squared: 0.9992
## F-statistic: 1.401e+06 on 5 and 5300 DF, p-value: < 2.2e-16
Variable selection identifies the most relevant predictors in a model, improving accuracy and interpretability while reducing overfitting.
Rank variables by statistical scores before modeling.
# Correlation matrix on mtcars
round(cor(mtcars), 2)
## mpg cyl disp hp drat wt qsec vs am gear carb
## mpg 1.00 -0.85 -0.85 -0.78 0.68 -0.87 0.42 0.66 0.60 0.48 -0.55
## cyl -0.85 1.00 0.90 0.83 -0.70 0.78 -0.59 -0.81 -0.52 -0.49 0.53
## disp -0.85 0.90 1.00 0.79 -0.71 0.89 -0.43 -0.71 -0.59 -0.56 0.39
## hp -0.78 0.83 0.79 1.00 -0.45 0.66 -0.71 -0.72 -0.24 -0.13 0.75
## drat 0.68 -0.70 -0.71 -0.45 1.00 -0.71 0.09 0.44 0.71 0.70 -0.09
## wt -0.87 0.78 0.89 0.66 -0.71 1.00 -0.17 -0.55 -0.69 -0.58 0.43
## qsec 0.42 -0.59 -0.43 -0.71 0.09 -0.17 1.00 0.74 -0.23 -0.21 -0.66
## vs 0.66 -0.81 -0.71 -0.72 0.44 -0.55 0.74 1.00 0.17 0.21 -0.57
## am 0.60 -0.52 -0.59 -0.24 0.71 -0.69 -0.23 0.17 1.00 0.79 0.06
## gear 0.48 -0.49 -0.56 -0.13 0.70 -0.58 -0.21 0.21 0.79 1.00 0.27
## carb -0.55 0.53 0.39 0.75 -0.09 0.43 -0.66 -0.57 0.06 0.27 1.00
library(corrplot)
corrplot(cor(mtcars), method = "color", tl.cex = 0.8)
# Variance of each predictor (drop near-zero variance)
sapply(mtcars, var)
## mpg cyl disp hp drat wt
## 3.632410e+01 3.189516e+00 1.536080e+04 4.700867e+03 2.858814e-01 9.573790e-01
## qsec vs am gear carb
## 3.193166e+00 2.540323e-01 2.489919e-01 5.443548e-01 2.608871e+00
Use model performance to evaluate subsets.
library(MASS)
full <- lm(mpg ~ ., data = mtcars)
empty <- lm(mpg ~ 1, data = mtcars)
# Forward selection
fwd <- stepAIC(empty, scope = list(upper = full), direction = "forward", trace = FALSE)
summary(fwd)
##
## Call:
## lm(formula = mpg ~ wt + cyl + hp, data = mtcars)
##
## Residuals:
## Min 1Q Median 3Q Max
## -3.9290 -1.5598 -0.5311 1.1850 5.8986
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 38.75179 1.78686 21.687 < 2e-16 ***
## wt -3.16697 0.74058 -4.276 0.000199 ***
## cyl -0.94162 0.55092 -1.709 0.098480 .
## hp -0.01804 0.01188 -1.519 0.140015
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 2.512 on 28 degrees of freedom
## Multiple R-squared: 0.8431, Adjusted R-squared: 0.8263
## F-statistic: 50.17 on 3 and 28 DF, p-value: 2.184e-11
# Backward elimination
bwd <- stepAIC(full, direction = "backward", trace = FALSE)
summary(bwd)
##
## Call:
## lm(formula = mpg ~ wt + qsec + am, data = mtcars)
##
## Residuals:
## Min 1Q Median 3Q Max
## -3.4811 -1.5555 -0.7257 1.4110 4.6610
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 9.6178 6.9596 1.382 0.177915
## wt -3.9165 0.7112 -5.507 6.95e-06 ***
## qsec 1.2259 0.2887 4.247 0.000216 ***
## am 2.9358 1.4109 2.081 0.046716 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 2.459 on 28 degrees of freedom
## Multiple R-squared: 0.8497, Adjusted R-squared: 0.8336
## F-statistic: 52.75 on 3 and 28 DF, p-value: 1.21e-11
Selection happens during model training.
library(glmnet)
x <- model.matrix(mpg ~ ., data = mtcars)[, -1]
y <- mtcars$mpg
# --- LASSO (alpha = 1) ---
lasso_cv <- cv.glmnet(x, y, alpha = 1)
plot(lasso_cv) # CV error vs log(lambda)
coef(lasso_cv, s = "lambda.min") # non-zero = selected variables
## 11 x 1 sparse Matrix of class "dgCMatrix"
## lambda.min
## (Intercept) 36.31068553
## cyl -0.87115711
## disp .
## hp -0.01394790
## drat .
## wt -2.72254841
## qsec .
## vs .
## am 0.33946305
## gear .
## carb -0.05780686
# --- Ridge (alpha = 0) ---
ridge_cv <- cv.glmnet(x, y, alpha = 0)
coef(ridge_cv, s = "lambda.min")
## 11 x 1 sparse Matrix of class "dgCMatrix"
## lambda.min
## (Intercept) 21.051283516
## cyl -0.374112703
## disp -0.005318127
## hp -0.011506803
## drat 1.055629523
## wt -1.204585685
## qsec 0.160391657
## vs 0.787069385
## am 1.591536197
## gear 0.541785546
## carb -0.534626533
# --- Elastic Net (alpha = 0.5) ---
enet_cv <- cv.glmnet(x, y, alpha = 0.5)
coef(enet_cv, s = "lambda.min")
## 11 x 1 sparse Matrix of class "dgCMatrix"
## lambda.min
## (Intercept) 31.507946409
## cyl -0.656456607
## disp -0.001865773
## hp -0.013916343
## drat 0.563405569
## wt -2.058202045
## qsec .
## vs 0.231158096
## am 1.053549722
## gear .
## carb -0.290622942
Tree-based methods rank variables by their contribution to reducing impurity.
library(randomForest)
set.seed(42)
rf_model <- randomForest(mpg ~ ., data = mtcars, importance = TRUE)
varImpPlot(rf_model, main = "Variable Importance (Random Forest)")
# Numeric importance scores
importance(rf_model)
## %IncMSE IncNodePurity
## cyl 12.620655 178.16498
## disp 13.790918 253.10985
## hp 11.548795 169.12588
## drat 4.385795 65.69089
## wt 12.737424 259.44080
## qsec 2.985945 33.48435
## vs 4.408521 34.18138
## am 2.127998 15.04090
## gear 3.340548 20.09017
## carb 7.184614 32.49537
Boruta compares each variable against random “shadow” features to decide importance.
library(Boruta)
set.seed(42)
boruta_out <- Boruta(mpg ~ ., data = mtcars, doTrace = 0)
print(boruta_out)
## Boruta performed 24 iterations in 0.23522 secs.
## 10 attributes confirmed important: am, carb, cyl, disp, drat and 5
## more;
## No attributes deemed unimportant.
plot(boruta_out, las = 2, cex.axis = 0.7, main = "Boruta Feature Selection")
# Final confirmed variables
getSelectedAttributes(boruta_out, withTentative = FALSE)
## [1] "cyl" "disp" "hp" "drat" "wt" "qsec" "vs" "am" "gear" "carb"