6Assignment

Irving Cedillo

6

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(Wage)

str(Wage)
'data.frame':   3000 obs. of  11 variables:
 $ year      : int  2006 2004 2003 2003 2005 2008 2009 2008 2006 2004 ...
 $ age       : int  18 24 45 43 50 54 44 30 41 52 ...
 $ maritl    : Factor w/ 5 levels "1. Never Married",..: 1 1 2 2 4 2 2 1 1 2 ...
 $ race      : Factor w/ 4 levels "1. White","2. Black",..: 1 1 1 3 1 1 4 3 2 1 ...
 $ education : Factor w/ 5 levels "1. < HS Grad",..: 1 4 3 4 2 4 3 3 3 2 ...
 $ region    : Factor w/ 9 levels "1. New England",..: 2 2 2 2 2 2 2 2 2 2 ...
 $ jobclass  : Factor w/ 2 levels "1. Industrial",..: 1 2 1 2 2 2 1 2 2 2 ...
 $ health    : Factor w/ 2 levels "1. <=Good","2. >=Very Good": 1 2 1 2 1 2 2 1 2 2 ...
 $ health_ins: Factor w/ 2 levels "1. Yes","2. No": 2 2 1 1 1 1 1 1 1 1 ...
 $ logwage   : num  4.32 4.26 4.88 5.04 4.32 ...
 $ wage      : num  75 70.5 131 154.7 75 ...
#create the cross validation setup
cross_val <- trainControl(method = 'cv', number = 10) 

#create the different models 1-15 degree to fid optmum degree
upper_lim_deg = 15

#theese objects will store ersults and the models for the anova copmarison
results_list <- vector("list", upper_lim_deg)
models_list <- vector("list", upper_lim_deg)

#Train the models
for(degree in 1:upper_lim_deg) {
  
  #create the template of the formula
  functions <- as.formula(paste0('wage~poly(age, degree=',degree,')')) 
  #fit the models 
  poly_model<-train(
    functions, 
    data=Wage,
    method = 'lm',
    trControl=cross_val
  )
  #collect all of the pieces together in the resulting dataframe
  results_list[[degree]]<- data.frame(
    Degree= degree,RMSE=poly_model$results$RMSE,R_SQR= poly_model$results$Rsquared,MAE= poly_model$results$MAE
  )
  #store al o fthe models into a dataframe of the results 
  models_list[[degree]]<- poly_model$finalModel
  
}

#responses for the metrics on the models given 
response_totals_df<-do.call(rbind, results_list)
print(response_totals_df)
   Degree     RMSE      R_SQR      MAE
1       1 40.89687 0.04098117 28.78207
2       2 39.93911 0.08249302 27.77592
3       3 39.87239 0.08549550 27.75689
4       4 39.84181 0.08674806 27.73360
5       5 39.86617 0.08632349 27.75571
6       6 39.84952 0.08689059 27.72036
7       7 39.86933 0.08616004 27.73733
8       8 39.81286 0.08700620 27.72870
9       9 39.82934 0.08786727 27.75928
10     10 39.84447 0.08647599 27.74755
11     11 39.90574 0.08422547 27.76745
12     12 39.93794 0.08336923 27.78184
13     13 39.82121 0.08595006 27.76952
14     14 39.99035 0.08179412 27.78410
15     15 39.85778 0.08566687 27.79920
#compare agains teh anova o the models
for(degree in 1:(upper_lim_deg-1)){
  anova_comp <- anova(models_list[[degree]], models_list[[degree+1]])
  pval=anova_comp$"Pr(>F)"[2]
  cat('Anova compare degree:',degree,' and ', degree+1,' has p val:', pval,'\n')
}
Anova compare degree: 1  and  2  has p val: 3.07742e-32 
Anova compare degree: 2  and  3  has p val: 0.001687063 
Anova compare degree: 3  and  4  has p val: 0.05103865 
Anova compare degree: 4  and  5  has p val: 0.369682 
Anova compare degree: 5  and  6  has p val: 0.1162015 
Anova compare degree: 6  and  7  has p val: 0.205311 
Anova compare degree: 7  and  8  has p val: 0.7779522 
Anova compare degree: 8  and  9  has p val: 0.03596326 
Anova compare degree: 9  and  10  has p val: 0.9675292 
Anova compare degree: 10  and  11  has p val: 0.7990375 
Anova compare degree: 11  and  12  has p val: 0.9479033 
Anova compare degree: 12  and  13  has p val: 0.7301651 
Anova compare degree: 13  and  14  has p val: 0.6964635 
Anova compare degree: 14  and  15  has p val: 0.4801506 

