13. This question should be answered using the Weekly data set, which is part of the ISLR2 package. This data is similar in nature to the Smarket data from this chapter’s lab, except that it contains 1, 089 weekly returns for 21 years, from the beginning of 1990 to the end of 2010.

library(ISLR2)

#(a) Produce some numerical and graphical summaries of the Weekly data. Do there appear to be any patterns?

summary (Weekly)
##       Year           Lag1               Lag2               Lag3         
##  Min.   :1990   Min.   :-18.1950   Min.   :-18.1950   Min.   :-18.1950  
##  1st Qu.:1995   1st Qu.: -1.1540   1st Qu.: -1.1540   1st Qu.: -1.1580  
##  Median :2000   Median :  0.2410   Median :  0.2410   Median :  0.2410  
##  Mean   :2000   Mean   :  0.1506   Mean   :  0.1511   Mean   :  0.1472  
##  3rd Qu.:2005   3rd Qu.:  1.4050   3rd Qu.:  1.4090   3rd Qu.:  1.4090  
##  Max.   :2010   Max.   : 12.0260   Max.   : 12.0260   Max.   : 12.0260  
##       Lag4               Lag5              Volume            Today         
##  Min.   :-18.1950   Min.   :-18.1950   Min.   :0.08747   Min.   :-18.1950  
##  1st Qu.: -1.1580   1st Qu.: -1.1660   1st Qu.:0.33202   1st Qu.: -1.1540  
##  Median :  0.2380   Median :  0.2340   Median :1.00268   Median :  0.2410  
##  Mean   :  0.1458   Mean   :  0.1399   Mean   :1.57462   Mean   :  0.1499  
##  3rd Qu.:  1.4090   3rd Qu.:  1.4050   3rd Qu.:2.05373   3rd Qu.:  1.4050  
##  Max.   : 12.0260   Max.   : 12.0260   Max.   :9.32821   Max.   : 12.0260  
##  Direction 
##  Down:484  
##  Up  :605  
##            
##            
##            
## 
pairs(Weekly)

##Only Year and Volume demonstrate any significant correlations.

#(b) Use the full data set to perform a logistic regression with Direction as the response and the five lag variables plus Volume as predictors. Use the summary function to print the results. Do any of the predictors appear to be statistically significant? If so, which ones?

## Lag2 appears to demonstrate some statistical significance.

logmod = glm(Direction~Lag1+Lag2+Lag3+Lag4+Lag5+Volume,family = "binomial", data=Weekly)
summary(logmod)
## 
## Call:
## glm(formula = Direction ~ Lag1 + Lag2 + Lag3 + Lag4 + Lag5 + 
##     Volume, family = "binomial", data = Weekly)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -1.6949  -1.2565   0.9913   1.0849   1.4579  
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)   
## (Intercept)  0.26686    0.08593   3.106   0.0019 **
## Lag1        -0.04127    0.02641  -1.563   0.1181   
## Lag2         0.05844    0.02686   2.175   0.0296 * 
## Lag3        -0.01606    0.02666  -0.602   0.5469   
## Lag4        -0.02779    0.02646  -1.050   0.2937   
## Lag5        -0.01447    0.02638  -0.549   0.5833   
## Volume      -0.02274    0.03690  -0.616   0.5377   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1496.2  on 1088  degrees of freedom
## Residual deviance: 1486.4  on 1082  degrees of freedom
## AIC: 1500.4
## 
## Number of Fisher Scoring iterations: 4
#(c) Compute the confusion matrix and overall fraction of correct predictions. Explain what the confusion matrix is telling you about the types of mistakes made by logistic regression.

## Only 11.5% of "Down" weekly trends were predicted correctly.

probs = predict(logmod, type="response")
preds = rep("Down", 1089)
preds[probs > 0.5] = "Up"
table(preds, Weekly$Direction)
##       
## preds  Down  Up
##   Down   54  48
##   Up    430 557
557/(48+557)
## [1] 0.9206612
54/(54+430)
## [1] 0.1115702
#(d) Now fit the logistic regression model using a training data period from 1990 to 2008, with Lag2 as the only predictor. Compute the confusion matrix and the overall fraction of correct predictions for the held out data (that is, the data from 2009 and 2010).

training.data = Weekly[Weekly$Year<2009,]
test.data = Weekly[Weekly$Year>2008,]
simpglm = glm(Direction~Lag2, data= training.data, family = "binomial")


