5Assignment

Assignment 5

Irving Cedillo

2

  • Lasso relative to the least squares model
    • Wrong: More flexible and hence will give improved prediction accuracy when its increase in bias is less than its decrease in variance. Since Lasso is more restrictive than OLS since it is based on two optimization problems it is much less flexible than OLS.
    • Wrong: More flexible and hence will give improved prediction accuracy when its increase in variance is less than its decrease in bias. Since Lasso is more restrictive than OLS since it is based on two optimization problems it is much less flexible than OLS.
    • Correct: Less flexible and hence will give improved prediction accuracy when its increase in bias is less than its decrease in variance.
    • Wrong: Less flexible and hence will give improved prediction accuracy when its increase in variance is less than its decrease in bias. Since Lasso is more restrictive than OLS since it is based on two optimization problems it is much more likely to have lower variance compared to OLS.
  • Ridge relative to the least squares model
    • Wrong: More flexible and hence will give improved prediction accuracy when its increase in bias is less than its decrease in variance. Since Ridge is more restrictive than OLS since it is based on two optimization problems it is much less flexible than OLS.
    • Wrong: More flexible and hence will give improved prediction accuracy when its increase in variance is less than its decrease in bias. Since Ridge is more restrictive than OLS since it is based on two optimization problems it is much less flexible than OLS.
    • Correct: Less flexible and hence will give improved prediction accuracy when its increase in bias is less than its decrease in variance
    • Wrong: Less flexible and hence will give improved prediction accuracy when its increase in variance is less than its decrease in bias. Since Ridge is more restrictive than OLS since it is based on two optimization problems it is much more likely to have lower variance compared to OLS.
  • Nonlinear models relative to the least squares model
    • Wrong: More flexible and hence will give improved prediction accuracy when its increase in bias is less than its decrease in variance. Since non-linear models are more flexible than OLS and are prone to over fit the data they are more likely to have higher variance.
    • Correct: More flexible and hence will give improved prediction accuracy when its increase in variance is less than its decrease in bias
    • Wrong: Less flexible and hence will give improved prediction accuracy when its increase in bias is less than its decrease in variance. Nonlinear models are more flexible.
    • Wrong: Less flexible and hence will give improved prediction accuracy when its increase in variance is less than its decrease in bias. Nonlinear models are more flexible.

9

Using the rsample package in the tinymodels we can achieve a stratified split, but in this situation since the response is numerical a random split works just as fine.

library(ISLR)
library(rsample)
library(caret)
Warning: package 'caret' was built under R version 4.5.2
Loading required package: ggplot2
Loading required package: lattice

Attaching package: 'caret'
The following object is masked from 'package:rsample':

    calibration
set.seed(420)

attach(College)

names(College)
 [1] "Private"     "Apps"        "Accept"      "Enroll"      "Top10perc"  
 [6] "Top25perc"   "F.Undergrad" "P.Undergrad" "Outstate"    "Room.Board" 
[11] "Books"       "Personal"    "PhD"         "Terminal"    "S.F.Ratio"  
[16] "perc.alumni" "Expend"      "Grad.Rate"  
data_split <- initial_split(College, prop=.75, strata=Apps)

train_data <- training(data_split)
test_data <- testing(data_split)

#cross validation set up 
cross_validation<- trainControl(method='cv', number=10)

#Least squares 
model_glm <- train(
  Apps ~., 
  data=train_data,
  method = "glm", 
  family = 'gaussian',
  trControl = cross_validation,
  preProcess = c("center","scale")
)


#Ridge Regression
ridge_params <- expand.grid(
  alpha = 0, #for lasso it is 1
  lambda = c(.5,1,3, 5,10,50,100,500,1000)
)

model_ridge <- train(
  Apps ~.,
  data=train_data,
  method= 'glmnet',
  tuneGrid = ridge_params,
  trControl = cross_validation,
  preProcess = c("center","scale")
)

#Lasso Regression
lasso_params <- expand.grid(
  alpha = 1, #for lasso it is 1
  lambda = c(.5,1,3, 5,10,50,100,500,1000)
)