It is a unique results where the anova results in a degree of 3 with the pvalue = .051 when running an anova comparison to degree = 4. However with cross validation using 10 fold - we get that degree 8 has the lowest RMSE. The anova sheds insight that the comparison of degree 8 and 9 is significant, however this can be due to random noise, which can influence the cv results. By the rule of parsimony we will go with the simplest model, therefore degree 3.

ggplot(data= Wage, aes(x= age, y= wage)) +
  geom_point(color= "black", alpha= 0.3, size = 1.2) +
  stat_smooth(
    method= "lm",             
    formula= y ~ poly(x, 3),  
    se = TRUE,                 
    color= "red",
    linewidth= 1.2
  ) +
  labs(
    title= "Deg3 Polynomial Regression Fit: Wage vs. Age",
    x="Age (Years)",
    y= "Wage"
  ) +
  theme_minimal()

The optimum number of cuts was chosen to be 5. It is true that degree poly 8 has the lowest RMSE, however the rate of return after each subsequent cut is not justified to get that many number of cuts. When compared to the polynomial model of degree 3 (RMSE=39.87239) the 5 cut yields an RMSE of (40.21877), only slightly being out beat by the poly model.

#set up cross alidation and cut params 
cross_v<- trainControl(method='cv',n=10)
min = 2
max = 15

results<- vector('list', 14)

#fit and create the model 
for(k in min:max){
  
  #create step formula 
  step_function<- as.formula(paste0('wage~cut(age,',k,',)'))
  
  #trainining
  step_model <-train(
    step_function,
    data=Wage,
    method='lm',
    trControl=cross_v
  )
  
  #save to dataframe
  results[[k-1]] <- data.frame(
    Cuts= k,
    RMSE= step_model$results$RMSE,
    R_SQR= step_model$results$Rsquared,
    MAE = step_model$results$MAE
  )
  
}


step_totals_df<- do.call(rbind,results)
print(step_totals_df)
   Cuts     RMSE       R_SQR      MAE
1     2 41.57520 0.008875974 29.47106
2     3 40.90143 0.036063139 28.84012
3     4 40.37225 0.064067076 28.38677
4     5 40.27545 0.065520491 28.36088
5     6 40.12825 0.070668278 28.15244
6     7 40.05921 0.076621377 27.97358
7     8 39.92510 0.082852119 27.78275
8     9 40.09196 0.075297993 27.88813
9    10 39.93270 0.083488952 27.84428
10   11 39.89824 0.081971222 27.80828
11   12 39.92912 0.081844914 27.84788
12   13 40.01763 0.081928527 27.93194
13   14 40.01556 0.079243217 27.90990
14   15 39.95376 0.082355874 27.87934
ggplot(Wage, aes(x=age, y=wage))+
  geom_point(color='black',alpha=.3, size=1.2)+
  stat_smooth(
    method='lm',
    formula= y~cut(x,5),
    se=TRUE,
    color='red'
  )+
  labs(
    title= 'K=5 cuts: Wage vs Age',
    x='Age',
    y='Wage'
  )+
  theme_minimal()

10

library(leaps)
set.seed(1)
attach(College)
train <- sample(length(Outstate), length(Outstate) / 2)
test <- -train
College.train <- College[train, ]
College.test <- College[test, ]
fit <- regsubsets(Outstate ~ ., data = College.train, nvmax = 17, method = "forward")
fit.summary <- summary(fit)
par(mfrow = c(1, 3))
plot(fit.summary$cp, xlab = "Number of variables", ylab = "Cp", type = "l")
min.cp <- min(fit.summary$cp)
std.cp <- sd(fit.summary$cp)
abline(h = min.cp + 0.2 * std.cp, col = "red", lty = 2)
abline(h = min.cp - 0.2 * std.cp, col = "red", lty = 2)
plot(fit.summary$bic, xlab = "Number of variables", ylab = "BIC", type='l')
min.bic <- min(fit.summary$bic)
std.bic <- sd(fit.summary$bic)
abline(h = min.bic + 0.2 * std.bic, col = "red", lty = 2)
abline(h = min.bic - 0.2 * std.bic, col = "red", lty = 2)
plot(fit.summary$adjr2, xlab = "Number of variables", ylab = "Adjusted R2", type = "l", ylim = c(0.4, 0.84))
max.adjr2 <- max(fit.summary$adjr2)
std.adjr2 <- sd(fit.summary$adjr2)
abline(h = max.adjr2 + 0.2 * std.adjr2, col = "red", lty = 2)
abline(h = max.adjr2 - 0.2 * std.adjr2, col = "red", lty = 2)