summary(simpglm)
## 
## Call:
## glm(formula = Direction ~ Lag2, family = "binomial", data = training.data)
## 
## Deviance Residuals: 
##    Min      1Q  Median      3Q     Max  
## -1.536  -1.264   1.021   1.091   1.368  
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)   
## (Intercept)  0.20326    0.06428   3.162  0.00157 **
## Lag2         0.05810    0.02870   2.024  0.04298 * 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1354.7  on 984  degrees of freedom
## Residual deviance: 1350.5  on 983  degrees of freedom
## AIC: 1354.5
## 
## Number of Fisher Scoring iterations: 4
testprobs = predict(simpglm, type="response", newdata = test.data)
testdirs = Weekly$Direction[Weekly$Year>2008]

testpreds = rep("Down", 104)
testpreds[testprobs>0.5] = "Up"
mean(probs)
## [1] 0.5555556
table(testpreds, testdirs)
##          testdirs
## testpreds Down Up
##      Down    9  5
##      Up     34 56
#(e) Repeat (d) using LDA.

library(MASS)
## 
## Attaching package: 'MASS'
## The following object is masked from 'package:ISLR2':
## 
##     Boston
lda.fit = lda(Direction~Lag2, data= training.data)
lda.fit
## Call:
## lda(Direction ~ Lag2, data = training.data)
## 
## Prior probabilities of groups:
##      Down        Up 
## 0.4477157 0.5522843 
## 
## Group means:
##             Lag2
## Down -0.03568254
## Up    0.26036581
## 
## Coefficients of linear discriminants:
##            LD1
## Lag2 0.4414162
lda.pred = predict(lda.fit, newdata=test.data, type="response")
lda.class = lda.pred$class
table(lda.class, test.data$Direction)
##          
## lda.class Down Up
##      Down    9  5
##      Up     34 56
mean(lda.class == test.data$Direction)
## [1] 0.625
#f) Repeat (d) using QDA

qda.fit = qda(Direction~Lag2, data= training.data)
qda.fit
## Call:
## qda(Direction ~ Lag2, data = training.data)
## 
## Prior probabilities of groups:
##      Down        Up 
## 0.4477157 0.5522843 
## 
## Group means:
##             Lag2
## Down -0.03568254
## Up    0.26036581
qda.pred = predict(qda.fit, newdata=test.data, type="response")
qda.class = qda.pred$class
table(qda.class, test.data$Direction)
##          
## qda.class Down Up
##      Down    0  0
##      Up     43 61
##g) Repeat (d) using KNN with K = 1.
library (class)

set.seed(1)

train.X = cbind(training.data$Lag2)
test.X = cbind(test.data$Lag2)
train.Y = cbind(training.data$Direction)
knn.pred = knn(train.X, test.X, train.Y, k=1)
table(knn.pred, test.data$Direction)
##         
## knn.pred Down Up
##        1   21 30
##        2   22 31
knn3.pred = knn(train.X, test.X, train.Y, k=3)
table(knn3.pred, test.data$Direction)
##          
## knn3.pred Down Up
##         1   16 19
##         2   27 42
##(h) Repeat (d) using naive Bayes.

library (e1071)

train=(Weekly$Year<2009)
weekly09=Weekly[!train ,]
direction09=Weekly$Direction[!train]

dim(weekly09)
## [1] 104   9
nbayes=naiveBayes(Direction~Lag2 ,data=Weekly ,subset=train)

nbayes.class=predict(nbayes ,weekly09)
table(nbayes.class ,direction09)
##             direction09
## nbayes.class Down Up
##         Down    0  0
##         Up     43 61
#(i) Which of these methods appears to provide the best results on this data?

##The methods that have the highest accuracy rates are the Logistic Regression and Linear Discriminant Analysis, as both both rates of 62.5%.


#(j) Experiment with different combinations of predictors, including possible transformations and interactions, for each of the methods. Report the variables, method, and associated confusion matrix that appears to provide the best results on the held out data. Note that you should also experiment with values for K in the KNN classifier

