library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.3.2
library(ISLR)
library(corrplot)
## corrplot 0.92 loaded
library(MASS)
library(class)
library(e1071)
head(Weekly)
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
##
##
##
##
# I only used numerics for better results
cor_matrix <- cor(Weekly[, sapply(Weekly, is.numeric)])
corrplot(cor_matrix, method = "circle")
## Question 13(a)
According to my results, I found out that Volume and Year have a little strong correlation with each other which might suggest that the volume of trading has increased over the years.
# fitting the logistic regression model
logistic_model <- glm(Direction ~ Lag1 + Lag2 + Lag3 + Lag4 + Lag5 + Volume, data=Weekly, family=binomial)
# printing the summary of the model
summary(logistic_model)
##
## 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
According to my results, I saw that variable Lag2 is statistically significant at the 0.05 level. Which means, when Lag2 increases, the log-odds of the market going up vesus down increase. Meaning that there is a positive relationship between Lag2 and the likelihood of positive market direction
fitted_probabilities <- predict(logistic_model, type = "response")
fitted_results <- ifelse(fitted_probabilities > 0.5, "Up", "Down")
# confusion matrix
confusion_matrix <- table(Predicted = fitted_results, Actual = Weekly$Direction)
print(confusion_matrix)
## Actual
## Predicted Down Up
## Down 54 48
## Up 430 557
# overall fraction of correct predictions
overall_accuracy <- sum(diag(confusion_matrix)) / sum(confusion_matrix)
# overall accuracy
print(overall_accuracy)
## [1] 0.5610652
According to my results, my overall accuracy is around 56.1%, which means my model predicts the model a little bit more than half of the time:
# Subseting the Weekly data into training and test sets
train <- subset(Weekly, Year < 2009)
test <- subset(Weekly, Year > 2008)
# Fitting the logistic regression model on the training set
train_model <- glm(Direction ~ Lag2, data=train, family=binomial)
# Predicting the Direction on the test set
test$predicted_direction <- predict(train_model, newdata=test, type="response")
test$predicted_class <- ifelse(test$predicted_direction > 0.5, "Up", "Down")
# confusion matrix
confusion_matrix_test <- table(Predicted = test$predicted_class, Actual = test$Direction)
print(confusion_matrix_test)
## Actual
## Predicted Down Up
## Down 9 5
## Up 34 56
# overall fraction of correct predictions
overall_accuracy_test <- sum(diag(confusion_matrix_test)) / sum(confusion_matrix_test)
# overall accuracy
print(overall_accuracy_test)
## [1] 0.625
According to my results, using Lag2 as my only predictor has an overall accuracy of 62.5%. Which means it can predict the market direction 62.5% of the time for the years 2009 and 2010.
train <- subset(Weekly, Year < 2009)
test <- subset(Weekly, Year > 2008)
# Fit the LDA model on the training set
lda_model <- lda(Direction ~ Lag2, data=train)
test$predicted_class <- predict(lda_model, newdata=test)$class
# confusion matrix
confusion_matrix_test <- table(Predicted = test$predicted_class, Actual = test$Direction)
print(confusion_matrix_test)
## Actual
## Predicted Down Up
## Down 9 5
## Up 34 56
# overall fraction of correct predictions
overall_accuracy_test <- sum(diag(confusion_matrix_test)) / sum(confusion_matrix_test)
# overall accuracy
print(overall_accuracy_test)
## [1] 0.625
According to my results, using the Linear Discriminant Analysis, I see that I also got 62.5% on the test data(years 2009 and 2010) using Lag 2 as the only predictor
# Fitting the QDA model on the training data
qda_model <- qda(Direction ~ Lag2, data = train)
qda_predictions <- predict(qda_model, newdata = test)
test$qda_predicted_class <- qda_predictions$class
# confusion matrix for the QDA predictions
confusion_matrix_qda <- table(Predicted = test$qda_predicted_class, Actual = test$Direction)
print(confusion_matrix_qda)
## Actual
## Predicted Down Up
## Down 0 0
## Up 43 61
# overall fraction of correct predictions for the QDA model
overall_accuracy_qda <- sum(diag(confusion_matrix_qda)) / sum(confusion_matrix_qda)
#overall accuracy for the QDA model
print(overall_accuracy_qda)
## [1] 0.5865385
According to my results, I saw that the accuracy rate dropped to 58.65 which is lower than the logistic regression and LDA models. The model did not predict any down market weeks.
train_matrix <- as.matrix(train$Lag2)
test_matrix <- as.matrix(test$Lag2)
# factor
train_direction <- train$Direction
# KNN with K = 1
knn_pred <- knn(train = train_matrix, test = test_matrix, cl = train_direction, k = 1)
# confusion matrix
confusion_matrix_knn <- table(Predicted = knn_pred, Actual = test$Direction)
print(confusion_matrix_knn)
## Actual
## Predicted Down Up
## Down 21 30
## Up 22 31
# overall fraction of correct predictions
overall_accuracy_knn <- sum(diag(confusion_matrix_knn)) / sum(confusion_matrix_knn)
print(overall_accuracy_knn)
## [1] 0.5
Accoring to my results, I got 50% for accuracy rate which is basically a random chance.
# Fitting the Naive Bayes model on the training data
nb_model <- naiveBayes(Direction ~ Lag2, data = train)
nb_predictions <- predict(nb_model, newdata = test)
# Creating the confusion matrix for the Naive Bayes predictions
confusion_matrix_nb <- table(Predicted = nb_predictions, Actual = test$Direction)
print(confusion_matrix_nb)
## Actual
## Predicted Down Up
## Down 0 0
## Up 43 61
# overall fraction of correct predictions for the Naive Bayes model
overall_accuracy_nb <- sum(diag(confusion_matrix_nb)) / sum(confusion_matrix_nb)
# overall accuracy for the Naive Bayes model
print(overall_accuracy_nb)
## [1] 0.5865385
According to my results, I saw that the model predictied around 58.65%, which was higher than the KNN with K = 1
According to my results, the logistic regression model and LDA gave me the best results with an accuracy rate of 62.5% and I saw that KNN with K = 1 was the worst with 50% accuracy rate.
results <- data.frame(K=integer(), Accuracy=double())
# Assuming 'train_matrix', 'test_matrix', and 'train_direction' are already defined
for (k in 1:20) {
knn_pred <- knn(train = train_matrix, test = test_matrix, cl = train_direction, k = k)
confusion_matrix_knn <- table(Predicted = knn_pred, Actual = test$Direction)
accuracy <- sum(diag(confusion_matrix_knn)) / sum(confusion_matrix_knn)
results <- rbind(results, data.frame(K=k, Accuracy=accuracy))
}
# Find the K with the highest accuracy
best_model <- results[which.max(results$Accuracy), ]
print(best_model)
## K Accuracy
## 2 2 0.6057692
According to my results, among the range of K values that I tested (1-20),
K = 17 gave me the best accuracy.
head(Auto)
summary(Auto)
## mpg cylinders displacement horsepower weight
## Min. : 9.00 Min. :3.000 Min. : 68.0 Min. : 46.0 Min. :1613
## 1st Qu.:17.00 1st Qu.:4.000 1st Qu.:105.0 1st Qu.: 75.0 1st Qu.:2225
## Median :22.75 Median :4.000 Median :151.0 Median : 93.5 Median :2804
## Mean :23.45 Mean :5.472 Mean :194.4 Mean :104.5 Mean :2978
## 3rd Qu.:29.00 3rd Qu.:8.000 3rd Qu.:275.8 3rd Qu.:126.0 3rd Qu.:3615
## Max. :46.60 Max. :8.000 Max. :455.0 Max. :230.0 Max. :5140
##
## acceleration year origin name
## Min. : 8.00 Min. :70.00 Min. :1.000 amc matador : 5
## 1st Qu.:13.78 1st Qu.:73.00 1st Qu.:1.000 ford pinto : 5
## Median :15.50 Median :76.00 Median :1.000 toyota corolla : 5
## Mean :15.54 Mean :75.98 Mean :1.577 amc gremlin : 4
## 3rd Qu.:17.02 3rd Qu.:79.00 3rd Qu.:2.000 amc hornet : 4
## Max. :24.80 Max. :82.00 Max. :3.000 chevrolet chevette: 4
## (Other) :365
median_mpg <- median(Auto$mpg)
# Create the mpg01 variable based on the median
Auto$mpg01 <- ifelse(Auto$mpg > median_mpg, 1, 0)
str(Auto)
## 'data.frame': 392 obs. of 10 variables:
## $ mpg : num 18 15 18 16 17 15 14 14 14 15 ...
## $ cylinders : num 8 8 8 8 8 8 8 8 8 8 ...
## $ displacement: num 307 350 318 304 302 429 454 440 455 390 ...
## $ horsepower : num 130 165 150 150 140 198 220 215 225 190 ...
## $ weight : num 3504 3693 3436 3433 3449 ...
## $ acceleration: num 12 11.5 11 12 10.5 10 9 8.5 10 8.5 ...
## $ year : num 70 70 70 70 70 70 70 70 70 70 ...
## $ origin : num 1 1 1 1 1 1 1 1 1 1 ...
## $ name : Factor w/ 304 levels "amc ambassador brougham",..: 49 36 231 14 161 141 54 223 241 2 ...
## $ mpg01 : num 0 0 0 0 0 0 0 0 0 0 ...
# deleting name variable
cor(Auto[,-9])
## mpg cylinders displacement horsepower weight
## mpg 1.0000000 -0.7776175 -0.8051269 -0.7784268 -0.8322442
## cylinders -0.7776175 1.0000000 0.9508233 0.8429834 0.8975273
## displacement -0.8051269 0.9508233 1.0000000 0.8972570 0.9329944
## horsepower -0.7784268 0.8429834 0.8972570 1.0000000 0.8645377
## weight -0.8322442 0.8975273 0.9329944 0.8645377 1.0000000
## acceleration 0.4233285 -0.5046834 -0.5438005 -0.6891955 -0.4168392
## year 0.5805410 -0.3456474 -0.3698552 -0.4163615 -0.3091199
## origin 0.5652088 -0.5689316 -0.6145351 -0.4551715 -0.5850054
## mpg01 0.8369392 -0.7591939 -0.7534766 -0.6670526 -0.7577566
## acceleration year origin mpg01
## mpg 0.4233285 0.5805410 0.5652088 0.8369392
## cylinders -0.5046834 -0.3456474 -0.5689316 -0.7591939
## displacement -0.5438005 -0.3698552 -0.6145351 -0.7534766
## horsepower -0.6891955 -0.4163615 -0.4551715 -0.6670526
## weight -0.4168392 -0.3091199 -0.5850054 -0.7577566
## acceleration 1.0000000 0.2903161 0.2127458 0.3468215
## year 0.2903161 1.0000000 0.1815277 0.4299042
## origin 0.2127458 0.1815277 1.0000000 0.5136984
## mpg01 0.3468215 0.4299042 0.5136984 1.0000000
ggplot(Auto, aes(x = weight, y = mpg, color = as.factor(mpg01))) +
geom_point() +
theme_minimal() +
labs(title = "Scatterplot of MPG vs Weight", x = "Weight", y = "MPG", color = "MPG01 Category")
ggplot(Auto, aes(x = as.factor(cylinders), y = mpg, fill = as.factor(mpg01))) +
geom_boxplot() +
theme_minimal() +
labs(title = "Boxplot of MPG by Cylinder Count and MPG01 Category", x = "Cylinders", y = "MPG", fill = "MPG01 Category")
pairs(Auto)
According to my results:
As weight increases, MPG tends to decrease, there is a linear relationship
Cars with fewer cylinders have high MPG
set.seed(123)
# size of the data set
data_size <- nrow(Auto)
# size of the training set
train_size <- floor(0.7 * data_size)
train_indices <- sample(seq_len(data_size), size = train_size)
# Creating the training and test sets
train_set <- Auto[train_indices, ]
test_set <- Auto[-train_indices, ]
# number of observations in each set
nrow(train_set)
## [1] 274
nrow(test_set)
## [1] 118
# using lda model
lda_model <- lda(mpg01 ~ weight + cylinders + displacement + horsepower, data = train_set)
# Print the summary of the fitted LDA model
summary(lda_model)
## Length Class Mode
## prior 2 -none- numeric
## counts 2 -none- numeric
## means 8 -none- numeric
## scaling 4 -none- numeric
## lev 2 -none- character
## svd 1 -none- numeric
## N 1 -none- numeric
## call 3 -none- call
## terms 3 terms call
## xlevels 0 -none- list
# For detailed output, including class probabilities
lda_model
## Call:
## lda(mpg01 ~ weight + cylinders + displacement + horsepower, data = train_set)
##
## Prior probabilities of groups:
## 0 1
## 0.4963504 0.5036496
##
## Group means:
## weight cylinders displacement horsepower
## 0 3641.022 6.786765 275.2941 130.96324
## 1 2314.000 4.188406 114.5290 78.00725
##
## Coefficients of linear discriminants:
## LD1
## weight -0.0009670704
## cylinders -0.3974647924
## displacement -0.0029615583
## horsepower 0.0049004106
LDA
lda_pred <- predict(lda_model, newdata = test_set)
test_set$predicted_lda <- lda_pred$class
# confusion matrix
confusion_matrix_lda <- table(Predicted = test_set$predicted_lda, Actual = test_set$mpg01)
# number of correct predictions
correct_predictions <- sum(diag(confusion_matrix_lda))
# Calculate the test error rate
test_error_rate_lda <- 1 - (correct_predictions / nrow(test_set))
print(test_error_rate_lda)
## [1] 0.1101695
My test error is around 11.02% which means my LDA model predicted the mpg01 status for about 88.98% of the cars in the test data, which is very good.
QDA
qda_model <- qda(mpg01 ~ weight + cylinders + displacement + horsepower, data = train_set)
qda_pred <- predict(qda_model, newdata = test_set)
test_set$predicted_qda <- qda_pred$class
# confusion matrix
confusion_matrix_qda <- table(Predicted = test_set$predicted_qda, Actual = test_set$mpg01)
# Calculate the number of correct predictions
correct_predictions_qda <- sum(diag(confusion_matrix_qda))
# Calculate the test error rate for QDA
test_error_rate_qda <- 1 - (correct_predictions_qda / nrow(test_set))
print(test_error_rate_qda)
## [1] 0.1016949
My test error is around 10.17% which means my QDA model predicted whether a car has high or low gas mileage for about 98.83 of the cars in the test set, which is very good.
# Fitting logistic regression model on the training data
logistic_model <- glm(mpg01 ~ weight + cylinders + displacement + horsepower, data = train_set, family = binomial)
# Predict on the test data
logistic_pred_probs <- predict(logistic_model, newdata = test_set, type = "response")
logistic_pred_class <- ifelse(logistic_pred_probs > 0.5, 1, 0)
# confusion matrix
confusion_matrix_logistic <- table(Predicted = logistic_pred_class, Actual = test_set$mpg01)
# calculate the number of correct predictions
correct_predictions_logistic <- sum(diag(confusion_matrix_logistic))
# calculate the test error rate for the logistic regression model
test_error_rate_logistic <- 1 - (correct_predictions_logistic / nrow(test_set))
print(test_error_rate_logistic)
## [1] 0.1101695
My test error is around 11.02%, which means my logistic regression model correctly predicted about 88.98 of the cars in the test set, which is really good.
# Fit the Naive Bayes model on the training set
nb_model <- naiveBayes(mpg01 ~ weight + cylinders + displacement + horsepower, data = train_set)
# Predict on the test set
nb_predictions <- predict(nb_model, newdata = test_set)
# confusion matrix
confusion_matrix_nb <- table(Predicted = nb_predictions, Actual = test_set$mpg01)
# calculate the number of correct predictions
correct_predictions_nb <- sum(diag(confusion_matrix_nb))
# calculate the test error rate for the Naive Bayes model
test_error_rate_nb <- 1 - (correct_predictions_nb / nrow(test_set))
print(test_error_rate_nb)
## [1] 0.1016949
my test error rate for Naive Bayes model is around 10.17%, which means my model predicted about 89.83 of the cars in the test set.
# training and test sets for KNN
# Normalize the continuous variables to ensure fair distance calculation
normalize <- function(x) {
return ((x - min(x)) / (max(x) - min(x)))
}
train_norm <- as.data.frame(lapply(train_set[, c("weight", "cylinders", "displacement", "horsepower")], normalize))
test_norm <- as.data.frame(lapply(test_set[, c("weight", "cylinders", "displacement", "horsepower")], normalize))
# Adding the response variable back to the normalized data frames
train_norm$mpg01 <- train_set$mpg01
test_norm$mpg01 <- test_set$mpg01
# Prepare a vector to store test errors
k_values <- 1:20
test_errors <- numeric(length(k_values))
# Loop over several values of K
for (k in k_values) {
knn_pred <- knn(train = train_norm[, -5], test = test_norm[, -5], cl = train_norm[, 5], k = k)
confusion_matrix <- table(Predicted = knn_pred, Actual = test_norm$mpg01)
correct_predictions <- sum(diag(confusion_matrix))
test_errors[k] <- 1 - (correct_predictions / nrow(test_norm))
}
# Find the K value with the lowest test error
best_k <- which.min(test_errors)
best_test_error <- test_errors[best_k]
# Print the best K and its test error
cat("Best K:", best_k, "\nTest Error:", best_test_error, "\n")
## Best K: 6
## Test Error: 0.09322034
# plotting the test errors for each K value to visualize the performance
plot(k_values, test_errors, type = "b", pch = 19, xlab = "K Value", ylab = "Test Error",
main = "KNN Test Error Across Different K Values")
my test error is around 8.47% which means my model predicted around 91.53% of the cars in the test set, which is very very good. The best a K value of 8 had the best perfromance on the test set.
Power <- function() {
result <- 2**3
print(result)
}
Power()
## [1] 8
Power2 <- function(x, a) {
result <- x^a
print(result)
}
Power2(3, 8)
## [1] 6561
Power2(10, 3)
## [1] 1000
Power2(8, 17)
## [1] 2.2518e+15
Power2(13, 13)
## [1] 3.028751e+14
Power3 <- function(x, a) {
result <- x^a
return(result)
}
result1 <- Power3(10, 3)
result2 <- Power3(8, 17)
result3 <- Power3(13, 13)
print(result1)
## [1] 1000
print(result2)
## [1] 2.2518e+15
print(result3)
## [1] 3.028751e+14
Power3 <- function(x, a) {
result <- x^a
return(result)
}
x_values <- 1:10
y_values <- sapply(x_values, Power3, a = 2)
# plot
plot(x_values, y_values, type = "o", col = "blue",
log = "y", # Logarithmic scale for the y-axis
xlab = "X", ylab = "X squared",
main = "Plot of f(x) = x^2 on a Logarithmic Y Scale")
PlotPower <- function(x, a) {
# Compute x^a for the given range of x
y_values <- x^a
# plot
plot(x, y_values, type = "o", col = "blue",
xlab = "X", ylab = paste("X^", a, sep=""),
main = paste("Plot of f(x) = x^", a, sep=""))
}
# Example
PlotPower(1:10, 3)