#from table above 6 is the minimum number of optimum variables
lm1 <- regsubsets(Outstate ~ ., data = College, method = "forward")
coeffs <- coef(fit, id = 6)
names(coeffs)
[1] "(Intercept)" "PrivateYes"  "Room.Board"  "Terminal"    "perc.alumni"
[6] "Expend"      "Grad.Rate"  
library(gam)
Warning: package 'gam' was built under R version 4.5.3
Loading required package: splines
Loading required package: foreach
Warning: package 'foreach' was built under R version 4.5.2
Loaded gam 1.22-7
gam1 <- gam(Outstate ~ Private + s(Room.Board, df = 2) + s(PhD, df = 2) + s(perc.alumni, df = 2) + s(Expend, df = 5) + s(Grad.Rate, df = 2), data=College.train)
par(mfrow = c(2, 3))
plot(gam1, se = T, col = "blue")

From the graphs above, Board, alumni, and rate all show a linear pattern, meanwhile the Expend variables shows a very strong indication of being nonlinear with the curve. The variable phD is a very weak nonlinear pattern with a slight curve upward.

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
}

preds <- predict(fit, College.test, id=6)
err <- mean((College.test$Outstate - preds)^2)
cat('\nError Term:',err,'\n')

Error Term: 3844857 
tss <- mean((College.test$Outstate - mean(College.test$Outstate))^2)
rss <- 1 - err / tss
cat('RSS:',rss,'\n\n\n')
RSS: 0.7313788 
summary(gam1)

Call: gam(formula = Outstate ~ Private + s(Room.Board, df = 2) + s(PhD, 
    df = 2) + s(perc.alumni, df = 2) + s(Expend, df = 5) + s(Grad.Rate, 
    df = 2), data = College.train)
Deviance Residuals:
     Min       1Q   Median       3Q      Max 
-7402.89 -1114.45   -12.67  1282.69  7470.60 

(Dispersion Parameter for gaussian family taken to be 3711182)

    Null Deviance: 6989966760 on 387 degrees of freedom
Residual Deviance: 1384271126 on 373 degrees of freedom
AIC: 6987.021 

Number of Local Scoring Iterations: NA 

Anova for Parametric Effects
                        Df     Sum Sq    Mean Sq F value    Pr(>F)    
Private                  1 1778718277 1778718277 479.286 < 2.2e-16 ***
s(Room.Board, df = 2)    1 1577115244 1577115244 424.963 < 2.2e-16 ***
s(PhD, df = 2)           1  322431195  322431195  86.881 < 2.2e-16 ***
s(perc.alumni, df = 2)   1  336869281  336869281  90.771 < 2.2e-16 ***
s(Expend, df = 5)        1  530538753  530538753 142.957 < 2.2e-16 ***
s(Grad.Rate, df = 2)     1   86504998   86504998  23.309 2.016e-06 ***
Residuals              373 1384271126    3711182                      
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Anova for Nonparametric Effects
                       Npar Df  Npar F     Pr(F)    
(Intercept)                                         
Private                                             
s(Room.Board, df = 2)        1  1.9157    0.1672    
s(PhD, df = 2)               1  0.9699    0.3253    
s(perc.alumni, df = 2)       1  0.1859    0.6666    
s(Expend, df = 5)            4 20.5075 2.665e-15 ***
s(Grad.Rate, df = 2)         1  0.5702    0.4506    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

From the Anova parametrics table all pvalues being below .05 means all vairables should be included in the model since they are all significant. Fro the non-paramteric table, only Expend has a pvalue below .05 so we reject the null hypothesis that, Expend is a strictly linear relationship, and all other variables fail to reject null hypothesis.