qda.fit2 = qda(Direction~Lag1 + Lag2 + Lag4, data= training.data)
qda.fit2
## Call:
## qda(Direction ~ Lag1 + Lag2 + Lag4, data = training.data)
## 
## Prior probabilities of groups:
##      Down        Up 
## 0.4477157 0.5522843 
## 
## Group means:
##              Lag1        Lag2       Lag4
## Down  0.289444444 -0.03568254 0.15925624
## Up   -0.009213235  0.26036581 0.09220956
qda.pred2 = predict(qda.fit2, newdata=test.data, type="response")
qda.class2 = qda.pred2$class
table(qda.class2, test.data$Direction)
##           
## qda.class2 Down Up
##       Down    9 20
##       Up     34 41
lda.fit2 = lda(Direction~Lag1 + Lag2 + Lag4, data= training.data)
lda.fit2
## Call:
## lda(Direction ~ Lag1 + Lag2 + Lag4, data = training.data)
## 
## Prior probabilities of groups:
##      Down        Up 
## 0.4477157 0.5522843 
## 
## Group means:
##              Lag1        Lag2       Lag4
## Down  0.289444444 -0.03568254 0.15925624
## Up   -0.009213235  0.26036581 0.09220956
## 
## Coefficients of linear discriminants:
##             LD1
## Lag1 -0.2984478
## Lag2  0.2960224
## Lag4 -0.1113485
lda.pred2 = predict(lda.fit2, newdata=test.data, type="response")
lda.class2 = lda.pred2$class
table(lda.class2, test.data$Direction)
##           
## lda.class2 Down Up
##       Down    9  7
##       Up     34 54
##Based on prior experimentation, utilizing Lag2 as the main predictor for direction still appears as the best combination.

14. In this problem, you will develop a model to predict whether a given car gets high or low gas mileage based on the Auto data set.

#a) Create a binary variable, mpg01, that contains a 1 if mpg contains a value above its median, and a 0 if mpg contains a value below its median. You can compute the median using the median() function. Note you may find it helpful to use the data.frame() function to create a single data set containing both mpg01 and the other Auto variables.

library(ISLR2) 
library(tidyverse) 
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
## ✔ ggplot2 3.4.0      ✔ purrr   1.0.1 
## ✔ tibble  3.1.8      ✔ dplyr   1.0.10
## ✔ tidyr   1.3.0      ✔ stringr 1.5.0 
## ✔ readr   2.1.3      ✔ forcats 1.0.0 
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ✖ dplyr::select() masks MASS::select()
library(ggthemes) 
library(GGally)
## Registered S3 method overwritten by 'GGally':
##   method from   
##   +.gg   ggplot2
library(knitr) 
library(kableExtra) 
## 
## Attaching package: 'kableExtra'
## 
## The following object is masked from 'package:dplyr':
## 
##     group_rows
library(broom)

theme_set(theme_tufte(base_size = 14))
set.seed(1)

data('Auto')
Auto <- Auto %>%
    filter(!cylinders %in% c(3,5)) %>%
    mutate(mpg01 = factor(ifelse(mpg > median(mpg), 1, 0)),
           cylinders = factor(cylinders, 
                              levels = c(4,6,8),
                              ordered = TRUE),
           origin = factor(origin,
                           levels = c(1,2,3),
                           labels = c('American', 'European', 'Asian')))
median(Auto$mpg)
## [1] 23
Auto %>%
    dplyr::select(mpg, mpg01) %>%
    sample_n(5)
##    mpg mpg01
## 1 29.8     1
## 2 23.0     0
## 3 25.0     1
## 4 28.4     1
## 5 17.0     0
#(b) Explore the data graphically in order to investigate the association between mpg01 and the other features. Which of the other features seem most likely to be useful in predicting mpg01? Scatterplots and boxplots may be useful tools to answer this question. Describe your findings.

Auto %>%
    dplyr::select(-name, -mpg) %>%
ggpairs(aes(col = mpg01, fill = mpg01, alpha = 0.6),
        upper = list(combo = 'box'),
        diag = list(discrete = wrap('barDiag', position = 'fill')),
        lower = list(combo = 'dot_no_facet')) +
    theme(axis.text.x = element_text(angle = 90, hjust = 1))

Auto %>%
    dplyr::select(-name, -mpg, - origin, -cylinders) %>%
    gather(Variable, value, -mpg01) %>%
    mutate(Variable = str_to_title(Variable)) %>%
    ggplot(aes(mpg01, value, fill = mpg01)) +
    geom_boxplot(alpha = 0.6) +
    facet_wrap(~ Variable, scales = 'free', ncol = 1, switch = 'x') +
    coord_flip() +
    theme(legend.position = 'top') +
    labs(x = '', y = '', title = 'Variable Boxplots by mpg01')