model_lasso <- train(
  Apps ~.,
  data=train_data,
  method= 'glmnet',
  tuneGrid = lasso_params,
  trControl = cross_validation,
  preProcess = c("center","scale")
)

#PCR
pcr_params <- expand.grid(ncomp=1:15)

model_pcr<- train(
  Apps~., 
  data=train_data, 
  method="pcr",
  tuneGrid=pcr_params,
  trControl =cross_validation,
  #needed sine the predictors are compared for variance, cannot have year dsitance overashadow smaller metrics-Unsupervised so does not use the response variable
  preProcess = c("center","scale")
)

#PLS 
pls_params<- expand.grid(ncomp=1:15)

model_pls<-train(
  Apps~.,
  data=train_data, 
  method="pls",
  tuneGrid=pls_params,
  trControl=cross_validation,
  #same as pcr it uses distanc eso needs to be standardized-Supervised so also uses the response
  preProcess = c("center","scale")
)

With all of the models performing relatively similarly, I would chose the OLS model, since interpreting the coefficients is easier and more predictable.

#OLS 
cat('OLS\n')
OLS
ols_pred<- as.numeric(predict(model_glm, newdata = test_data))
ols_metrics<- postResample(pred=ols_pred, obs=test_data$Apps)

print(ols_metrics)
        RMSE     Rsquared          MAE 
1183.6636281    0.8785714  650.5702197 
#Lasso
cat('\n\n\nLasso\n')



Lasso
lasso_pred<- as.numeric(predict(model_lasso, newdata=test_data))

lasso_lambda<-model_lasso$bestTune$lambda
cat('Lambda:',lasso_lambda,'\n')
Lambda: 1 
lasso_coefs <- coef(model_lasso$finalModel, s = model_lasso$bestTune$lambda)

eliminated_vars<-rownames(lasso_coefs)[lasso_coefs[,1] == 0]
cat('Removed Vars:',eliminated_vars,'\n')
Removed Vars:  
lasso_metrics<- postResample(pred=lasso_pred, obs=test_data$Apps)
print(lasso_metrics)
        RMSE     Rsquared          MAE 
1176.6536537    0.8801018  645.0082262 
#Ridge
cat('\n\n\nRidge\n')



Ridge
ridge_pred<- as.numeric(predict(model_ridge, newdata=test_data))
ridge_lambnda<- model_ridge$bestTune$lambda
cat('Lambda:',ridge_lambnda,'\n')
Lambda: 100 
ridge_metrics<- postResample(pred=ridge_pred, obs=test_data$Apps)
print(ridge_metrics)
        RMSE     Rsquared          MAE 
1085.6225584    0.8950542  642.6121746 
#PCR
cat('\n\n\nPCR\n')



PCR
pcr_pred<- as.numeric(predict(model_pcr, newdata=test_data))
pcr_m<-model_pcr$bestTune$ncomp
cat('M:', pcr_m,'\n')
M: 10 
pcr_metrics<- postResample(pred=pcr_pred, obs=test_data$Apps)
print(pcr_metrics)
        RMSE     Rsquared          MAE 
1324.1170235    0.8507953  816.7150543 
#PLS
cat('\n\n\nPLS\n')



PLS
pls_pred<- as.numeric(predict(model_pls, newdata=test_data))
pls_m<-model_pls$bestTune$ncomp
cat('M:', pls_m,'\n')
M: 15 
pls_metrics<- postResample(pred=pls_pred, obs=test_data$Apps)
print(pls_metrics)
        RMSE     Rsquared          MAE 
1183.6663952    0.8785631  650.7104974 

11

library(MASS)
Warning: package 'MASS' was built under R version 4.5.2
library(psych)

Attaching package: 'psych'
The following objects are masked from 'package:ggplot2':

    %+%, alpha
attach(Boston)
set.seed(420)

clean_boston <- Boston|>
  dplyr::mutate(
    chas_factor = as.factor(chas)
    
  )|>
  dplyr::select(-chas,-rad)|>
  tidyr::drop_na()

