library(e1071)
## Warning: package 'e1071' was built under R version 4.0.5
\(\textbf{Chapter 9}\)
\(\textbf{Question 5:}\) We have seen that we can fit an SVM with a non-linear kernel in order to perform classification using a non-linear decision boundary. We will now see that we can also obtain a non-linear decision boundary by performing logistic regression using non-linear transformations of the features.
set.seed(5)
x1 = runif(500) - 0.5
x2 = runif(500) - 0.5
y = 1 * (x1^2 - x2^2 > 0)
plot(x1[y == 0], x2[y == 0], xlab = "X1", ylab = "X2", col = "gray", pch = 1)
points(x1[y == 1], x2[y == 1], col = "blue", pch = 3)
fit_1 <- glm(y ~ x1 + x2, family = "binomial")
summary(fit_1)
##
## Call:
## glm(formula = y ~ x1 + x2, family = "binomial")
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -1.200 -1.161 -1.131 1.190 1.223
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -0.03150 0.08949 -0.352 0.725
## x1 -0.06176 0.30506 -0.202 0.840
## x2 -0.11509 0.31086 -0.370 0.711
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 693.02 on 499 degrees of freedom
## Residual deviance: 692.85 on 497 degrees of freedom
## AIC: 698.85
##
## Number of Fisher Scoring iterations: 3
df <- data.frame(x1 = x1, x2 = x2, y = y)
prediction_1 <- predict(fit_1, df, type = "response")
prediction_2 <- ifelse(prediction_1 > 0.5, 1, 0)
df_1 <- df[prediction_2 == 1,]
df_0 <- df[prediction_2 == 0,]
plot(df[prediction_2 == 0,]$x1, df[prediction_2 == 0,]$x2, xlab = "X1", ylab = "X2", col = "gray", pch = 1)
points(df[prediction_2 == 1,]$x1, df[prediction_2 == 1,]$x2, col = "blue", pch = 3)
fit_2 <- glm(y ~ poly(x1, 2) + poly(x2, 2), family = "binomial")
## Warning: glm.fit: algorithm did not converge
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
summary(fit_2)
##
## Call:
## glm(formula = y ~ poly(x1, 2) + poly(x2, 2), family = "binomial")
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -0.003739 0.000000 0.000000 0.000000 0.003504
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 252.0 3439.0 0.073 0.942
## poly(x1, 2)1 2792.7 40700.9 0.069 0.945
## poly(x1, 2)2 100456.5 1343613.6 0.075 0.940
## poly(x2, 2)1 -792.9 16782.0 -0.047 0.962
## poly(x2, 2)2 -99176.6 1325929.2 -0.075 0.940
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 6.9302e+02 on 499 degrees of freedom
## Residual deviance: 2.8367e-05 on 495 degrees of freedom
## AIC: 10
##
## Number of Fisher Scoring iterations: 25
prediction_3 <- predict(fit_2, df, type = "response")
prediction_4 <- ifelse(prediction_3 > 0.5, 1, 0)
plot(df[prediction_4 == 0,]$x1, df[prediction_4 == 0,]$x2, xlab = "X1", ylab = "X2", col = "gray", pch = 1)
points(df[prediction_4 == 1,]$x1, df[prediction_4 == 1,]$x2, col = "blue", pch = 3)
fit_svm <- svm(as.factor(df$y) ~ x1 + x2, df, kernel = "linear", cost = .1)
predictions_svm <- predict(fit_svm, df)
plot(df[predictions_svm == 0,]$x1, df[predictions_svm == 0,]$x2, xlab = "X1", ylab = "X2", col = "gray", pch = 1)
points(df[predictions_svm == 1,]$x1, df[predictions_svm == 1,]$x2, col = "blue", pch = 3)
fit_svm_2 <- svm(as.factor(df$y) ~ x1 + x2, df, kernel = "radial", gamma = 1)
predictions_svm_2 <- predict(fit_svm_2, df)
plot(df[predictions_svm_2 == 0,]$x1, df[predictions_svm_2 == 0,]$x2, xlab = "X1", ylab = "X2", col = "gray", pch = 1)
points(df[predictions_svm_2 == 1,]$x1, df[predictions_svm_2 == 1,]$x2, col = "blue", pch = 3)
\(\textbf{Response:}\) it can be observed that SVM with a non-linear kernel and logistic regression utilizing interaction terms both can offer success in finding non-linear decision boundaries. That being said, the interaction terms I applied to logistic regression appeared to be slightly more effective than the non-linear kernel SVM in this case. On the other hand, both logistic regression without any interaction terms and the linear kernel SVM performed very poorly when tasked with identifying the non-linear decision boundary.
\(\textbf{Question 7:}\) In this problem, you will use support vector approaches in order to predict whether a given car gets high or low gas mileage based on the Auto data set.
library(ISLR)
bin_variable <- ifelse(Auto$mpg > median(Auto$mpg), 1, 0)
Auto$mpglevel <- as.factor(bin_variable)
set.seed(5)
tune_1 <- tune(svm, mpglevel ~ ., data = Auto, kernel = "linear", ranges = list(cost = c(0.01, 0.1, 1, 5, 10, 100)))
summary(tune_1)
##
## Parameter tuning of 'svm':
##
## - sampling method: 10-fold cross validation
##
## - best parameters:
## cost
## 1
##
## - best performance: 0.01019231
##
## - Detailed performance results:
## cost error dispersion
## 1 1e-02 0.07391026 0.02208631
## 2 1e-01 0.04576923 0.02585417
## 3 1e+00 0.01019231 0.01786828
## 4 5e+00 0.01782051 0.02088734
## 5 1e+01 0.02294872 0.01871043
## 6 1e+02 0.03576923 0.03002696
\(\textbf{Response:}\) it can be observed that the best cost seems to be 1.
set.seed(5)
tune_2 <- tune(svm, mpglevel ~ ., data = Auto, kernel = "polynomial", ranges = list(cost = c(0.01, 0.1, 1, 5, 10), degree = c(2, 3, 4, 5)))
summary(tune_2)
##
## Parameter tuning of 'svm':
##
## - sampling method: 10-fold cross validation
##
## - best parameters:
## cost degree
## 10 2
##
## - best performance: 0.5738462
##
## - Detailed performance results:
## cost degree error dispersion
## 1 0.01 2 0.5841026 0.04075521
## 2 0.10 2 0.5841026 0.04075521
## 3 1.00 2 0.5841026 0.04075521
## 4 5.00 2 0.5841026 0.04075521
## 5 10.00 2 0.5738462 0.03762359
## 6 0.01 3 0.5841026 0.04075521
## 7 0.10 3 0.5841026 0.04075521
## 8 1.00 3 0.5841026 0.04075521
## 9 5.00 3 0.5841026 0.04075521
## 10 10.00 3 0.5841026 0.04075521
## 11 0.01 4 0.5841026 0.04075521
## 12 0.10 4 0.5841026 0.04075521
## 13 1.00 4 0.5841026 0.04075521
## 14 5.00 4 0.5841026 0.04075521
## 15 10.00 4 0.5841026 0.04075521
## 16 0.01 5 0.5841026 0.04075521
## 17 0.10 5 0.5841026 0.04075521
## 18 1.00 5 0.5841026 0.04075521
## 19 5.00 5 0.5841026 0.04075521
## 20 10.00 5 0.5841026 0.04075521
\(\textbf{Response:}\) the best performance was given with cost of 10 and degree of 2.
set.seed(5)
tune_2 <- tune(svm, mpglevel ~ ., data = Auto, kernel = "radial", ranges = list(cost = c(0.01, 0.1, 1, 5, 10, 100), gamma = c(0.01, 0.1, 1, 5, 10, 10)))
summary(tune_2)
##
## Parameter tuning of 'svm':
##
## - sampling method: 10-fold cross validation
##
## - best parameters:
## cost gamma
## 100 0.01
##
## - best performance: 0.01012821
##
## - Detailed performance results:
## cost gamma error dispersion
## 1 1e-02 0.01 0.58410256 0.04075521
## 2 1e-01 0.01 0.08416667 0.02962936
## 3 1e+00 0.01 0.07134615 0.02315997
## 4 5e+00 0.01 0.04833333 0.02175755
## 5 1e+01 0.01 0.02282051 0.02193311
## 6 1e+02 0.01 0.01012821 0.01307720
## 7 1e-02 0.10 0.23211538 0.08391233
## 8 1e-01 0.10 0.07647436 0.02060620
## 9 1e+00 0.10 0.05089744 0.02357836
## 10 5e+00 0.10 0.02044872 0.02354784
## 11 1e+01 0.10 0.01782051 0.01724506
## 12 1e+02 0.10 0.02288462 0.01870128
## 13 1e-02 1.00 0.58410256 0.04075521
## 14 1e-01 1.00 0.58410256 0.04075521
## 15 1e+00 1.00 0.06115385 0.02976796
## 16 5e+00 1.00 0.06365385 0.03620146
## 17 1e+01 1.00 0.06365385 0.03620146
## 18 1e+02 1.00 0.06365385 0.03620146
## 19 1e-02 5.00 0.58410256 0.04075521
## 20 1e-01 5.00 0.58410256 0.04075521
## 21 1e+00 5.00 0.53326923 0.05928665
## 22 5e+00 5.00 0.53070513 0.05708644
## 23 1e+01 5.00 0.53070513 0.05708644
## 24 1e+02 5.00 0.53070513 0.05708644
## 25 1e-02 10.00 0.58410256 0.04075521
## 26 1e-01 10.00 0.58410256 0.04075521
## 27 1e+00 10.00 0.55115385 0.04522834
## 28 5e+00 10.00 0.54608974 0.04883070
## 29 1e+01 10.00 0.54608974 0.04883070
## 30 1e+02 10.00 0.54608974 0.04883070
## 31 1e-02 10.00 0.58410256 0.04075521
## 32 1e-01 10.00 0.58410256 0.04075521
## 33 1e+00 10.00 0.55115385 0.04522834
## 34 5e+00 10.00 0.54608974 0.04883070
## 35 1e+01 10.00 0.54608974 0.04883070
## 36 1e+02 10.00 0.54608974 0.04883070
\(\textbf{Response:}\) in the above case, the lowest cross-validation error was given for a gamma of 0.01 and a cost of 100.
Hint: In the lab, we used the plot() function for svm objects only in cases with p = 2. When p > 2, you can use the plot() function to create plots displaying pairs of variables at a time. Essentially, instead of typing plot(svmfit , dat) where svmfit contains your fitted model and dat is a data frame containing your data, you can type plot(svmfit , dat , x1∼x4) in order to plot just the first and fourth variables. However, you must replace x1 and x4 with the correct variable names. To find out more, type ?plot.svm.
lin_svm <- svm(mpglevel ~ ., data = Auto, kernel = "linear", cost = 1)
pol_svm <- svm(mpglevel ~ ., data = Auto, kernel = "polynomial", cost = 10, degree = 2)
rad_svm <- svm(mpglevel ~ ., data = Auto, kernel = "radial", cost = 100, gamma = 0.01)
plot_function = function(fit_param) {
for (n in names(Auto)[!(names(Auto) %in% c("mpg", "mpglevel", "name"))]) {
plot(fit_param, Auto, as.formula(paste("mpg~", n, sep = "")))
}
}
\(\textbf{Linear}\)
plot_function(lin_svm)
\(\textbf{Polynomial}\)
plot_function(pol_svm)
\(\textbf{Radial}\)
plot_function(rad_svm)
\(\textbf{Question 8:}\) This problem involves the OJ data set which is part of the ISLR package.
set.seed(5)
training_sample <- sample(1:nrow(OJ), 800)
training_ds <- OJ[training_sample,]
test_ds <- OJ[-training_sample,]
svm_lin <- svm(Purchase ~ ., data = training_ds, kernel = "linear", cost = 0.01)
summary(svm_lin)
##
## Call:
## svm(formula = Purchase ~ ., data = training_ds, kernel = "linear",
## cost = 0.01)
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: linear
## cost: 0.01
##
## Number of Support Vectors: 441
##
## ( 219 222 )
##
##
## Number of Classes: 2
##
## Levels:
## CH MM
\(\textbf{Response:}\) 441 support vectors were created, with 219 belong to level CH and 222 belong to level MM.
predictions_training_ds <- predict(svm_lin, training_ds)
conf_mat <- table(training_ds$Purchase, predictions_training_ds)
(conf_mat[2, 1] + conf_mat[1, 2]) / sum(conf_mat)
## [1] 0.16625
\(\textbf{Response:}\) the training error rate is 0.16625.
predictions_test_ds <- predict(svm_lin, test_ds)
conf_mat <- table(test_ds$Purchase, predictions_test_ds)
(conf_mat[2, 1] + conf_mat[1, 2]) / sum(conf_mat)
## [1] 0.1666667
\(\textbf{Response:}\) the test error rate is 0.1666667.
set.seed(5)
tune_3 <- tune(svm, Purchase ~ ., data = training_ds, kernel = "linear", ranges = list(cost = 10^seq(-2, 1, by = 0.25)))
summary(tune_3)
##
## Parameter tuning of 'svm':
##
## - sampling method: 10-fold cross validation
##
## - best parameters:
## cost
## 10
##
## - best performance: 0.16625
##
## - Detailed performance results:
## cost error dispersion
## 1 0.01000000 0.17625 0.05382908
## 2 0.01778279 0.17500 0.04750731
## 3 0.03162278 0.17375 0.04945888
## 4 0.05623413 0.17375 0.04767147
## 5 0.10000000 0.17375 0.04348132
## 6 0.17782794 0.17250 0.04199868
## 7 0.31622777 0.17375 0.04730589
## 8 0.56234133 0.17250 0.04923018
## 9 1.00000000 0.16750 0.04456581
## 10 1.77827941 0.16750 0.04495368
## 11 3.16227766 0.17000 0.04758034
## 12 5.62341325 0.17250 0.04241004
## 13 10.00000000 0.16625 0.03955042
\(\textbf{Response:}\) the best performance was given for a cost of 10.
svm_lin_2 <- svm(Purchase ~ ., kernel = "linear", data = training_ds, cost = tune_3$best.parameter$cost)
predictions_training_ds_2 <- predict(svm_lin_2, training_ds)
conf_mat <- table(training_ds$Purchase, predictions_training_ds_2)
(conf_mat[2, 1] + conf_mat[1, 2]) / sum(conf_mat)
## [1] 0.16125
\(\textbf{Response:}\) the training error rate is 0.16125.
predictions_test_ds_2 <- predict(svm_lin_2, test_ds)
conf_mat <- table(test_ds$Purchase, predictions_test_ds_2)
(conf_mat[2, 1] + conf_mat[1, 2]) / sum(conf_mat)
## [1] 0.1740741
\(\textbf{Response:}\) the test error rate is 0.1740741.
svm_rad <- svm(Purchase ~ ., kernel = "radial", data = training_ds)
summary(svm_rad)
##
## Call:
## svm(formula = Purchase ~ ., data = training_ds, kernel = "radial")
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: radial
## cost: 1
##
## Number of Support Vectors: 374
##
## ( 183 191 )
##
##
## Number of Classes: 2
##
## Levels:
## CH MM
\(\textbf{Response:}\) 374 support vectors were created, with 183 belong to level CH and 191 belong to level MM.
predictions_training_ds_3 <- predict(svm_rad, training_ds)
conf_mat <- table(training_ds$Purchase, predictions_training_ds_3)
(conf_mat[2, 1] + conf_mat[1, 2]) / sum(conf_mat)
## [1] 0.15
\(\textbf{Response:}\) the training error rate is 0.15.
predictions_test_ds_3 <- predict(svm_rad, test_ds)
conf_mat <- table(test_ds$Purchase, predictions_test_ds_3)
(conf_mat[2, 1] + conf_mat[1, 2]) / sum(conf_mat)
## [1] 0.1703704
\(\textbf{Response:}\) the test error rate is 0.1703704.
set.seed(5)
tune_4 <- tune(svm, Purchase ~ ., data = training_ds, kernel = "radial", ranges = list(cost = 10^seq(-2, 1, by = 0.25)))
summary(tune_4)
##
## Parameter tuning of 'svm':
##
## - sampling method: 10-fold cross validation
##
## - best parameters:
## cost
## 3.162278
##
## - best performance: 0.16625
##
## - Detailed performance results:
## cost error dispersion
## 1 0.01000000 0.38750 0.04677072
## 2 0.01778279 0.38750 0.04677072
## 3 0.03162278 0.34625 0.06209592
## 4 0.05623413 0.20875 0.04332131
## 5 0.10000000 0.18875 0.04348132
## 6 0.17782794 0.18500 0.04518481
## 7 0.31622777 0.18125 0.03738408
## 8 0.56234133 0.17500 0.03004626
## 9 1.00000000 0.17375 0.02791978
## 10 1.77827941 0.17625 0.03087272
## 11 3.16227766 0.16625 0.03007514
## 12 5.62341325 0.16875 0.03186887
## 13 10.00000000 0.18125 0.03186887
\(\textbf{Response:}\) the best performance was given for a cost of 3.16227766.
svm_rad_2 <- svm(Purchase ~ ., kernel = "radial", data = training_ds, cost = tune_4$best.parameter$cost)
predictions_training_ds_4 <- predict(svm_rad_2, training_ds)
conf_mat <- table(training_ds$Purchase, predictions_training_ds_4)
(conf_mat[2, 1] + conf_mat[1, 2]) / sum(conf_mat)
## [1] 0.14375
\(\textbf{Response:}\) the training error rate is 0.14375.
predictions_test_ds_4 <- predict(svm_rad_2, test_ds)
conf_mat <- table(test_ds$Purchase, predictions_test_ds_4)
(conf_mat[2, 1] + conf_mat[1, 2]) / sum(conf_mat)
## [1] 0.1740741
\(\textbf{Response:}\) the test error rate is 0.1740741.
svm_pol <- svm(Purchase ~ ., kernel = "polynomial", data = training_ds, degree = 2)
summary(svm_pol)
##
## Call:
## svm(formula = Purchase ~ ., data = training_ds, kernel = "polynomial",
## degree = 2)
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: polynomial
## cost: 1
## degree: 2
## coef.0: 0
##
## Number of Support Vectors: 439
##
## ( 216 223 )
##
##
## Number of Classes: 2
##
## Levels:
## CH MM
\(\textbf{Response:}\) 439 support vectors were created, with 216 belong to level CH and 223 belong to level MM.
predictions_training_ds_5 <- predict(svm_pol, training_ds)
conf_mat <- table(training_ds$Purchase, predictions_training_ds_5)
(conf_mat[2, 1] + conf_mat[1, 2]) / sum(conf_mat)
## [1] 0.17625
\(\textbf{Response:}\) the training error rate is 0.17625.
predictions_test_ds_5 <- predict(svm_pol, test_ds)
conf_mat <- table(test_ds$Purchase, predictions_test_ds_5)
(conf_mat[2, 1] + conf_mat[1, 2]) / sum(conf_mat)
## [1] 0.2074074
\(\textbf{Response:}\) the test error rate is 0.2074074.
set.seed(5)
tune_5 <- tune(svm, Purchase ~ ., data = training_ds, kernel = "polynomial", degree = 2, ranges = list(cost = 10^seq(-2, 1, by = 0.25)))
summary(tune_5)
##
## Parameter tuning of 'svm':
##
## - sampling method: 10-fold cross validation
##
## - best parameters:
## cost
## 10
##
## - best performance: 0.175
##
## - Detailed performance results:
## cost error dispersion
## 1 0.01000000 0.36625 0.05205833
## 2 0.01778279 0.35375 0.05744865
## 3 0.03162278 0.34750 0.05645795
## 4 0.05623413 0.32250 0.06061032
## 5 0.10000000 0.30875 0.05070681
## 6 0.17782794 0.25250 0.05857094
## 7 0.31622777 0.20500 0.03689324
## 8 0.56234133 0.20250 0.03809710
## 9 1.00000000 0.20250 0.04199868
## 10 1.77827941 0.19625 0.03682259
## 11 3.16227766 0.19375 0.03596391
## 12 5.62341325 0.18375 0.03387579
## 13 10.00000000 0.17500 0.03280837
\(\textbf{Response:}\) the best performance was given for a cost of 10.
svm_pol_2 <- svm(Purchase ~ ., data = training_ds, kernel = "polynomial", degree = 2, cost = tune_5$best.parameter$cost)
predictions_training_ds_6 <- predict(svm_pol_2, training_ds)
conf_mat <- table(training_ds$Purchase, predictions_training_ds_6)
(conf_mat[2, 1] + conf_mat[1, 2]) / sum(conf_mat)
## [1] 0.14125
\(\textbf{Response:}\) the training error rate is 0.14125.
predictions_test_ds_6 <- predict(svm_pol_2, test_ds)
conf_mat <- table(test_ds$Purchase, predictions_test_ds_6)
(conf_mat[2, 1] + conf_mat[1, 2]) / sum(conf_mat)
## [1] 0.1666667
\(\textbf{Response:}\) the test error rate is 0.1666667.
\(\textbf{Response:}\) Ultimately, it appears that the polynomial kernel with optimal cost gives the minimum error rate on both training and test data for the experiments I conducted. It should also be noted that, interestingly, the original support vector classifier from (b) using cost=0.01 also gave the same test error rate as the polynomial kernel with optimal cost.