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(42)
x1 <- runif (500) - 0.5
x2 <- runif (500) - 0.5
y <- 1 * (x1^2 - x2^2 > 0)
gen <- data.frame(x1 = x1, x2 = x2, y = as.factor(y))
ggplot(gen, aes(x = x1, y = x2, color = y)) +
geom_point(alpha = 0.5) +
labs(title = "Plot of Observations with Hyperbolic Decision Boundary",
x = "X1", y = "X2") +
scale_color_manual(values = c("red", "blue")) +
theme_minimal()
model.fit <- glm(y ~ x1 + x2, family = binomial, data = gen)
summary(model.fit)
##
## Call:
## glm(formula = y ~ x1 + x2, family = binomial, data = gen)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 0.09978 0.08976 1.112 0.266
## x1 -0.17659 0.30658 -0.576 0.565
## x2 -0.20067 0.30978 -0.648 0.517
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 691.79 on 499 degrees of freedom
## Residual deviance: 691.08 on 497 degrees of freedom
## AIC: 697.08
##
## Number of Fisher Scoring iterations: 3
probabilities <- predict(model.fit, gen, type = "response")
predicted_labels <- ifelse(probabilities > 0.5, 1, 0)
gen2 <- gen
gen2$predicted_y <- as.factor(predicted_labels)
ggplot(gen2, aes(x = x1, y = x2, color = predicted_y)) +
geom_point(alpha = 0.5) +
labs(title = "Logistic Regression Predicted Classes",
x = "X1", y = "X2") +
scale_color_manual(values = c("red", "blue")) +
theme_minimal()
model.nl.fit <- glm(y ~ poly(x1,2) + poly(x2,2), family = binomial, data = gen, control = glm.control(maxit = 50))
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
summary(model.nl.fit)
##
## Call:
## glm(formula = y ~ poly(x1, 2) + poly(x2, 2), family = binomial,
## data = gen, control = glm.control(maxit = 50))
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 423.6 105671.4 0.004 0.997
## poly(x1, 2)1 -2733.1 5162607.5 -0.001 1.000
## poly(x1, 2)2 265100.7 47298657.0 0.006 0.996
## poly(x2, 2)1 6642.2 5192528.8 0.001 0.999
## poly(x2, 2)2 -256275.0 45727067.7 -0.006 0.996
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 6.9179e+02 on 499 degrees of freedom
## Residual deviance: 1.1354e-08 on 495 degrees of freedom
## AIC: 10
##
## Number of Fisher Scoring iterations: 45
probabilities <- predict(model.nl.fit, type = "response")
predicted_labels <- ifelse(probabilities > 0.5, 1, 0)
gen3 <- gen
gen3$predicted_labels <- as.factor(predicted_labels)
ggplot(gen3, aes(x = x1, y = x2, color = predicted_labels)) +
geom_point(alpha = 0.5) +
labs(title = "Predicted Class Labels with Non-linear Decision Boundary",
x = "X1", y = "X2") +
scale_color_manual(values = c("red", "blue")) +
theme_minimal()
svc.fit <- svm(y ~ x1 + x2, data = gen, type = "C-classification", kernel = "linear")
predicted_labels_svc <- predict(svc.fit, data.frame(x1, x2))
gen4 <- gen
gen4$predicted_labels_svc <- as.factor(predicted_labels_svc)
ggplot(gen4, aes(x = x1, y = x2, color = predicted_labels_svc)) +
geom_point(alpha = 0.5) +
labs(title = "SVC Predicted Class Labels",
x = "X1", y = "X2") +
scale_color_manual(values = c("red", "blue")) +
theme_minimal()
svmradial.fit <- svm(y ~ x1 + x2, data = data.frame(x1, x2, y), type = "C-classification", kernel = "radial")
predicted_labels_rbf <- predict(svmradial.fit, data.frame(x1, x2))
gen5 <- gen
gen5$predicted_labels_rbf <- as.factor(predicted_labels_rbf)
ggplot(gen5, aes(x = x1, y = x2, color = predicted_labels_rbf)) +
geom_point(alpha = 0.5) +
labs(title = "SVM with RBF Kernel Predicted Labels",
x = "X1", y = "X2") +
scale_color_manual(values = c("red", "blue")) +
theme_minimal()
From the results, SVM with non-linear kernal (Radial) and logistic regression with non-linear functions are very effective in discovering non-linear decision boundaries. The other models tested (logistic regression, SVC) were not effective in discovering non-linear boundaries.
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.
auto.df = Auto
auto.median <- median(Auto$mpg, na.rm = TRUE)
auto.df$mpgcat <- ifelse(auto.df$mpg > auto.median, 1, 0)
head(auto.df)
## mpg cylinders displacement horsepower weight acceleration year origin
## 1 18 8 307 130 3504 12.0 70 1
## 2 15 8 350 165 3693 11.5 70 1
## 3 18 8 318 150 3436 11.0 70 1
## 4 16 8 304 150 3433 12.0 70 1
## 5 17 8 302 140 3449 10.5 70 1
## 6 15 8 429 198 4341 10.0 70 1
## name mpgcat
## 1 chevrolet chevelle malibu 0
## 2 buick skylark 320 0
## 3 plymouth satellite 0
## 4 amc rebel sst 0
## 5 ford torino 0
## 6 ford galaxie 500 0
cgrid = data.frame(cost=seq(0.05, 100, length.out = 15))
linearsvm = tune(svm, mpgcat~., data=auto.df, kernel='linear', ranges=cgrid)
linearsvm
##
## Parameter tuning of 'svm':
##
## - sampling method: 10-fold cross validation
##
## - best parameters:
## cost
## 0.05
##
## - best performance: 0.08025343
plot(linearsvm$performance[,c(1,2)], type='l')
Cost at 0.05 had the lowest error of 0.0795.
set.seed(42)
params = data.frame(cost = seq(0.05, 100, length.out = 5), degree = seq(1, 100, length.out = 5))
polysvm = tune(svm, mpgcat~., data=auto.df, ranges=params, kernel='polynomial')
polysvm
##
## Parameter tuning of 'svm':
##
## - sampling method: 10-fold cross validation
##
## - best parameters:
## cost degree
## 100 1
##
## - best performance: 0.07709117
params = data.frame(cost = seq(0.05, 100, length.out = 5), gamma = seq(0.1, 100, length.out = 5))
radialsvm = tune(svm, mpgcat~., data=auto.df, ranges=params, kernel='radial')
radialsvm
##
## Parameter tuning of 'svm':
##
## - sampling method: 10-fold cross validation
##
## - best parameters:
## cost gamma
## 25.0375 0.1
##
## - best performance: 0.03838624
Cost at 100, degree 1 had the lowest error of 0.0771 for polynomial kernel. Cost at 25.0375, gamma 0.1 had the lowest error of 0.0384 for radial kernel. SVM radial had better results.
plot(linearsvm$performance[,c(1,2)], type='l')
This problem involves the OJ data set which is part of the ISLR2 package.
data("OJ")
set.seed(42)
train_indices <- sample(1:nrow(OJ), 800)
train_set <- OJ[train_indices, ]
test_set <- OJ[-train_indices, ]
svm.fit <- svm(Purchase ~ ., data = train_set, kernel = "linear", cost = 0.01)
summary(svm.fit)
##
## Call:
## svm(formula = Purchase ~ ., data = train_set, kernel = "linear",
## cost = 0.01)
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: linear
## cost: 0.01
##
## Number of Support Vectors: 432
##
## ( 215 217 )
##
##
## Number of Classes: 2
##
## Levels:
## CH MM
SVM-type set to c-classification, linear kernel, and cost 0.01. Relatively high number of support vectors (432/800)
train_error_rate <- mean(predict(svm.fit, train_set) != train_set$Purchase)
print(paste("Training Error Rate:", train_error_rate))
## [1] "Training Error Rate: 0.17125"
test_error_rate <- mean(predict(svm.fit, test_set) != test_set$Purchase)
print(paste("Test Error Rate:", test_error_rate))
## [1] "Test Error Rate: 0.162962962962963"
cparams <- 10^seq(-2, 1, length.out = 10)
tune_results <- tune(
svm,
train.x = Purchase ~ .,
data = train_set,
kernel = "linear",
ranges = list(cost = cparams),
scale = FALSE,
)
summary(tune_results)
##
## Parameter tuning of 'svm':
##
## - sampling method: 10-fold cross validation
##
## - best parameters:
## cost
## 0.1
##
## - best performance: 0.1775
##
## - Detailed performance results:
## cost error dispersion
## 1 0.01000000 0.26125 0.04767147
## 2 0.02154435 0.20375 0.03488573
## 3 0.04641589 0.18125 0.03644345
## 4 0.10000000 0.17750 0.04440971
## 5 0.21544347 0.17750 0.03622844
## 6 0.46415888 0.17750 0.04116363
## 7 1.00000000 0.18375 0.04450733
## 8 2.15443469 0.18500 0.05062114
## 9 4.64158883 0.18250 0.04257347
## 10 10.00000000 0.17875 0.04489571
Cost at 0.1, had the lowest error of 0.1775.
svm.fit2 <- svm(Purchase ~ ., data = train_set, kernel = "linear", cost = 0.1)
train_error_rate <- mean(predict(svm.fit2, train_set) != train_set$Purchase)
print(paste("Training Error Rate:", train_error_rate))
## [1] "Training Error Rate: 0.17125"
test_error_rate <- mean(predict(svm.fit2, test_set) != test_set$Purchase)
print(paste("Test Error Rate:", test_error_rate))
## [1] "Test Error Rate: 0.162962962962963"
svm.rad.fit <- svm(Purchase ~ ., data = train_set, kernel = "radial", cost = 0.01)
summary(svm.rad.fit)
##
## Call:
## svm(formula = Purchase ~ ., data = train_set, kernel = "radial",
## cost = 0.01)
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: radial
## cost: 0.01
##
## Number of Support Vectors: 621
##
## ( 308 313 )
##
##
## Number of Classes: 2
##
## Levels:
## CH MM
train_error_rate <- mean(predict(svm.rad.fit, train_set) != train_set$Purchase)
print(paste("Training Error Rate:", train_error_rate))
## [1] "Training Error Rate: 0.385"
test_error_rate <- mean(predict(svm.rad.fit, test_set) != test_set$Purchase)
print(paste("Test Error Rate:", test_error_rate))
## [1] "Test Error Rate: 0.403703703703704"
cparams <- 10^seq(-2, 1, length.out = 10)
tune_results <- tune(
svm,
train.x = Purchase ~ .,
data = train_set,
kernel = "radial",
ranges = list(cost = cparams),
scale = FALSE,
)
summary(tune_results)
##
## Parameter tuning of 'svm':
##
## - sampling method: 10-fold cross validation
##
## - best parameters:
## cost
## 4.641589
##
## - best performance: 0.20625
##
## - Detailed performance results:
## cost error dispersion
## 1 0.01000000 0.38500 0.06942222
## 2 0.02154435 0.38500 0.06942222
## 3 0.04641589 0.38500 0.06942222
## 4 0.10000000 0.36500 0.05945353
## 5 0.21544347 0.33500 0.05521423
## 6 0.46415888 0.31250 0.04124790
## 7 1.00000000 0.26500 0.03944053
## 8 2.15443469 0.22500 0.06666667
## 9 4.64158883 0.20625 0.06270799
## 10 10.00000000 0.20875 0.06068189
svm.rad.fit2 <- svm(Purchase ~ ., data = train_set, kernel = "radial", cost = 4.6416)
train_error_rate <- mean(predict(svm.rad.fit2, train_set) != train_set$Purchase)
print(paste("Training Error Rate:", train_error_rate))
## [1] "Training Error Rate: 0.15"
test_error_rate <- mean(predict(svm.rad.fit2, test_set) != test_set$Purchase)
print(paste("Test Error Rate:", test_error_rate))
## [1] "Test Error Rate: 0.159259259259259"
svm.poly.fit <- svm(Purchase ~ ., data = train_set, kernel = "polynomial", cost = 0.01, degree = 2)
summary(svm.poly.fit)
##
## Call:
## svm(formula = Purchase ~ ., data = train_set, kernel = "polynomial",
## cost = 0.01, degree = 2)
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: polynomial
## cost: 0.01
## degree: 2
## coef.0: 0
##
## Number of Support Vectors: 621
##
## ( 308 313 )
##
##
## Number of Classes: 2
##
## Levels:
## CH MM
train_error_rate <- mean(predict(svm.poly.fit, train_set) != train_set$Purchase)
print(paste("Training Error Rate:", train_error_rate))
## [1] "Training Error Rate: 0.385"
test_error_rate <- mean(predict(svm.poly.fit, test_set) != test_set$Purchase)
print(paste("Test Error Rate:", test_error_rate))
## [1] "Test Error Rate: 0.403703703703704"
cparams <- 10^seq(-2, 1, length.out = 10)
tune_results <- tune(
svm,
train.x = Purchase ~ .,
data = train_set,
kernel = "polynomial",
degree = 2,
ranges = list(cost = cparams),
scale = FALSE,
)
summary(tune_results)
##
## Parameter tuning of 'svm':
##
## - sampling method: 10-fold cross validation
##
## - best parameters:
## cost
## 0.01
##
## - best performance: 0.17875
##
## - Detailed performance results:
## cost error dispersion
## 1 0.01000000 0.17875 0.04752558
## 2 0.02154435 0.18625 0.05050096
## 3 0.04641589 0.18125 0.04796194
## 4 0.10000000 0.17875 0.05205833
## 5 0.21544347 0.18875 0.07464034
## 6 0.46415888 0.18625 0.06192794
## 7 1.00000000 0.20500 0.10739982
## 8 2.15443469 0.19625 0.05560588
## 9 4.64158883 0.20500 0.09650130
## 10 10.00000000 0.18500 0.04779877
best_model_poly <- tune_results$best.model
print(paste("Optimal Cost:", best_model_poly$cost))
## [1] "Optimal Cost: 0.01"
svm.poly.fit2 <- svm(Purchase ~ ., data = train_set, kernel = "polynomial", cost = best_model_poly$cost)
train_error_rate <- mean(predict(svm.poly.fit2, train_set) != train_set$Purchase)
print(paste("Training Error Rate:", train_error_rate))
## [1] "Training Error Rate: 0.36625"
test_error_rate <- mean(predict(svm.poly.fit2, test_set) != test_set$Purchase)
print(paste("Test Error Rate:", test_error_rate))
## [1] "Test Error Rate: 0.377777777777778"
Out of all the results, tuned SVM radial kernel had the lowest error rate of 0.1593. This was closely followed by SVM linear, then SVM polynomial.