str(clean_boston)
'data.frame':   506 obs. of  13 variables:
 $ crim       : num  0.00632 0.02731 0.02729 0.03237 0.06905 ...
 $ zn         : num  18 0 0 0 0 0 12.5 12.5 12.5 12.5 ...
 $ indus      : num  2.31 7.07 7.07 2.18 2.18 2.18 7.87 7.87 7.87 7.87 ...
 $ nox        : num  0.538 0.469 0.469 0.458 0.458 0.458 0.524 0.524 0.524 0.524 ...
 $ rm         : num  6.58 6.42 7.18 7 7.15 ...
 $ age        : num  65.2 78.9 61.1 45.8 54.2 58.7 66.6 96.1 100 85.9 ...
 $ dis        : num  4.09 4.97 4.97 6.06 6.06 ...
 $ tax        : num  296 242 242 222 222 222 311 311 311 311 ...
 $ ptratio    : num  15.3 17.8 17.8 18.7 18.7 18.7 15.2 15.2 15.2 15.2 ...
 $ black      : num  397 397 393 395 397 ...
 $ lstat      : num  4.98 9.14 4.03 2.94 5.33 ...
 $ medv       : num  24 21.6 34.7 33.4 36.2 28.7 22.9 27.1 16.5 18.9 ...
 $ chas_factor: Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...
summary(clean_boston)
      crim                zn             indus            nox        
 Min.   : 0.00632   Min.   :  0.00   Min.   : 0.46   Min.   :0.3850  
 1st Qu.: 0.08205   1st Qu.:  0.00   1st Qu.: 5.19   1st Qu.:0.4490  
 Median : 0.25651   Median :  0.00   Median : 9.69   Median :0.5380  
 Mean   : 3.61352   Mean   : 11.36   Mean   :11.14   Mean   :0.5547  
 3rd Qu.: 3.67708   3rd Qu.: 12.50   3rd Qu.:18.10   3rd Qu.:0.6240  
 Max.   :88.97620   Max.   :100.00   Max.   :27.74   Max.   :0.8710  
       rm             age              dis              tax       
 Min.   :3.561   Min.   :  2.90   Min.   : 1.130   Min.   :187.0  
 1st Qu.:5.886   1st Qu.: 45.02   1st Qu.: 2.100   1st Qu.:279.0  
 Median :6.208   Median : 77.50   Median : 3.207   Median :330.0  
 Mean   :6.285   Mean   : 68.57   Mean   : 3.795   Mean   :408.2  
 3rd Qu.:6.623   3rd Qu.: 94.08   3rd Qu.: 5.188   3rd Qu.:666.0  
 Max.   :8.780   Max.   :100.00   Max.   :12.127   Max.   :711.0  
    ptratio          black            lstat            medv       chas_factor
 Min.   :12.60   Min.   :  0.32   Min.   : 1.73   Min.   : 5.00   0:471      
 1st Qu.:17.40   1st Qu.:375.38   1st Qu.: 6.95   1st Qu.:17.02   1: 35      
 Median :19.05   Median :391.44   Median :11.36   Median :21.20              
 Mean   :18.46   Mean   :356.67   Mean   :12.65   Mean   :22.53              
 3rd Qu.:20.20   3rd Qu.:396.23   3rd Qu.:16.95   3rd Qu.:25.00              
 Max.   :22.00   Max.   :396.90   Max.   :37.97   Max.   :50.00              
describe(clean_boston)
             vars   n   mean     sd median trimmed    mad    min    max  range
crim            1 506   3.61   8.60   0.26    1.68   0.33   0.01  88.98  88.97
zn              2 506  11.36  23.32   0.00    5.08   0.00   0.00 100.00 100.00
indus           3 506  11.14   6.86   9.69   10.93   9.37   0.46  27.74  27.28
nox             4 506   0.55   0.12   0.54    0.55   0.13   0.38   0.87   0.49
rm              5 506   6.28   0.70   6.21    6.25   0.51   3.56   8.78   5.22
age             6 506  68.57  28.15  77.50   71.20  28.98   2.90 100.00  97.10
dis             7 506   3.80   2.11   3.21    3.54   1.91   1.13  12.13  11.00
tax             8 506 408.24 168.54 330.00  400.04 108.23 187.00 711.00 524.00
ptratio         9 506  18.46   2.16  19.05   18.66   1.70  12.60  22.00   9.40
black          10 506 356.67  91.29 391.44  383.17   8.09   0.32 396.90 396.58
lstat          11 506  12.65   7.14  11.36   11.90   7.11   1.73  37.97  36.24
medv           12 506  22.53   9.20  21.20   21.56   5.93   5.00  50.00  45.00
chas_factor*   13 506   1.07   0.25   1.00    1.00   0.00   1.00   2.00   1.00
              skew kurtosis   se