## Warning: The `switch` argument of `facet_wrap()` is deprecated as of ggplot2 2.2.0.
## ℹ Please use the `strip.position` argument instead.

#(c) Split the data into a training set and a test set.

set.seed(1)
num_train <- nrow(Auto) * 0.75

inTrain <- sample(nrow(Auto), size = num_train)

training <- Auto[inTrain,]
testing <- Auto[-inTrain,]

##cylinders, displacement, horsepower, weight, & year seem to hold the most influence for mpg.

#(d) Perform LDA on the training data in order to predict mpg01 using the variables that seemed most associated with mpg01 in (b). What is the test error of the model obtained?

## The test error is  0.104.

require(MASS)
fmla <- as.formula('mpg01 ~ displacement + horsepower + weight + year + cylinders')
lda_model <- lda(fmla, data = training)

pred <- predict(lda_model, testing)
table(pred$class, testing$mpg01)
##    
##      0  1
##   0 48  5
##   1  5 39
mean(pred$class == testing$mpg01)
## [1] 0.8969072
#(e) Perform QDA on the training data in order to predict mpg01 using the variables that seemed most associated with mpg01 in (b). What is the test error of the model obtained?

##The QDA error is 0.104.

qda_model <- qda(fmla, data = training)

pred <- predict(qda_model, testing)
table(pred$class, testing$mpg01)
##    
##      0  1
##   0 48  5
##   1  5 39
mean(pred$class == testing$mpg01)
## [1] 0.8969072
#(f) Perform logistic regression on the training data in order to predict mpg01 using the variables that seemed most associated with mpg01 in (b). What is the test error of the model obtained?

##The logistic regression error is 0.072.

log_reg <- glm(fmla, data = training, family = binomial)

pred <- predict(log_reg, testing, type = 'response')
pred_values <- round(pred)
table(pred_values, testing$mpg01)
##            
## pred_values  0  1
##           0 49  3
##           1  4 41
mean(pred_values == testing$mpg01)
## [1] 0.9278351
#(g) Perform naive Bayes on the training data in order to predict mpg01 using the variables that seemed most associated with mpg01 in (b). What is the test error of the model obtained?

##The naive bayes error is 0.092

nbayes=naiveBayes(fmla, data=training, subset=train)

nbayes.class=predict(nbayes ,testing)
table(nbayes.class ,testing$mpg01)
##             
## nbayes.class  0  1
##            0 48  4
##            1  5 40
mean(nbayes.class == testing$mpg01)
## [1] 0.9072165
#(h) Perform KNN on the training data, with several values of K, in order to predict mpg01. Use only the variables that seemed most associated with mpg01 in (b). What test errors do you obtain? Which value of K seems to perform the best on this data set?


##K = 7 seems to be the best KNN model with an accuracy of 0.897.

require(class)
set.seed(1)
acc <- list()

x_train <- training[,c('cylinders', 'displacement', 'horsepower', 'weight', 'year')]
y_train <- training$mpg0
x_test <- testing[,c('cylinders', 'displacement', 'horsepower', 'weight', 'year')]

for (i in 1:20) {
    knn_pred <- knn(train = x_train, test = x_test, cl = y_train, k = i)
    acc[as.character(i)] = mean(knn_pred == testing$mpg01)
}
acc <- unlist(acc)

data_frame(acc = acc) %>%
    mutate(k = row_number()) %>%
    ggplot(aes(k, acc)) +
    geom_col(aes(fill = k == which.max(acc))) +
    labs(x = 'K', y = 'Accuracy', title = 'KNN Accuracy for different values of K') +
    scale_x_continuous(breaks = 1:20) +
    scale_y_continuous(breaks = round(c(seq(0.90, 0.94, 0.01), max(acc)),
                                      digits = 3)) +
    geom_hline(yintercept = max(acc), lty = 2) +
    coord_cartesian(ylim = c(min(acc), max(acc))) +
    guides(fill = FALSE)
## Warning: `data_frame()` was deprecated in tibble 1.1.0.
## ℹ Please use `tibble()` instead.
## Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
## of ggplot2 3.3.4.

16. Using the Boston data set, fit classification models in order to predict whether a given census tract has a crime rate above or below the median. Explore logistic regression, LDA, naive Bayes, and KNN models using various subsets of the predictors. Describe your findings.

