This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.
When you click the Knit button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:
summary(cars)
## speed dist
## Min. : 4.0 Min. : 2.00
## 1st Qu.:12.0 1st Qu.: 26.00
## Median :15.0 Median : 36.00
## Mean :15.4 Mean : 42.98
## 3rd Qu.:19.0 3rd Qu.: 56.00
## Max. :25.0 Max. :120.00
You can also embed plots, for example:
Note that the echo = FALSE parameter was added to the
code chunk to prevent printing of the R code that generated the
plot.
# Load necessary libraries
library(caret)
## Warning: package 'caret' was built under R version 4.3.3
## Loading required package: ggplot2
## Warning: package 'ggplot2' was built under R version 4.3.3
## Loading required package: lattice
## Warning: package 'lattice' was built under R version 4.3.3
library(rattle)
## Warning: package 'rattle' was built under R version 4.3.3
## Loading required package: tibble
## Loading required package: bitops
## Rattle: A free graphical interface for data science with R.
## Version 5.5.1 Copyright (c) 2006-2021 Togaware Pty Ltd.
## Type 'rattle()' to shake, rattle, and roll your data.
library(rpart)
library(rpart.plot)
## Warning: package 'rpart.plot' was built under R version 4.3.3
library(RColorBrewer)
# Function to handle missing values
handle_missing <- function(data) {
data$age[is.na(data$age)] <- mean(data$age, na.rm = TRUE)
return(data)
}
# Function for feature engineering
feature_engineering <- function(data) {
data$FamilySize <- data$sibsp + data$parch
return(data)
}
# Load and preprocess the dataset
url <- "https://goo.gl/At238b"
titanic <- read.csv(url)
titanic <- titanic[, c("survived", "embarked", "age", "sex", "sibsp", "parch", "fare")]
titanic <- handle_missing(titanic)
titanic <- na.omit(titanic)
titanic$survived <- factor(titanic$survived)
titanic$embarked <- factor(titanic$embarked)
titanic$sex <- factor(titanic$sex)
titanic <- feature_engineering(titanic)
# Summary of the data
summary(titanic)
## survived embarked age sex sibsp parch
## 0:808 C:270 Min. : 0.17 female:464 Min. :0.0 Min. :0.0000
## 1:498 Q:123 1st Qu.:22.00 male :842 1st Qu.:0.0 1st Qu.:0.0000
## S:913 Median :29.88 Median :0.0 Median :0.0000
## Mean :29.83 Mean :0.5 Mean :0.3859
## 3rd Qu.:35.00 3rd Qu.:1.0 3rd Qu.:0.0000
## Max. :80.00 Max. :8.0 Max. :9.0000
## fare FamilySize
## Min. : 0.000 Min. : 0.0000
## 1st Qu.: 7.896 1st Qu.: 0.0000
## Median : 14.454 Median : 0.0000
## Mean : 33.224 Mean : 0.8859
## 3rd Qu.: 31.275 3rd Qu.: 1.0000
## Max. :512.329 Max. :10.0000
# Proportion of survived and not survived
prop.table(table(titanic$survived))
##
## 0 1
## 0.618683 0.381317
# Correlation matrix
library(corrplot)
## corrplot 0.92 loaded
numeric_titanic <- titanic[, c("sibsp", "age", "parch", "fare")]
correlation_matrix <- cor(numeric_titanic)
print(correlation_matrix)
## sibsp age parch fare
## sibsp 1.0000000 -0.1896710 0.3732808 0.1610297
## age -0.1896710 1.0000000 -0.1296365 0.1702670
## parch 0.3732808 -0.1296365 1.0000000 0.2223266
## fare 0.1610297 0.1702670 0.2223266 1.0000000
corrplot(correlation_matrix, method="circle")
# 9) Plot survival with other features to see if any correlation exists.
# Bar plot
barplot_table <- table(titanic$survived, titanic$sex)
bp <- barplot(barplot_table, beside = TRUE, legend = TRUE, col = c("red", "blue"),
main = "Survival by Gender", xlab = "Survived", ylab = "Frequency")
text(x = bp, y = barplot_table, label = barplot_table, pos = 3, cex = 0.8, col = "black")
# Box Plot
boxplot(fare ~ survived, data = titanic,
main = "Survival by Fare", xlab = "Survived", ylab = "Fare",
col = c("skyblue", "pink"), names = c("No", "Yes"),
outline = FALSE) # Removes outliers for cleaner visualization
# Density plots
library(ggplot2)
ggplot(titanic, aes(x = fare, fill = survived)) +
geom_density(alpha = 0.5, adjust = 1.5) + # Adjust parameter controls smoothness
labs(title = "Density Plot of Fare by Survival", x = "Fare", y = "Density") +
scale_fill_manual(values = c("skyblue", "pink"), name = "Survived", labels = c("No", "Yes"))
# Histograms
hist(titanic$fare[titanic$survived == "0"], col = "pink",
main = "Histogram of Fare for Non-Survivors", xlab = "Fare", ylab = "Frequency",
xlim = c(0, max(titanic$fare)), ylim = c(0, 200),
breaks = seq(0, max(titanic$fare), by = 10))
abline(v = mean(titanic$fare[titanic$survived == "0"]), col = "blue", lwd = 2)
# Scatter plots
plot(titanic$age, titanic$fare,
col = ifelse(titanic$survived == 1, "skyblue", "pink"),
pch = 16, main = "Scatter Plot of Fare vs Age", xlab = "Age", ylab = "Fare")
legend("topright", legend = c("Survived", "Not Survived"), pch = 16, col = c("skyblue", "pink"))
lines(lowess(titanic$age, titanic$fare), col = "green")
# Split dataset into training and testing
set.seed(1000)
train_index <- sample(1:nrow(titanic), 0.8 * nrow(titanic))
train_data <- titanic[train_index, ]
test_data <- titanic[-train_index, ]
# Train a decision tree model
fit <- rpart(survived ~ sex + age + sibsp + parch + fare + embarked + FamilySize,
data = train_data, method = "class")
# Plot the decision tree
fancyRpartPlot(fit)
png("fancy_decision_tree_plot_train.png", width = 800, height = 600)
fancyRpartPlot(fit)
dev.off()
## png
## 2
# Make predictions on the test set
predictions <- predict(fit, newdata = test_data, type = "class")
results <- data.frame(PassengerSex = test_data$sex, Survived = as.numeric(predictions))
# Examine the tree
printcp(fit)
##
## Classification tree:
## rpart(formula = survived ~ sex + age + sibsp + parch + fare +
## embarked + FamilySize, data = train_data, method = "class")
##
## Variables actually used in tree construction:
## [1] age FamilySize fare sex
##
## Root node error: 390/1044 = 0.37356
##
## n= 1044
##
## CP nsplit rel error xerror xstd
## 1 0.405128 0 1.00000 1.00000 0.040078
## 2 0.021795 1 0.59487 0.59487 0.034443
## 3 0.010256 3 0.55128 0.57179 0.033955
## 4 0.010000 7 0.51026 0.59231 0.034390
summary(fit)
## Call:
## rpart(formula = survived ~ sex + age + sibsp + parch + fare +
## embarked + FamilySize, data = train_data, method = "class")
## n= 1044
##
## CP nsplit rel error xerror xstd
## 1 0.40512821 0 1.0000000 1.0000000 0.04007803
## 2 0.02179487 1 0.5948718 0.5948718 0.03444349
## 3 0.01025641 3 0.5512821 0.5717949 0.03395542
## 4 0.01000000 7 0.5102564 0.5923077 0.03439034
##
## Variable importance
## sex fare FamilySize age parch sibsp embarked
## 51 14 11 10 8 5 1
##
## Node number 1: 1044 observations, complexity param=0.4051282
## predicted class=0 expected loss=0.3735632 P(node) =1
## class counts: 654 390
## probabilities: 0.626 0.374
## left son=2 (674 obs) right son=3 (370 obs)
## Primary splits:
## sex splits as RL, improve=132.46560, (0 missing)
## fare < 15.1729 to the left, improve= 44.56075, (0 missing)
## FamilySize < 0.5 to the left, improve= 19.85816, (0 missing)
## embarked splits as RLL, improve= 17.31542, (0 missing)
## parch < 0.5 to the left, improve= 15.92044, (0 missing)
## Surrogate splits:
## parch < 0.5 to the left, agree=0.684, adj=0.108, (0 split)
## fare < 77.6229 to the left, agree=0.673, adj=0.078, (0 split)
## FamilySize < 0.5 to the left, agree=0.668, adj=0.062, (0 split)
## age < 18.25 to the right, agree=0.654, adj=0.024, (0 split)
##
## Node number 2: 674 observations, complexity param=0.01025641
## predicted class=0 expected loss=0.1869436 P(node) =0.6455939
## class counts: 548 126
## probabilities: 0.813 0.187
## left son=4 (479 obs) right son=5 (195 obs)
## Primary splits:
## fare < 26.26875 to the left, improve=10.950570, (0 missing)
## age < 9.5 to the right, improve=10.491300, (0 missing)
## parch < 0.5 to the left, improve= 3.753284, (0 missing)
## embarked splits as RLL, improve= 3.202181, (0 missing)
## FamilySize < 0.5 to the left, improve= 2.261516, (0 missing)
## Surrogate splits:
## FamilySize < 2.5 to the left, agree=0.757, adj=0.159, (0 split)
## parch < 0.5 to the left, agree=0.754, adj=0.149, (0 split)
## sibsp < 3.5 to the left, agree=0.743, adj=0.113, (0 split)
## age < 44.5 to the left, agree=0.740, adj=0.103, (0 split)
##
## Node number 3: 370 observations, complexity param=0.02179487
## predicted class=1 expected loss=0.2864865 P(node) =0.3544061
## class counts: 106 264
## probabilities: 0.286 0.714
## left son=6 (266 obs) right son=7 (104 obs)
## Primary splits:
## fare < 48.2021 to the left, improve=13.898900, (0 missing)
## FamilySize < 3.5 to the right, improve=13.398030, (0 missing)
## embarked splits as RLL, improve= 8.493113, (0 missing)
## sibsp < 2.5 to the right, improve= 7.311364, (0 missing)
## parch < 3.5 to the right, improve= 5.420420, (0 missing)
## Surrogate splits:
## age < 46 to the left, agree=0.741, adj=0.077, (0 split)
## embarked splits as RLL, agree=0.732, adj=0.048, (0 split)
## FamilySize < 8.5 to the left, agree=0.730, adj=0.038, (0 split)
## sibsp < 6.5 to the left, agree=0.727, adj=0.029, (0 split)
##
## Node number 4: 479 observations, complexity param=0.01025641
## predicted class=0 expected loss=0.1294363 P(node) =0.4588123
## class counts: 417 62
## probabilities: 0.871 0.129
## left son=8 (463 obs) right son=9 (16 obs)
## Primary splits:
## age < 14.5 to the right, improve=10.3103200, (0 missing)
## parch < 0.5 to the left, improve= 3.5301990, (0 missing)
## embarked splits as RLL, improve= 1.0438490, (0 missing)
## FamilySize < 1.5 to the left, improve= 0.7275991, (0 missing)
## fare < 7.9104 to the left, improve= 0.3909300, (0 missing)
##
## Node number 5: 195 observations, complexity param=0.01025641
## predicted class=0 expected loss=0.3282051 P(node) =0.1867816
## class counts: 131 64
## probabilities: 0.672 0.328
## left son=10 (29 obs) right son=11 (166 obs)
## Primary splits:
## FamilySize < 4.5 to the right, improve=5.877986, (0 missing)
## sibsp < 2.5 to the right, improve=4.494130, (0 missing)
## age < 53.5 to the right, improve=2.260211, (0 missing)
## parch < 2.5 to the right, improve=1.564212, (0 missing)
## fare < 158.2084 to the right, improve=1.533459, (0 missing)
## Surrogate splits:
## sibsp < 2.5 to the right, agree=0.974, adj=0.828, (0 split)
## age < 15.25 to the left, agree=0.892, adj=0.276, (0 split)
## parch < 3.5 to the right, agree=0.877, adj=0.172, (0 split)
## embarked splits as RLR, agree=0.872, adj=0.138, (0 split)
## fare < 262.6875 to the right, agree=0.862, adj=0.069, (0 split)
##
## Node number 6: 266 observations, complexity param=0.02179487
## predicted class=1 expected loss=0.3721805 P(node) =0.2547893
## class counts: 99 167
## probabilities: 0.372 0.628
## left son=12 (27 obs) right son=13 (239 obs)
## Primary splits:
## FamilySize < 3.5 to the right, improve=11.775190, (0 missing)
## sibsp < 2.5 to the right, improve= 4.860271, (0 missing)
## fare < 10.48125 to the left, improve= 4.612900, (0 missing)
## parch < 3.5 to the right, improve= 4.170674, (0 missing)
## embarked splits as RLL, improve= 2.721452, (0 missing)
## Surrogate splits:
## sibsp < 2.5 to the right, agree=0.944, adj=0.444, (0 split)
## parch < 2.5 to the right, agree=0.932, adj=0.333, (0 split)
## fare < 44.2396 to the right, agree=0.910, adj=0.111, (0 split)
##
## Node number 7: 104 observations
## predicted class=1 expected loss=0.06730769 P(node) =0.09961686
## class counts: 7 97
## probabilities: 0.067 0.933
##
## Node number 8: 463 observations
## predicted class=0 expected loss=0.1101512 P(node) =0.4434866
## class counts: 412 51
## probabilities: 0.890 0.110
##
## Node number 9: 16 observations
## predicted class=1 expected loss=0.3125 P(node) =0.01532567
## class counts: 5 11
## probabilities: 0.313 0.688
##
## Node number 10: 29 observations
## predicted class=0 expected loss=0.03448276 P(node) =0.02777778
## class counts: 28 1
## probabilities: 0.966 0.034
##
## Node number 11: 166 observations, complexity param=0.01025641
## predicted class=0 expected loss=0.3795181 P(node) =0.1590038
## class counts: 103 63
## probabilities: 0.620 0.380
## left son=22 (156 obs) right son=23 (10 obs)
## Primary splits:
## age < 14.5 to the right, improve=8.19354300, (0 missing)
## fare < 135.0666 to the right, improve=1.71267800, (0 missing)
## parch < 1.5 to the left, improve=1.65012700, (0 missing)
## FamilySize < 1.5 to the left, improve=0.68587130, (0 missing)
## embarked splits as LLR, improve=0.06862297, (0 missing)
##
## Node number 12: 27 observations
## predicted class=0 expected loss=0.1851852 P(node) =0.02586207
## class counts: 22 5
## probabilities: 0.815 0.185
##
## Node number 13: 239 observations
## predicted class=1 expected loss=0.3221757 P(node) =0.2289272
## class counts: 77 162
## probabilities: 0.322 0.678
##
## Node number 22: 156 observations
## predicted class=0 expected loss=0.3397436 P(node) =0.1494253
## class counts: 103 53
## probabilities: 0.660 0.340
##
## Node number 23: 10 observations
## predicted class=1 expected loss=0 P(node) =0.009578544
## class counts: 0 10
## probabilities: 0.000 1.000
split_var <- fit$variable[1]
split_var
## sex
## 132.4656
# Assess model performance
confusionMatrix(predictions, test_data$survived)
## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 131 28
## 1 23 80
##
## Accuracy : 0.8053
## 95% CI : (0.7521, 0.8515)
## No Information Rate : 0.5878
## P-Value [Acc > NIR] : 5.431e-14
##
## Kappa : 0.5955
##
## Mcnemar's Test P-Value : 0.5754
##
## Sensitivity : 0.8506
## Specificity : 0.7407
## Pos Pred Value : 0.8239
## Neg Pred Value : 0.7767
## Prevalence : 0.5878
## Detection Rate : 0.5000
## Detection Prevalence : 0.6069
## Balanced Accuracy : 0.7957
##
## 'Positive' Class : 0
##
# Optionally, if you need to train and assess with fixed indices:
trainFixedIndex <- titanic[1:1046, ]
testFixedIndex <- titanic[1047:nrow(titanic), ]
fitFixed <- rpart(survived ~ sex + age + sibsp + parch + fare + embarked,
data = trainFixedIndex, method = "class")
fancyRpartPlot(fitFixed)
png("fancy_decision_tree_plot_fixed_index.png", width = 800, height = 600)
fancyRpartPlot(fitFixed)
dev.off()
## png
## 2
predictionsFixed <- predict(fitFixed, newdata = testFixedIndex, type = "class")
resultsFixed <- data.frame(PassengerSex = testFixedIndex$sex, Survived = as.numeric(predictionsFixed))
printcp(fitFixed)
##
## Classification tree:
## rpart(formula = survived ~ sex + age + sibsp + parch + fare +
## embarked, data = trainFixedIndex, method = "class")
##
## Variables actually used in tree construction:
## [1] age sex
##
## Root node error: 444/1046 = 0.42447
##
## n= 1046
##
## CP nsplit rel error xerror xstd
## 1 0.490991 0 1.00000 1.00000 0.036003
## 2 0.033784 1 0.50901 0.50901 0.029979
## 3 0.010000 2 0.47523 0.47973 0.029333
summary(fitFixed)
## Call:
## rpart(formula = survived ~ sex + age + sibsp + parch + fare +
## embarked, data = trainFixedIndex, method = "class")
## n= 1046
##
## CP nsplit rel error xerror xstd
## 1 0.49099099 0 1.0000000 1.0000000 0.03600318
## 2 0.03378378 1 0.5090090 0.5090090 0.02997867
## 3 0.01000000 2 0.4752252 0.4797297 0.02933347
##
## Variable importance
## sex age parch fare sibsp embarked
## 74 9 8 6 2 1
##
## Node number 1: 1046 observations, complexity param=0.490991
## predicted class=0 expected loss=0.4244742 P(node) =1
## class counts: 602 444
## probabilities: 0.576 0.424
## left son=2 (656 obs) right son=3 (390 obs)
## Primary splits:
## sex splits as RL, improve=156.75120, (0 missing)
## fare < 15.6646 to the left, improve= 46.51541, (0 missing)
## parch < 0.5 to the left, improve= 22.54089, (0 missing)
## age < 8.5 to the right, improve= 16.42941, (0 missing)
## embarked splits as RLL, improve= 15.13880, (0 missing)
## Surrogate splits:
## parch < 0.5 to the left, agree=0.666, adj=0.105, (0 split)
## fare < 77.6229 to the left, agree=0.660, adj=0.087, (0 split)
## sibsp < 2.5 to the left, agree=0.632, adj=0.013, (0 split)
## age < 16.5 to the right, agree=0.630, adj=0.008, (0 split)
## embarked splits as LRL, agree=0.630, adj=0.008, (0 split)
##
## Node number 2: 656 observations, complexity param=0.03378378
## predicted class=0 expected loss=0.2134146 P(node) =0.6271511
## class counts: 516 140
## probabilities: 0.787 0.213
## left son=4 (627 obs) right son=5 (29 obs)
## Primary splits:
## age < 10 to the right, improve=18.037890, (0 missing)
## fare < 26.26875 to the left, improve= 9.603202, (0 missing)
## parch < 0.5 to the left, improve= 6.329854, (0 missing)
## embarked splits as RLL, improve= 4.185190, (0 missing)
## sibsp < 0.5 to the left, improve= 0.946299, (0 missing)
## Surrogate splits:
## sibsp < 3.5 to the left, agree=0.96, adj=0.103, (0 split)
##
## Node number 3: 390 observations
## predicted class=1 expected loss=0.2205128 P(node) =0.3728489
## class counts: 86 304
## probabilities: 0.221 0.779
##
## Node number 4: 627 observations
## predicted class=0 expected loss=0.1881978 P(node) =0.5994264
## class counts: 509 118
## probabilities: 0.812 0.188
##
## Node number 5: 29 observations
## predicted class=1 expected loss=0.2413793 P(node) =0.02772467
## class counts: 7 22
## probabilities: 0.241 0.759
split_var_fixed <- fitFixed$variable[1]
split_var_fixed
## sex
## 156.7512