crim          5.19    36.60 0.38
zn            2.21     3.95 1.04
indus         0.29    -1.24 0.30
nox           0.72    -0.09 0.01
rm            0.40     1.84 0.03
age          -0.60    -0.98 1.25
dis           1.01     0.46 0.09
tax           0.67    -1.15 7.49
ptratio      -0.80    -0.30 0.10
black        -2.87     7.10 4.06
lstat         0.90     0.46 0.32
medv          1.10     1.45 0.41
chas_factor*  3.39     9.48 0.01
#spit the data into test and train set
data_split_boston <- initial_split(clean_boston, prop=.75, strata=crim)
train_data_boston <- training(data_split_boston)
test_data_boston <- testing(data_split_boston)

#cross validation set up 
cross_validation<- trainControl(method='cv', number=10)

best subset selection

Best subset selection highlighted an interesting quirk with the full model. The subset_pred value given was negative though crim cannot be negative. This quirk highlights the high skew faced by the crim column. From the ggpairs of the before and after of the crim column we can see that applying a logarithmic transformation better normalizes the response.

library(leaps)
library(plotly)
Warning: package 'plotly' was built under R version 4.5.2

Attaching package: 'plotly'
The following object is masked from 'package:MASS':

    select
The following object is masked from 'package:ggplot2':

    last_plot
The following object is masked from 'package:stats':

    filter
The following object is masked from 'package:graphics':

    layout
library(GGally)
predict_regsubsets <- function(object, newdata, id) {
  form <- as.formula(object$call[[2]]) 
  mat <- model.matrix(form, newdata)   
  coefi <- coef(object, id = id)     
  xvars <- names(coefi)               
  mat[, xvars] %*% coefi               
}


model_best_subset <- regsubsets(
  crim ~ ., 
  data = train_data_boston,
  method = "exhaustive", 
  nvmax = 10
)
cat('Best Subset Selection \n')
Best Subset Selection 
summary(model_best_subset)
Subset selection object
Call: regsubsets.formula(crim ~ ., data = train_data_boston, method = "exhaustive", 
    nvmax = 10)
12 Variables  (and intercept)
             Forced in Forced out
zn               FALSE      FALSE
indus            FALSE      FALSE
nox              FALSE      FALSE
rm               FALSE      FALSE
age              FALSE      FALSE
dis              FALSE      FALSE
tax              FALSE      FALSE
ptratio          FALSE      FALSE
black            FALSE      FALSE
lstat            FALSE      FALSE
medv             FALSE      FALSE
chas_factor1     FALSE      FALSE
1 subsets of each size up to 10
Selection Algorithm: exhaustive
          zn  indus nox rm  age dis tax ptratio black lstat medv chas_factor1
1  ( 1 )  " " " "   " " " " " " " " "*" " "     " "   " "   " "  " "         
2  ( 1 )  " " " "   " " " " " " " " "*" " "     " "   "*"   " "  " "         
3  ( 1 )  " " " "   " " " " " " " " "*" " "     "*"   "*"   " "  " "         
4  ( 1 )  " " "*"   " " " " " " " " "*" " "     "*"   "*"   " "  " "         
5  ( 1 )  " " "*"   " " " " " " "*" "*" " "     "*"   "*"   " "  " "         
6  ( 1 )  "*" "*"   " " " " " " "*" "*" " "     "*"   " "   "*"  " "         
7  ( 1 )  "*" "*"   " " " " " " "*" "*" " "     "*"   "*"   "*"  " "         
8  ( 1 )  "*" "*"   " " "*" " " "*" "*" " "     "*"   "*"   "*"  " "         
9  ( 1 )  "*" "*"   "*" "*" " " "*" "*" " "     "*"   "*"   "*"  " "         
10  ( 1 ) "*" "*"   "*" "*" "*" "*" "*" " "     "*"   "*"   "*"  " "         
cat('Best Subset\n')
Best Subset
best_num <- which.min(summary(model_best_subset)$bic)
subset_pred <- as.numeric(predict_regsubsets(model_best_subset, 
                                             newdata = test_data_boston, 
                                             id = best_num))
