p <- seq(0, 1, 0.01)
gini <- p * (1 - p) * 2
entropy <- -(p * log(p) + (1 - p) * log(1 - p))
class.err <- 1 - pmax(p, 1 - p)
matplot(p, cbind(gini, entropy, class.err), col = c("pink", "skyblue", "mediumpurple"), type = "l",
xlab = "p̂ m1", ylab = "Value",
main = "Comparison of Gini Index, Entropy, and Classification Error")
legend("topright", legend = c("Gini Index", "Entropy", "Classification Error"), col = c("pink", "skyblue", "mediumpurple"), lty = 1)
set.seed(123)
index_OJ <- sample(1:nrow(OJ), 800)
train_OJ <- OJ[index_OJ, ]
test_OJ <- OJ[-index_OJ, ]
OJ_tree <- tree(Purchase ~ ., data = train_OJ)
summary(OJ_tree)
##
## Classification tree:
## tree(formula = Purchase ~ ., data = train_OJ)
## Variables actually used in tree construction:
## [1] "LoyalCH" "PriceDiff"
## Number of terminal nodes: 8
## Residual mean deviance: 0.7625 = 603.9 / 792
## Misclassification error rate: 0.165 = 132 / 800
The summary indicates which variables were used in constructing the tree are LoyalCH and PriceDiff. The tree has 8 terminal nodes, the training error rate is 0.165, indicates high performance of this model.
OJ_tree
## node), split, n, deviance, yval, (yprob)
## * denotes terminal node
##
## 1) root 800 1071.00 CH ( 0.60875 0.39125 )
## 2) LoyalCH < 0.5036 350 415.10 MM ( 0.28000 0.72000 )
## 4) LoyalCH < 0.276142 170 131.00 MM ( 0.12941 0.87059 )
## 8) LoyalCH < 0.0356415 56 10.03 MM ( 0.01786 0.98214 ) *
## 9) LoyalCH > 0.0356415 114 108.90 MM ( 0.18421 0.81579 ) *
## 5) LoyalCH > 0.276142 180 245.20 MM ( 0.42222 0.57778 )
## 10) PriceDiff < 0.05 74 74.61 MM ( 0.20270 0.79730 ) *
## 11) PriceDiff > 0.05 106 144.50 CH ( 0.57547 0.42453 ) *
## 3) LoyalCH > 0.5036 450 357.10 CH ( 0.86444 0.13556 )
## 6) PriceDiff < -0.39 27 32.82 MM ( 0.29630 0.70370 ) *
## 7) PriceDiff > -0.39 423 273.70 CH ( 0.90071 0.09929 )
## 14) LoyalCH < 0.705326 130 135.50 CH ( 0.78462 0.21538 )
## 28) PriceDiff < 0.145 43 58.47 CH ( 0.58140 0.41860 ) *
## 29) PriceDiff > 0.145 87 62.07 CH ( 0.88506 0.11494 ) *
## 15) LoyalCH > 0.705326 293 112.50 CH ( 0.95222 0.04778 ) *
Looking at the 8th node, this terminal node identifies a group of customers with low loyalty to the Citrus Hill brand (LoyalCH < 0.0356415) and predicts that they are highly likely to purchase the Minute Maid (MM) brand (probability of approximately 98.2%).
plot(OJ_tree)
text(OJ_tree, pretty = 0)
> According to the plot above, we can see there are 8 nodes. LoyalCH,
PriceDiff are the most important variables.
test_predictions <- predict(OJ_tree, newdata = test_OJ, type = "class")
conf_matrix <- confusionMatrix(test_predictions, test_OJ$Purchase)
print(conf_matrix)
## Confusion Matrix and Statistics
##
## Reference
## Prediction CH MM
## CH 150 34
## MM 16 70
##
## Accuracy : 0.8148
## 95% CI : (0.7633, 0.8593)
## No Information Rate : 0.6148
## P-Value [Acc > NIR] : 9.56e-13
##
## Kappa : 0.596
##
## Mcnemar's Test P-Value : 0.01621
##
## Sensitivity : 0.9036
## Specificity : 0.6731
## Pos Pred Value : 0.8152
## Neg Pred Value : 0.8140
## Prevalence : 0.6148
## Detection Rate : 0.5556
## Detection Prevalence : 0.6815
## Balanced Accuracy : 0.7883
##
## 'Positive' Class : CH
##
test_error_rate <- 1 - conf_matrix$overall['Accuracy']
test_error_rate
## Accuracy
## 0.1851852
The overall accuracy of the model is approximately 81.48% with high true positive rate and low true negative rate. The test error rate, calculated as 1 - Accuracy, is 18.52%
cv_OJ <- cv.tree(OJ_tree)
cv_OJ
## $size
## [1] 8 7 6 5 4 3 2 1
##
## $dev
## [1] 690.2346 692.8691 683.0423 717.4446 717.4446 743.3604 793.1266
## [8] 1073.0916
##
## $k
## [1] -Inf 12.03823 14.92474 25.76707 26.02613 38.91686 50.61655
## [8] 298.68751
##
## $method
## [1] "deviance"
##
## attr(,"class")
## [1] "prune" "tree.sequence"
The tree sizes tested range from 1 to 8 terminal nodes. The corresponding cross-validated error rates range from approximately 707 to 1071.78. The tree size with the lowest cross-validated error rate is 6 nodes with error rate of 707.
plot(cv_OJ$size, cv_OJ$dev, type = "b", xlab = "Tree Size", ylab = "Cross-Validated Classification Error Rate")
According to the plot created in (g), tree size of 6 corresponds to the lowest cross-validated classification error rate, which match the result from question (f).
prune_OJ = prune.tree(OJ_tree, best = 6)
summary(prune_OJ)
##
## Classification tree:
## snip.tree(tree = OJ_tree, nodes = c(4L, 14L))
## Variables actually used in tree construction:
## [1] "LoyalCH" "PriceDiff"
## Number of terminal nodes: 6
## Residual mean deviance: 0.7945 = 630.9 / 794
## Misclassification error rate: 0.165 = 132 / 800
summary(OJ_tree)
##
## Classification tree:
## tree(formula = Purchase ~ ., data = train_OJ)
## Variables actually used in tree construction:
## [1] "LoyalCH" "PriceDiff"
## Number of terminal nodes: 8
## Residual mean deviance: 0.7625 = 603.9 / 792
## Misclassification error rate: 0.165 = 132 / 800
The training error rate for the pruned tree with 6 terminal nodes is 0.165, which is the same as the training error rate for the unpruned tree with 8 terminal nodes. There is no difference in the training error rates between the pruned and unpruned trees.
pruned_pred <- predict(prune_OJ, newdata = test_OJ, type = "class")
pruned_conf <- confusionMatrix(pruned_pred, test_OJ$Purchase)
pruned_test_rate <- 1 - pruned_conf$overall['Accuracy']
pruned_test_rate
## Accuracy
## 0.1851852
Both the pruned and unpruned trees have test error rates of 0.185.