##The correlation matrix demonstrates that rad & tax variables highly influence crime rates; this is also implied from the box-plot visuals. From the KNN graph, we also know the optimal value for K to take, given rad', 'nox', 'tax', 'age', 'dis', 'zn', 'indus' utilized as predictors, would be 3.

library(corrplot)
## corrplot 0.92 loaded
Boston <- Boston %>%
    mutate(chas = factor(chas),
           crime_factor = factor(ifelse(crim > median(crim), 
                                              'High', 'Low'), 
                                       levels = c('High', 'Low')))

cor_test <- Boston %>%
    select(-chas, -crime_factor) %>%
    cor.mtest(conf.level = .95)

Boston %>%
    select(-chas, -crime_factor) %>%
    cor %>%
    corrplot(method = 'color', 
         order = 'hclust', addrect = 2,
         tl.col = 'black', addCoef.col = 'black', number.cex = 0.65,
         p.mat = cor_test$p, sig.level = .05)

Boston %>%
    dplyr::select(zn:crime_factor) %>%
    gather(value_type, value, -crime_factor, -chas) %>%
    ggplot(aes(value_type, value, fill = crime_factor)) +
    geom_boxplot(alpha = 0.5) +
    facet_wrap(~value_type, scales = 'free') +
    scale_fill_discrete(name = 'Crime Rate') +
    theme(legend.position = 'top')

set.seed(1)
train_size <- nrow(Boston) * 0.75
inTrain <- sample(1:nrow(Boston), size = train_size)
train <- Boston[inTrain,]
test <- Boston[-inTrain,]

log_reg <- glm(crime_factor ~ rad + nox + tax + 
                   age + dis + indus, data = train, family = binomial)

log_reg %>%
    tidy %>%
    kable(digits = 3)
term estimate std.error statistic p.value
(Intercept) 31.312 4.984 6.282 0.000
rad -0.602 0.132 -4.543 0.000
nox -53.440 9.090 -5.879 0.000
tax 0.008 0.003 2.903 0.004
age -0.018 0.011 -1.697 0.090
dis -0.544 0.179 -3.034 0.002
indus 0.095 0.049 1.950 0.051
lda_model <- lda(crime_factor ~ poly(rad, 3) + poly(nox, 3) + 
                   poly(tax, 3) + poly(age, 3) + poly(dis, 3), data = train)
pred <- predict(lda_model, test)
acc <- mean(pred$class == test$crime_factor)

table(pred$class, test$crime_factor) %>%
    kable(format = 'html') %>%
    kable_styling() %>%
    add_header_above(c('Predicted' = 1, 'Observed' = 2)) %>%
    column_spec(1, bold = T) %>%
    add_footnote(label = acc)
Predicted
Observed
High Low
High 62 11
Low 2 52
a 0.897637795275591
qda_model <- qda(crime_factor ~ rad + nox + tax + age + dis, data = train)
pred <- predict(qda_model, test)
acc <- mean(pred$class == test$crime_factor) 

table(pred$class, test$crime_factor) %>%
    kable(format = 'html') %>%
    kable_styling() %>%
    add_header_above(c('Predicted' = 1, 'Observed' = 2)) %>%
    column_spec(1, bold = T) %>%
    add_footnote(label = acc)
Predicted
Observed
High Low
High 52 3
Low 12 60
a 0.881889763779528
variables <- c('rad', 'nox', 'tax', 'age', 'dis', 'zn', 'indus')

x_train <- train[, variables]
y_train <- train$crime_factor
x_test <- test[, variables]
acc <- list()

for (i in 1:20) {
    knn_pred <- knn(train = x_train, test = x_test, cl = y_train, k = i)
    acc[as.character(i)] = mean(knn_pred == test$crime_factor)
}

acc <- unlist(acc)

data_frame(acc = acc) %>%
    mutate(k = row_number()) %>%
    ggplot(aes(k, acc)) +
    geom_col(aes(fill = k == which.max(acc))) +
    labs(x = 'K', y = 'Accuracy', title = 'KNN Accuracy for different values of K') +
    scale_x_continuous(breaks = 1:20) +
    scale_y_continuous(breaks = round(c(seq(0.90, 0.94, 0.01), max(acc)),
                                      digits = 3)) +
    geom_hline(yintercept = max(acc), lty = 2) +
    coord_cartesian(ylim = c(min(acc), max(acc))) +
    guides(fill = FALSE)