head(subset_pred)
[1] -2.493791  2.172709  1.159948  1.531825  2.337680  1.256242
coef(model_best_subset, id = best_num)
(Intercept)         tax       black       lstat 
-3.23438960  0.02380488 -0.01508065  0.22430524 
ggpairs(clean_boston|>select(crim,tax,black,lstat, dis, indus), progress=FALSE)

ggpairs(clean_boston|>
          mutate(crim=log(crim))|>
          select(crim,tax,black,lstat, dis, indus), progress=FALSE)

Re-runing the model with the transformed crim column results in much more stable outputs and estimations for the response column. The best susbset model selected the top 6 variable model as the top performer.

model_best_subset2 <- regsubsets(
  log(crim) ~ ., 
  data = train_data_boston,
  method = "exhaustive", 
  nvmax = 10
)
cat('Best Subset Selection \n')
Best Subset Selection 
summary(model_best_subset2)
Subset selection object
Call: regsubsets.formula(log(crim) ~ ., data = train_data_boston, method = "exhaustive", 
    nvmax = 10)
12 Variables  (and intercept)
             Forced in Forced out
zn               FALSE      FALSE
indus            FALSE      FALSE
nox              FALSE      FALSE
rm               FALSE      FALSE
age              FALSE      FALSE
dis              FALSE      FALSE
tax              FALSE      FALSE
ptratio          FALSE      FALSE
black            FALSE      FALSE
lstat            FALSE      FALSE
medv             FALSE      FALSE
chas_factor1     FALSE      FALSE
1 subsets of each size up to 10
Selection Algorithm: exhaustive
          zn  indus nox rm  age dis tax ptratio black lstat medv chas_factor1
1  ( 1 )  " " " "   " " " " " " " " "*" " "     " "   " "   " "  " "         
2  ( 1 )  " " " "   "*" " " " " " " "*" " "     " "   " "   " "  " "         
3  ( 1 )  "*" " "   "*" " " " " " " "*" " "     " "   " "   " "  " "         
4  ( 1 )  "*" " "   "*" " " " " " " "*" " "     "*"   " "   " "  " "         
5  ( 1 )  "*" " "   "*" " " " " " " "*" " "     " "   "*"   "*"  " "         
6  ( 1 )  "*" " "   "*" " " " " " " "*" " "     "*"   "*"   "*"  " "         
7  ( 1 )  "*" "*"   "*" " " " " " " "*" " "     "*"   "*"   "*"  " "         
8  ( 1 )  "*" "*"   "*" " " " " " " "*" " "     "*"   "*"   "*"  "*"         
9  ( 1 )  "*" "*"   "*" " " " " " " "*" "*"     "*"   "*"   "*"  "*"         
10  ( 1 ) "*" "*"   "*" " " "*" " " "*" "*"     "*"   "*"   "*"  "*"         
cat('Best Subset\n')
Best Subset
best_num <- which.min(summary(model_best_subset2)$bic)
subset_pred_log <- as.numeric(predict_regsubsets(model_best_subset2, 
                                             newdata = test_data_boston, 
                                             id = best_num))
subset_pred = exp(subset_pred_log)
head(subset_pred)
[1] 0.1024247 0.2144035 0.1702796 0.2321319 0.2732120 0.2340430
coef(model_best_subset2, id = best_num)
 (Intercept)           zn          nox          tax        black        lstat 
-6.682176497 -0.016618116  5.230445589  0.006496082 -0.002419189  0.053724940 
        medv 
 0.032052945 

ridge/lasso/pcr

The following models were run using the same logarithmic operation performed to be able to normalize the response variable and handle the skew.

#Ridge Regression
ridge_params <- expand.grid(
  alpha = 0, #for lasso it is 1
  lambda = c(.001,.01,.1,.5,1)
)

