set.seed(123) # seed for reproducibility
library(glmnet) # for ridge regression
## load data
data("mtcars")
X <- as.matrix(mtcars[,which(names(mtcars)!="mpg")])
y <- as.matrix(scale(mtcars[,"mpg"],center = T,scale = T)) # scale y
y <- mtcars[,"mpg"]
## select training and test samples
n <- nrow(X)
train_rows <- sample(1:n, .66*n) ## 66% training, 34% test
X.train <- X[train_rows, ]
X.test <- X[-train_rows, ]
y.train <- y[train_rows]
y.test <- y[-train_rows]
# See how increasing lambda shrinks the coefficients --------------------------
# Setting alpha = 1 implements lasso regression
lasso.model <- glmnet(X.train, y.train, alpha = 1, standardize = TRUE)
plot(lasso.model, xvar = "lambda")
legend("bottomright", lwd = 1, col = 1:ncol(X.train), legend = colnames(X), cex = 1)
# Perform 10-fold cross-validation to select lambda
lasso_cv <- cv.glmnet(X.train, y.train, alpha = 1, type.measure="mse",
standardize = TRUE, nfolds =10,family="gaussian")
# Plot cross-validation results
plot(lasso_cv)
# Select best cross-validated lambda
lambda_cv <- lasso_cv$lambda.min
# Fit final model, get its sum of squared residuals and multiple R-squared
## 注:也有人不做前面的交叉验证步骤,直接给 lambda一个值,比如lambda = 0.001
lasso.model <- glmnet(X.train, y.train, lambda = lambda_cv, alpha = 1, standardize = TRUE)
# Make prediction
y.test_hat <- predict(lasso.model, X.test)
Rsquare <- cor(y.test,y.test_hat)^2
MSE <- mean((y.test - y.test_hat)^2)
plot(y.test,y.test_hat,col="#00000050",pch = 19,main = "Test result for lasso")
abline(lm(y.test_hat~y.test),lty = 2,lwd = 2,col = "gray")
text(x = 12,y = 20,labels = paste0("MSE = ",round(MSE,4),"\n","R-sequared = ",round(Rsquare,4)))
# See how increasing lambda shrinks the coefficients --------------------------
# Setting alpha = 0 implements ridge regression
ridge.model <- glmnet(X.train, y.train, alpha = 0, standardize = TRUE)
plot(ridge.model, xvar = "lambda",main = "Ridge")
legend("bottomright", lwd = 1, col = 1:ncol(X.train), legend = colnames(X), cex = 1)
# Perform 10-fold cross-validation to select lambda
ridge_cv <- cv.glmnet(X.train, y.train, alpha = 0, type.measure="mse",
standardize = TRUE, nfolds =10,family="gaussian")
# Plot cross-validation results
plot(ridge_cv,main = "Ridge")
# Select best cross-validated lambda
lambda_cv <- ridge_cv$lambda.min
# Fit final model, get its sum of squared residuals and multiple R-squared
## 注:也有人不做前面的交叉验证步骤,直接给 lambda一个值,比如lambda = 0.001
ridge.model <- glmnet(X.train, y.train, lambda = lambda_cv, alpha = 0, standardize = TRUE)
# Make prediction
y.test_hat <- predict(ridge.model, X.test)
Rsquare <- cor(y.test,y.test_hat)^2
MSE <- mean((y.test - y.test_hat)^2)
plot(y.test,y.test_hat,col="#00000050",pch = 19,main = "Test result for ridge")
abline(lm(y.test_hat~y.test),lty = 2,lwd = 2,col = "gray")
text(x = 12,y = 20,labels = paste0("MSE = ",round(MSE,4),"\n","R-sequared = ",round(Rsquare,4)))
There are two parameters to tune: λ and α. The glmnet package allows to tune λ via cross-validation for a fixed α, but it does not support α-tuning, so we will turn to caret for this job.
dat <- cbind(y.train, X.train)
head(dat)
library(caret)
# Set training control
train_control <- trainControl(method = "repeatedcv",
number = 5,
repeats = 5,
search = "random",
verboseIter = F)
# Train the model
elastic_net_model <- train(y.train ~ .,
data = dat,
method = "glmnet",
preProcess = c("center", "scale"),
tuneLength = 25,
trControl = train_control)
# Check results
y.test_hat <- predict(elastic_net_model, X.test)
Rsquare <- cor(y.test, y.test_hat)^2
MSE <- mean((y.test - y.test_hat)^2)
plot(y.test,y.test_hat,col="#00000050",pch = 19,main = "Test result for ENet")
abline(lm(y.test_hat~y.test),lty = 2,lwd = 2,col = "gray")
text(x = 12,y = 20,labels = paste0("MSE = ",round(MSE,4),"\n","R-sequared = ",round(Rsquare,4)))