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.
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
##
##
##
##
plot(Weekly, cex = 0.5)
lr.weekly <- glm(Direction ~ Lag1 + Lag2 + Lag3 + Lag4 + Lag5 + Volume,
data = Weekly, family = binomial)
summary(lr.weekly)
##
## Call:
## glm(formula = Direction ~ Lag1 + Lag2 + Lag3 + Lag4 + Lag5 +
## Volume, family = binomial, data = Weekly)
##
## 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
Lag2 appears to be statistically significant with a P-value of 0.0296.
contrasts(Weekly$Direction)
## Up
## Down 0
## Up 1
lr.weekly.pred <- predict(lr.weekly, type = "response") > 0.5
(pred.table <- table(ifelse(lr.weekly.pred, "Up (pred)", "Down (pred)"), Weekly$Direction))
##
## Down Up
## Down (pred) 54 48
## Up (pred) 430 557
sum(diag(pred.table)) / sum(pred.table)
## [1] 0.5610652
Confusion matrix tells us things such as recall and precision. Overall accuracy was 0.56.
sub.week <- Weekly$Year < 2009
new.model <- glm(Direction ~ Lag2, data = Weekly[sub.week, ], family = binomial)
new.predict <- predict(new.model, Weekly[!sub.week, ], type = "response") > 0.5
(new.pred.table <- table(ifelse(new.predict, "Up (pred)", "Down (pred)"), Weekly[!sub.week, ]$Direction))
##
## Down Up
## Down (pred) 9 5
## Up (pred) 34 56
sum(diag(new.pred.table)) / sum(new.pred.table)
## [1] 0.625
new.model2 <- lda(Direction ~ Lag2, data = Weekly[sub.week, ])
new.predict2 <- predict(new.model2, Weekly[!sub.week, ], type = "response")$class
(new.predict.table2 <- table(new.predict2, Weekly[!sub.week, ]$Direction))
##
## new.predict2 Down Up
## Down 9 5
## Up 34 56
sum(diag(new.predict.table2)) / sum(new.predict.table2)
## [1] 0.625
new.model3 <- qda(Direction ~ Lag2, data = Weekly[sub.week, ])
new.predict3 <- predict(new.model3, Weekly[!sub.week, ], type = "response")$class
(new.predict.table3 <- table(new.predict3, Weekly[!sub.week, ]$Direction))
##
## new.predict3 Down Up
## Down 0 0
## Up 43 61
sum(diag(new.predict.table3)) / sum(new.predict.table3)
## [1] 0.5865385
new.model4 <- knn(Weekly[sub.week, "Lag2", drop = FALSE],
Weekly[!sub.week, "Lag2", drop = FALSE],
Weekly$Direction[sub.week]
)
(new.predict.table4 <- table(new.model4, Weekly[!sub.week, ]$Direction))
##
## new.model4 Down Up
## Down 21 30
## Up 22 31
sum(diag(new.predict.table4)) / sum(new.predict.table4)
## [1] 0.5
new.model5 <- naiveBayes(Direction ~ Lag2, data = Smarket, subset = sub.week)
new.predict5 <- predict(new.model5, Weekly[!sub.week, ], type = "class")
(new.predict.table5 <- table(new.predict5, Weekly[!sub.week, ]$Direction))
##
## new.predict5 Down Up
## Down 27 29
## Up 16 32
sum(diag(new.predict.table5)) / sum(new.predict.table5)
## [1] 0.5673077
Logistic regression and LDA had the highest scores with 0.625 overall accuracy.
sub.week <- Weekly$Year < 2009
new.model <- glm(Direction ~ Lag1 + Lag2, data = Weekly[sub.week, ], family = binomial)
new.predict <- predict(new.model, Weekly[!sub.week, ], type = "response") > 0.5
(new.pred.table <- table(ifelse(new.predict, "Up (pred)", "Down (pred)"), Weekly[!sub.week, ]$Direction))
##
## Down Up
## Down (pred) 7 8
## Up (pred) 36 53
sum(diag(pred.table)) / sum(pred.table)
## [1] 0.5610652
new.model2 <- lda(Direction ~ Lag1 + Lag2 + Lag3, data = Weekly[sub.week, ])
new.predict2 <- predict(new.model2, Weekly[!sub.week, ], type = "response")$class
(new.predict.table2 <- table(new.predict2, Weekly[!sub.week, ]$Direction))
##
## new.predict2 Down Up
## Down 8 9
## Up 35 52
sum(diag(new.predict.table2)) / sum(new.predict.table2)
## [1] 0.5769231
new.model3 <- qda(Direction ~ Lag2 + Lag3, data = Weekly[sub.week, ])
new.predict3 <- predict(new.model3, Weekly[!sub.week, ], type = "response")$class
(new.predict.table3 <- table(new.predict3, Weekly[!sub.week, ]$Direction))
##
## new.predict3 Down Up
## Down 4 2
## Up 39 59
sum(diag(new.predict.table3)) / sum(new.predict.table3)
## [1] 0.6057692
new.model4 <- knn(Weekly[sub.week, "Lag3", drop = FALSE],
Weekly[!sub.week, "Lag3", drop = FALSE],
Weekly$Direction[sub.week]
)
(new.predict.table4 <- table(new.model4, Weekly[!sub.week, ]$Direction))
##
## new.model4 Down Up
## Down 21 27
## Up 22 34
sum(diag(new.predict.table4)) / sum(new.predict.table4)
## [1] 0.5288462
new.model5 <- naiveBayes(Direction ~ Lag1 + Lag2, data = Smarket, subset = sub.week)
new.predict5 <- predict(new.model5, Weekly[!sub.week, ], type = "class")
(new.predict.table5 <- table(new.predict5, Weekly[!sub.week, ]$Direction))
##
## new.predict5 Down Up
## Down 34 39
## Up 9 22
sum(diag(new.predict.table5)) / sum(new.predict.table5)
## [1] 0.5384615
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.
m <- cbind(Auto[, -1], data.frame("mpg01" = Auto$mpg > median(Auto$mpg)))
pairs(m[, 1:7])
par(mfrow = c(2, 4))
for (i in 1:7) hist(m[, i], breaks = 20, main = colnames(m)[i])
for (i in 1:7) boxplot(m[, i] ~ m$mpg01, main = colnames(m)[i])
Displacement, horsepower, weight, and acceleration seem to be useful in predicting mpg01. There seems to be linear relationships among the variables.
set.seed(42)
train <- sample(seq_len(nrow(m)), nrow(m) * 4/5)
sort(sapply(1:7, function(i) {
setNames(abs(t.test(m[, i] ~ m$mpg01)$statistic), colnames(m)[i])
}))
## acceleration year origin horsepower displacement weight
## 7.302430 9.403221 11.824099 17.681939 22.632004 22.932777
## cylinders
## 23.035328
mpg.lda <- lda(mpg01 ~ displacement + horsepower + weight + acceleration, data = m[train, ])
mpg.pred <- predict(mpg.lda, m[-train, ], type = "response")$class
mean(mpg.pred != m[-train, ]$mpg01)
## [1] 0.06329114
mpg.qda <- qda(mpg01 ~ displacement + horsepower + weight + acceleration, data = m[train, ])
mpg.pred.2 <- predict(mpg.qda, m[-train, ], type = "response")$class
mean(mpg.pred.2 != m[-train, ]$mpg01)
## [1] 0.08860759
mpg.glm <- glm(mpg01 ~ displacement + horsepower + weight + acceleration, data = m[train, ], family = binomial)
mpg.pred.3 <- predict(mpg.glm, m[-train, ], type = "response") > 0.5
mean(mpg.pred.3 != m[-train, ]$mpg01)
## [1] 0.06329114
mpg.bayes <- naiveBayes(mpg01 ~ displacement + horsepower + weight + acceleration, data = m[train, ])
mpg.pred.4 <- predict(mpg.bayes, m[-train, ], type = "class")
mean(mpg.pred.4 != m[-train, ]$mpg01)
## [1] 0.06329114
res <- sapply(1:50, function(k) {
mpg.knn <- knn(m[train, c(2, 3, 4, 5)], m[-train, c(2, 3, 4, 5)], m$mpg01[train], k = k)
mean(mpg.knn != m[-train, ]$mpg01)
})
names(res) <- 1:50
plot(res, type = "o")
res[which.min(res)]
## 3
## 0.07594937
LDA, logistic regression, and Bayes had the lowest test error rates of 0.0633.
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. Hint: You will have to create the response variable yourself, using the variables that are contained in the Boston data set.
crime.med <- ifelse(Boston$crim > median(Boston$crim), 1, 0)
Boston$crime.med <- crime.med
boston.glm <- glm(crime.med ~ ., data = Boston, family = "binomial")
## Warning: glm.fit: algorithm did not converge
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
summary(boston.glm)
##
## Call:
## glm(formula = crime.med ~ ., family = "binomial", data = Boston)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.437e+01 1.202e+05 0.000 1.000
## crim 1.083e+03 1.773e+04 0.061 0.951
## zn 2.194e+00 5.856e+01 0.037 0.970
## indus -2.510e+00 9.002e+02 -0.003 0.998
## chas 4.489e+00 1.014e+04 0.000 1.000
## nox -2.585e+02 1.458e+05 -0.002 0.999
## rm -3.953e+01 1.653e+03 -0.024 0.981
## age 3.437e-01 5.798e+01 0.006 0.995
## dis -1.742e+01 2.146e+03 -0.008 0.994
## rad -5.933e+00 2.642e+03 -0.002 0.998
## tax 1.639e-01 1.078e+02 0.002 0.999
## ptratio 5.525e+00 3.640e+03 0.002 0.999
## black 3.266e-02 1.208e+01 0.003 0.998
## lstat -1.687e+00 3.560e+02 -0.005 0.996
## medv 2.358e+00 5.382e+02 0.004 0.997
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 7.0146e+02 on 505 degrees of freedom
## Residual deviance: 2.8371e-05 on 491 degrees of freedom
## AIC: 30
##
## Number of Fisher Scoring iterations: 25
boston.lda <- lda(crime.med ~ ., data = Boston)
boston.lda
## Call:
## lda(crime.med ~ ., data = Boston)
##
## Prior probabilities of groups:
## 0 1
## 0.5 0.5
##
## Group means:
## crim zn indus chas nox rm age dis
## 0 0.0955715 21.525692 7.002292 0.05138340 0.4709711 6.394395 51.31028 5.091596
## 1 7.1314756 1.201581 15.271265 0.08695652 0.6384190 6.174874 85.83953 2.498489
## rad tax ptratio black lstat medv
## 0 4.158103 305.7431 17.90711 388.7061 9.419486 24.94941
## 1 14.940711 510.7312 19.00395 324.6420 15.886640 20.11621
##
## Coefficients of linear discriminants:
## LD1
## crim 0.0046376592
## zn -0.0056431194
## indus 0.0126159626
## chas -0.0592836851
## nox 8.1826206579
## rm 0.0874007870
## age 0.0112829040
## dis 0.0453643651
## rad 0.0699133176
## tax -0.0008444666
## ptratio 0.0513806507
## black -0.0009892799
## lstat 0.0143945059
## medv 0.0386990631
boston.bayes <- naiveBayes(as.factor(crime.med) ~ ., data = Boston)
boston.bayes
##
## Naive Bayes Classifier for Discrete Predictors
##
## Call:
## naiveBayes.default(x = X, y = Y, laplace = laplace)
##
## A-priori probabilities:
## Y
## 0 1
## 0.5 0.5
##
## Conditional probabilities:
## crim
## Y [,1] [,2]
## 0 0.0955715 0.06281773
## 1 7.1314756 11.10912294
##
## zn
## Y [,1] [,2]
## 0 21.525692 29.319808
## 1 1.201581 4.798611
##
## indus
## Y [,1] [,2]
## 0 7.002292 5.514454
## 1 15.271265 5.439010
##
## chas
## Y [,1] [,2]
## 0 0.05138340 0.2212161
## 1 0.08695652 0.2823299
##
## nox
## Y [,1] [,2]
## 0 0.4709711 0.05559789
## 1 0.6384190 0.09870365
##
## rm
## Y [,1] [,2]
## 0 6.394395 0.5556856
## 1 6.174874 0.8101381
##
## age
## Y [,1] [,2]
## 0 51.31028 25.88190
## 1 85.83953 17.87423
##
## dis
## Y [,1] [,2]
## 0 5.091596 2.081304
## 1 2.498489 1.085521
##
## rad
## Y [,1] [,2]
## 0 4.158103 1.659121
## 1 14.940711 9.529843
##
## tax
## Y [,1] [,2]
## 0 305.7431 87.4837
## 1 510.7312 167.8553
##
## ptratio
## Y [,1] [,2]
## 0 17.90711 1.811216
## 1 19.00395 2.346947
##
## black
## Y [,1] [,2]
## 0 388.7061 22.83774
## 1 324.6420 118.83084
##
## lstat
## Y [,1] [,2]
## 0 9.419486 4.923497
## 1 15.886640 7.546922
##
## medv
## Y [,1] [,2]
## 0 24.94941 7.232047
## 1 20.11621 10.270362
sample <- sample(1:nrow(Boston), 0.8*nrow(Boston))
train <- Boston[sample, ]
test <- Boston[-sample, ]
boston.knn <- knn(train[, -1], test[, -1], train$crime.med, k = 7)
table(boston.knn, test$crime.med)
##
## boston.knn 0 1
## 0 48 2
## 1 2 50