model_ridge_boston <- train(
  log(crim) ~.,
  data=train_data_boston,
  method= 'glmnet',
  tuneGrid = ridge_params,
  trControl = cross_validation,
  preProcess = c("center","scale")
)


#Lasso Regression
lasso_params <- expand.grid(
  alpha = 1, #for lasso it is 1
  lambda = c(.001,.01,.1,.5,1)
)

model_lasso_boston <- train(
  log(crim) ~.,
  data=train_data_boston,
  method= 'glmnet',
  tuneGrid = lasso_params,
  trControl = cross_validation,
  preProcess = c("center","scale")
)


pcr_params <- expand.grid(ncomp=1:10)

model_pcr_boston<- train(
  log(crim) ~.,
  data=train_data_boston,
  method="pcr",
  tuneGrid=pcr_params,
  trControl =cross_validation,
  preProcess = c("center","scale")
)

summary

All models performed relatively well and the extra precaution was made to transform the models back using the inverse operation of \(exp\) due to the \(log\) transformation applied to crim. Keeping with the law parsimony the model selected would be Best Subset Selection since it uses only 6 variables, and performed similarly to the Ridge,PCR and Lasso, who kept all variables.

#OLS 
cat('Best Subset\n')
Best Subset
best_num <- which.min(summary(model_best_subset2)$bic)
subset_pred_log <- as.numeric(predict_regsubsets(model_best_subset2, 
                                             newdata = test_data_boston, 
                                             id = best_num))
cat('Best # predictors:', best_num, '\n')
Best # predictors: 6 
subset_pred = exp(subset_pred_log)
subset_metrics <- postResample(pred=subset_pred, obs=test_data_boston$crim)
print(subset_metrics)
     RMSE  Rsquared       MAE 
2.5619700 0.6712687 1.1687967 
cat('\n')
coef(model_best_subset2, id = best_num)
 (Intercept)           zn          nox          tax        black        lstat 
-6.682176497 -0.016618116  5.230445589  0.006496082 -0.002419189  0.053724940 
        medv 
 0.032052945 
#Lasso
cat('\n\n\nLasso\n')



Lasso
lasso_pred_log<- as.numeric(predict(model_lasso_boston, newdata=test_data_boston))
lasso_pred<-exp(lasso_pred_log)

lasso_lambda<-model_lasso_boston$bestTune$lambda
cat('Lambda:',lasso_lambda,'\n')
Lambda: 0.001 
lasso_coefs <- coef(model_lasso_boston$finalModel, 
                    s= model_lasso_boston$bestTune$lambda)

eliminated_vars<-rownames(lasso_coefs)[lasso_coefs[,1] == 0]
cat('Removed Vars:',eliminated_vars,'\n')
Removed Vars:  
lasso_metrics<- postResample(pred=lasso_pred, obs=test_data_boston$crim)
print(lasso_metrics)
     RMSE  Rsquared       MAE 
2.7286241 0.6619475 1.2274664 
#Ridge
cat('\n\n\nRidge\n')



Ridge
ridge_pred_log<- as.numeric(predict(model_ridge_boston, newdata=test_data_boston))
ridge_pred<- exp(ridge_pred_log)
ridge_lambnda<- model_ridge_boston$bestTune$lambda
cat('Lambda:',ridge_lambnda,'\n')
Lambda: 0.1 
ridge_metrics<- postResample(pred=ridge_pred, obs=test_data_boston$crim)
print(ridge_metrics)
     RMSE  Rsquared       MAE 
2.5481457 0.6551781 1.2049297 
#PCR
cat('\n\n\nPCR\n')



PCR
pcr_pred_log<- as.numeric(predict(model_pcr_boston, newdata=test_data_boston))
pcr_pred<- exp(pcr_pred_log)

pcr_m<-model_pcr_boston$bestTune$ncomp
cat('M:', pcr_m,'\n')
M: 10 
pcr_metrics<- postResample(pred=pcr_pred, obs=test_data_boston$crim)
print(pcr_metrics)
     RMSE  Rsquared       MAE 
2.6976859 0.6701477 1.2161034