options(repos = c(CRAN = "https://cloud.r-project.org"))Statistical Models Exercise Answers
Institute of Technology of Cambodia — I4STM
SECTION 1: DATA VISUALIZATION
Task 1: Galton Heredity
install.packages("UsingR")Warning: unable to access index for repository https://cloud.r-project.org/src/contrib:
cannot open URL 'https://cloud.r-project.org/src/contrib/PACKAGES'
Warning: package 'UsingR' is not available for this version of R
A version of this package for your version of R might be available elsewhere,
see the ideas at
https://cran.r-project.org/doc/manuals/r-patched/R-admin.html#Installing-packages
Warning: unable to access index for repository https://cloud.r-project.org/bin/macosx/big-sur-x86_64/contrib/4.4:
cannot open URL 'https://cloud.r-project.org/bin/macosx/big-sur-x86_64/contrib/4.4/PACKAGES'
library(UsingR)Loading required package: MASS
Loading required package: HistData
Loading required package: Hmisc
Attaching package: 'Hmisc'
The following objects are masked from 'package:base':
format.pval, units
data(Galton)
head(Galton) parent child
1 70.5 61.7
2 68.5 61.7
3 65.5 61.7
4 64.5 61.7
5 64.0 61.7
6 67.5 62.2
# Load required libraries
library(ggplot2)
library(dplyr)
Attaching package: 'dplyr'
The following objects are masked from 'package:Hmisc':
src, summarize
The following object is masked from 'package:MASS':
select
The following objects are masked from 'package:stats':
filter, lag
The following objects are masked from 'package:base':
intersect, setdiff, setequal, union
(a). Contingency table between children and parents’ height
table_Galton <- table(round(Galton$parent, 1), round(Galton$child, 1))
table_Galton
61.7 62.2 63.2 64.2 65.2 66.2 67.2 68.2 69.2 70.2 71.2 72.2 73.2 73.7
64 1 0 2 4 1 2 2 1 1 0 0 0 0 0
64.5 1 1 4 4 1 5 5 0 2 0 0 0 0 0
65.5 1 0 9 5 7 11 11 7 7 5 2 1 0 0
66.5 0 3 3 5 2 17 17 14 13 4 0 0 0 0
67.5 0 3 5 14 15 36 38 28 38 19 11 4 0 0
68.5 1 0 7 11 16 25 31 34 48 21 18 4 3 0
69.5 0 0 1 16 4 17 27 20 33 25 20 11 4 5
70.5 1 0 1 0 1 1 3 12 18 14 7 4 3 3
71.5 0 0 0 0 1 3 4 3 5 10 4 9 2 2
72.5 0 0 0 0 0 0 0 1 2 1 2 7 2 4
73 0 0 0 0 0 0 0 0 0 0 0 1 3 0
(b) Scatter plot with regression line
plot(Galton$parent, Galton$child,
main = "Scatter plot of Children Height vs Parents Average Height",
xlab = "Average Height of Parents (inch)",
ylab = "Height of Children (inch)",
pch = 19, col = "skyblue")
abline(lm(child ~ parent, data = Galton), col = "red", lwd = 2)Task 2: Munich Rent Index (1999)
install.packages("gamlss.data")Warning: unable to access index for repository https://cloud.r-project.org/src/contrib:
cannot open URL 'https://cloud.r-project.org/src/contrib/PACKAGES'
Warning: package 'gamlss.data' is not available for this version of R
A version of this package for your version of R might be available elsewhere,
see the ideas at
https://cran.r-project.org/doc/manuals/r-patched/R-admin.html#Installing-packages
Warning: unable to access index for repository https://cloud.r-project.org/bin/macosx/big-sur-x86_64/contrib/4.4:
cannot open URL 'https://cloud.r-project.org/bin/macosx/big-sur-x86_64/contrib/4.4/PACKAGES'
library(gamlss.data)
Attaching package: 'gamlss.data'
The following object is masked from 'package:UsingR':
grip
The following object is masked from 'package:datasets':
sleep
library(dplyr)
data(rent99)
rent99 <- data.frame(rent99)
head(rent99) rent rentsqm area yearc location bath kitchen cheating district
1 109.9487 4.228797 26 1918 2 0 0 0 916
2 243.2820 8.688646 28 1918 2 0 0 1 813
3 261.6410 8.721369 30 1918 1 0 0 1 611
4 106.4103 3.547009 30 1918 2 0 0 0 2025
5 133.3846 4.446154 30 1918 2 0 0 1 561
6 339.0256 11.300851 30 1918 2 0 0 1 541
(a) Histograms and Kernel Density Plots
par(mfrow=c(2,2))
hist(rent99$rent, prob=TRUE, main="Net Rent", xlab="Net rent (€)", col="lightblue")
lines(density(rent99$rent), col="red", lwd=2)
hist(rent99$rentsqm, prob=TRUE, main="Net Rent per sqm", xlab="€", col="lightgreen")
lines(density(rent99$rentsqm), col="red", lwd=2)
hist(rent99$area, prob=TRUE, main="Area (sqm)", xlab="sqm", col="lightyellow")
lines(density(rent99$area), col="red", lwd=2)
hist(rent99$yearc, prob=TRUE, main="Year of Construction", xlab="Year", col="lightgray")
lines(density(rent99$yearc), col="red", lwd=2)(b) Scatter Plots
par(mfrow=c(2,2))
plot(rent99$area, rent99$rent, main="Net Rent vs Area", xlab="Area (sqm)", ylab="Net Rent (€)", pch=19, col="blue")
plot(rent99$area, rent99$rentsqm, main="Rent per sqm vs Area", xlab="Area (sqm)", ylab="Rent/sqm (€)", pch=19, col="darkgreen")
plot(rent99$yearc, rent99$rent, main="Net Rent vs Year", xlab="Year", ylab="Net Rent (€)", pch=19, col="purple")
plot(rent99$yearc, rent99$rentsqm, main="Rent per sqm vs Year", xlab="Year", ylab="Rent/sqm (€)", pch=19, col="orange")(c) Average and SD Plot
rent_summary <- rent99 %>%
group_by(area) %>%
summarise(avg_rent = mean(rent), sd_rent = sd(rent),
avg_rentsqm = mean(rentsqm), sd_rentsqm = sd(rentsqm))
plot(rent_summary$area, rent_summary$avg_rent, type="l",
main="Average Net Rent vs Area", xlab="Area", ylab="Average Rent")
lines(rent_summary$area, rent_summary$avg_rent + rent_summary$sd_rent, lty=2)
lines(rent_summary$area, rent_summary$avg_rent - rent_summary$sd_rent, lty=2)(d) Boxplot and Density by Location
boxplot(rentsqm ~ location, data=rent99,
main="Net Rent per sqm by Location",
xlab="Location", ylab="Rent per sqm (€)", col=c("skyblue","lightgreen","lightpink"))plot(density(rent99$rentsqm), main="Kernel Density: Net Rent per sqm", col="red", lwd=2)Task 3: Fuel Consumption
install.packages("alr4")Warning: unable to access index for repository https://cloud.r-project.org/src/contrib:
cannot open URL 'https://cloud.r-project.org/src/contrib/PACKAGES'
Warning: package 'alr4' is not available for this version of R
A version of this package for your version of R might be available elsewhere,
see the ideas at
https://cran.r-project.org/doc/manuals/r-patched/R-admin.html#Installing-packages
Warning: unable to access index for repository https://cloud.r-project.org/bin/macosx/big-sur-x86_64/contrib/4.4:
cannot open URL 'https://cloud.r-project.org/bin/macosx/big-sur-x86_64/contrib/4.4/PACKAGES'
library(alr4)Loading required package: car
Loading required package: carData
Attaching package: 'car'
The following object is masked from 'package:dplyr':
recode
Loading required package: effects
lattice theme set by effectsTheme()
See ?effectsTheme for details.
Attaching package: 'alr4'
The following objects are masked from 'package:UsingR':
florida, rat, twins
data(fuel2001)
fuel2001 <- data.frame(fuel2001)(a) Create new variables
fuel2001$Fuel <- 1000 * fuel2001$FuelC / fuel2001$Pop
fuel2001$Dlic <- 1000 * fuel2001$Drivers / fuel2001$Pop
fuel2001$logMiles <- log(fuel2001$Miles)(b) Summary and Correlation Plot
summary(fuel2001) Drivers FuelC Income Miles
Min. : 328094 Min. : 148769 Min. :20993 Min. : 1534
1st Qu.: 1087128 1st Qu.: 737361 1st Qu.:25323 1st Qu.: 36586
Median : 2718209 Median : 2048664 Median :27871 Median : 78914
Mean : 3750504 Mean : 2542786 Mean :28404 Mean : 77419
3rd Qu.: 4424256 3rd Qu.: 3039932 3rd Qu.:31208 3rd Qu.:112828
Max. :21623793 Max. :14691753 Max. :40640 Max. :300767
MPC Pop Tax Fuel
Min. : 6556 Min. : 381882 Min. : 7.50 Min. :317.5
1st Qu.: 9391 1st Qu.: 1162624 1st Qu.:18.00 1st Qu.:575.0
Median :10458 Median : 3115130 Median :20.00 Median :626.0
Mean :10448 Mean : 4257046 Mean :20.15 Mean :613.1
3rd Qu.:11311 3rd Qu.: 4845200 3rd Qu.:23.25 3rd Qu.:666.6
Max. :17495 Max. :25599275 Max. :29.00 Max. :842.8
Dlic logMiles
Min. : 700.2 Min. : 7.336
1st Qu.: 864.1 1st Qu.:10.507
Median : 909.1 Median :11.276
Mean : 903.7 Mean :10.914
3rd Qu.: 943.0 3rd Qu.:11.634
Max. :1075.3 Max. :12.614
pairs(fuel2001[, c("Fuel", "Dlic", "Income", "logMiles", "Tax")], main="Correlation Plot")SECTION 2: nassCDS DATA ANALYSIS
install.packages("DAAG")Warning: unable to access index for repository https://cloud.r-project.org/src/contrib:
cannot open URL 'https://cloud.r-project.org/src/contrib/PACKAGES'
Warning: package 'DAAG' is not available for this version of R
A version of this package for your version of R might be available elsewhere,
see the ideas at
https://cran.r-project.org/doc/manuals/r-patched/R-admin.html#Installing-packages
Warning: unable to access index for repository https://cloud.r-project.org/bin/macosx/big-sur-x86_64/contrib/4.4:
cannot open URL 'https://cloud.r-project.org/bin/macosx/big-sur-x86_64/contrib/4.4/PACKAGES'
library(DAAG)
Attaching package: 'DAAG'
The following object is masked from 'package:alr4':
ais
The following object is masked from 'package:car':
vif
The following object is masked from 'package:MASS':
hills
data(nassCDS)Question 1: Seatbelt Use and Mortality
(1). How many indiv used seatbelts
sum(nassCDS$seatbelt == "belted", na.rm=TRUE)[1] 18573
(2) table of seatbelt usage vs accident outcome
table_seat <- table(nassCDS$seatbelt, nassCDS$dead)
table_seat
alive dead
none 6964 680
belted 18073 500
(3) Proportion test
test_proportion <- function(tab){
p1 <- tab[1,2]/sum(tab[1,])
p2 <- tab[2,2]/sum(tab[2,])
p <- (tab[1,2]+tab[2,2])/sum(tab)
se <- sqrt(p*(1-p)*(1/sum(tab[1,])+1/sum(tab[2,])))
z <- (p1 - p2)/se
pval <- 2*pnorm(-abs(z))
return(data.frame(Z_statistic=z, P_value=pval))
}
test_proportion(table_seat) Z_statistic P_value
1 22.02001 1.852181e-107
(4) Visualization
barplot(table_seat, beside=TRUE, col=c("skyblue","salmon"),
main="Seatbelt Usage vs Accident Outcome", ylab="Count")Question 2: Age of Occupants and Accident Outcome
tapply(nassCDS$ageOFocc, nassCDS$dead, mean, na.rm=TRUE) alive dead
36.85701 44.61525
tapply(nassCDS$ageOFocc, nassCDS$dead, sd, na.rm=TRUE) alive dead
17.65621 21.32238
boxplot(ageOFocc ~ dead, data=nassCDS, main="Occupant Age by Outcome",
xlab="Outcome", ylab="Age", col=c("orange","lightblue"))
stripchart(ageOFocc ~ dead, data=nassCDS, vertical=TRUE, add=TRUE, pch=16, col="blue")alive <- nassCDS$ageOFocc[nassCDS$dead=="alive"]
dead <- nassCDS$ageOFocc[nassCDS$dead=="dead"]
t.test(alive, dead, var.equal=FALSE)
Welch Two Sample t-test
data: alive and dead
t = -12.302, df = 1256.4, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-8.995522 -6.520963
sample estimates:
mean of x mean of y
36.85701 44.61525
(1) mean and standard deviation
# Load the nassCDS dataset
data(nassCDS, package = "DAAG")
# Check the structure of the dataset
str(nassCDS)'data.frame': 26217 obs. of 15 variables:
$ dvcat : Ord.factor w/ 5 levels "1-9km/h"<"10-24"<..: 3 2 2 3 3 4 5 5 2 2 ...
$ weight : num 25.1 25.1 32.4 495.4 25.1 ...
$ dead : Factor w/ 2 levels "alive","dead": 1 1 1 1 1 1 1 2 1 1 ...
$ airbag : Factor w/ 2 levels "none","airbag": 1 2 1 2 1 1 1 1 1 1 ...
$ seatbelt : Factor w/ 2 levels "none","belted": 2 2 1 2 2 2 2 1 2 2 ...
$ frontal : num 1 1 1 1 1 1 1 1 0 1 ...
$ sex : Factor w/ 2 levels "f","m": 1 1 1 1 1 1 2 2 2 1 ...
$ ageOFocc : num 26 72 69 53 32 22 22 32 40 18 ...
$ yearacc : num 1997 1997 1997 1997 1997 ...
$ yearVeh : num 1990 1995 1988 1995 1988 ...
$ abcat : chr "unavail" "deploy" "unavail" "deploy" ...
$ occRole : chr "driver" "driver" "driver" "driver" ...
$ deploy : num 0 1 0 1 0 0 0 0 0 0 ...
$ injSeverity: num 3 1 4 1 3 3 3 4 1 0 ...
$ caseid : chr "2:3:1" "2:3:2" "2:5:1" "2:10:1" ...
# Look at the variables we need
head(nassCDS[, c("dead", "ageOFocc")]) dead ageOFocc
1 alive 26
2 alive 72
3 alive 69
4 alive 53
5 alive 32
6 alive 22
# mean and standard deviation of age by accident outcome
age_stats <- nassCDS %>%
group_by(dead) %>%
summarise(
mean_age = mean(ageOFocc, na.rm = TRUE),
sd_age = sd(ageOFocc, na.rm = TRUE),
n = n()
)
print(age_stats)# A tibble: 2 × 4
dead mean_age sd_age n
<fct> <dbl> <dbl> <int>
1 alive 36.9 17.7 25037
2 dead 44.6 21.3 1180
(2) Visualize the distribution of the occupants’ age by accident outcome with data points
# Create boxplot with data points
ggplot(nassCDS, aes(x = dead, y = ageOFocc, fill = dead)) +
geom_boxplot(alpha = 0.7, outlier.shape = NA) +
geom_jitter(width = 0.2, alpha = 0.3, size = 0.8) +
labs(title = "Distribution of Occupant Age by Accident Outcome",
x = "Accident Outcome",
y = "Age of Occupant") +
theme_minimal() +
scale_fill_manual(values = c("alive" = "lightblue", "dead" = "lightcoral"))The boxplot shows the distribution of ages for both groups (alive and dead) with individual data points overlaid. This visualization helps compare the central tendency, spread, and potential outliers in age distribution between survivors and fatalities.
(3) 95% confidence interval for the mean difference of the age of occupant using t distribution.
# Calculate 95% confidence interval for mean age difference using t-distribution
# Extract ages for each group
age_alive <- nassCDS$ageOFocc[nassCDS$dead == "alive"]
age_dead <- nassCDS$ageOFocc[nassCDS$dead == "dead"]
# Perform t-test to get confidence interval
t_test_result <- t.test(age_dead, age_alive, conf.level = 0.95)
# Extract the confidence interval
ci_lower <- t_test_result$conf.int[1]
ci_upper <- t_test_result$conf.int[2]
mean_diff <- t_test_result$estimate[1] - t_test_result$estimate[2]
cat("Mean age difference (dead - alive):", round(mean_diff, 2), "\n")Mean age difference (dead - alive): 7.76
cat("95% Confidence Interval: [", round(ci_lower, 2), ",", round(ci_upper, 2), "]\n")95% Confidence Interval: [ 6.52 , 9 ]
cat("t-statistic:", round(t_test_result$statistic, 2), "\n")t-statistic: 12.3
cat("p-value:", format.pval(t_test_result$p.value), "\n")p-value: < 2.22e-16
Description:
The 95% confidence interval for the mean difference in age between occupants who died and those who survived is [lower bound, upper bound]. This means we are 95% confident that the true mean age difference in the population falls within this interval.
Question 3: Sex, Age, and Safety Devices
(1)
boxplot(ageOFocc ~ sex, data=nassCDS, main="Occupant Age by Sex", col=c("pink","lightblue"))(2)
sum(nassCDS$ageOFocc > 50 & nassCDS$dead=="alive", na.rm=TRUE)[1] 5174
(3)
nassCDS$AgeOFocc_class <- ifelse(nassCDS$ageOFocc > 50, 1, 0)(4-7)
nassCDS_o50 <- nassCDS %>%
filter(ageOFocc > 50) %>%
select(dead, airbag, weight, injSeverity) %>%
na.omit()
dim(nassCDS_o50)[1] 5573 4
barplot(table(nassCDS_o50$dead, nassCDS_o50$airbag),
beside=TRUE, col=c("skyblue","tomato"),
main="Airbag vs Outcome (Age > 50)", ylab="Count")barplot(table(nassCDS_o50$injSeverity, nassCDS_o50$airbag),
beside=TRUE, col=c("lightgreen","pink"),
main="Airbag vs Injury Severity (Age > 50)", ylab="Count")Question 4: Summary Function for Fatal Accidents
nass_analysis <- function(data){
d <- subset(data, dead=="dead")
pct_dead <- 100 * nrow(d) / nrow(data)
pct_male <- 100 * sum(d$sex=="male", na.rm=TRUE)/nrow(d)
pct_female <- 100 * sum(d$sex=="female", na.rm=TRUE)/nrow(d)
mode_sev <- names(sort(table(d$injSeverity), decreasing=TRUE))[1]
age_min <- min(d$ageOFocc, na.rm=TRUE)
age_max <- max(d$ageOFocc, na.rm=TRUE)
table_out <- data.frame(pct_dead, pct_male, pct_female, mode_sev, age_min, age_max)
hist(d$injSeverity, main="Injury Severity among Deaths", xlab="Injury Severity", col="lightblue")
return(table_out)
}
nass_analysis(nassCDS) pct_dead pct_male pct_female mode_sev age_min age_max
1 4.500896 0 0 4 16 97
(1) which of the accident outcome is “dead”?
fatal_cases <- nassCDS %>% filter(dead == "dead")
# Check the result
cat("Total observations in original dataset:", nrow(nassCDS), "\n")Total observations in original dataset: 26217
cat("Fatal cases found:", nrow(fatal_cases), "\n")Fatal cases found: 1180
cat("Percentage of fatal cases:", round(nrow(fatal_cases)/nrow(nassCDS)*100, 2), "%\n")Percentage of fatal cases: 4.5 %
# Preview the fatal cases
head(fatal_cases) dvcat weight dead airbag seatbelt frontal sex ageOFocc yearacc yearVeh
8 55+ 27.078 dead none none 1 m 32 1997 1987
14 25-39 89.627 dead airbag belted 0 f 54 1997 1994
83 55+ 27.078 dead none belted 1 m 67 1997 1992
84 55+ 27.078 dead none belted 1 f 64 1997 1992
265 55+ 13.374 dead none none 1 m 23 1997 1986
311 25-39 12.383 dead none belted 0 f 77 1997 1992
abcat occRole deploy injSeverity caseid AgeOFocc_class
8 unavail driver 0 4 2:13:2 0
14 nodeploy driver 0 4 2:17:1 1
83 unavail driver 0 4 2:79:1 1
84 unavail pass 0 4 2:79:1 1
265 unavail driver 0 4 4:58:1 0
311 unavail pass 0 4 4:96:2 1
This task filters the dataset to include only cases where the occupant died
(2) The percentage of deaths
# 4.2 Calculate percentage of deaths out of the overall number of observations
total_observations <- nrow(nassCDS)
fatal_count <- nrow(fatal_cases)
death_percentage <- (fatal_count / total_observations) * 100
cat("Overall death statistics:\n")Overall death statistics:
cat("Total observations:", total_observations, "\n")Total observations: 26217
cat("Number of deaths:", fatal_count, "\n")Number of deaths: 1180
cat("Percentage of deaths:", round(death_percentage, 2), "%\n")Percentage of deaths: 4.5 %
(3) Calculate gender percentages among fatalities
# 4.3 Calculate the percentages of females and males among the occupants who died
gender_breakdown <- fatal_cases %>%
count(sex) %>%
mutate(percentage = (n / fatal_count) * 100)
print("Gender distribution among fatalities:")[1] "Gender distribution among fatalities:"
print(gender_breakdown) sex n percentage
1 f 464 39.32203
2 m 716 60.67797
# Extract specific percentages
female_pct <- gender_breakdown$percentage[gender_breakdown$sex == "f"]
male_pct <- gender_breakdown$percentage[gender_breakdown$sex == "m"]
cat("\nDetailed breakdown:\n")
Detailed breakdown:
cat("Female fatalities:", ifelse(length(female_pct) > 0, round(female_pct, 2), 0), "%\n")Female fatalities: 39.32 %
cat("Male fatalities:", ifelse(length(male_pct) > 0, round(male_pct, 2), 0), "%\n")Male fatalities: 60.68 %
(4) Find most frequent injury severity
# 4 Show the most frequent severity of their injuries
severity_analysis <- fatal_cases %>%
count(injSeverity) %>%
arrange(desc(n)) # Sort by frequency in descending order
print("Injury severity frequency among fatalities:")[1] "Injury severity frequency among fatalities:"
print(severity_analysis) injSeverity n
1 4 1084
2 3 87
3 2 7
4 1 1
5 5 1
most_frequent_severity <- severity_analysis$injSeverity[1]
most_frequent_count <- severity_analysis$n[1]
cat("\nMost frequent injury severity:", most_frequent_severity, "\n")
Most frequent injury severity: 4
cat("Number of cases with this severity:", most_frequent_count, "\n")Number of cases with this severity: 1084
cat("This represents", round(most_frequent_count/fatal_count*100, 2), "% of all fatalities\n")This represents 91.86 % of all fatalities
This identifies the most common injury severity level among those who died. We count occurrences of each injury severity level and sort them to find the most frequent one. This reveals what injury severity is most associated with fatal outcomes.
(5) Calculate age range of fatalities
# 4.5 Calculate the minimum and maximum age of the occupant
min_age <- min(fatal_cases$ageOFocc, na.rm = TRUE)
max_age <- max(fatal_cases$ageOFocc, na.rm = TRUE)
cat("Age range:", max_age - min_age, "years\n")Age range: 81 years
(6) Create injury severity vs age visualization
# histogram with severity of injuries on x-axis and occupant's age on y-axis
ggplot(fatal_cases, aes(x = factor(injSeverity), y = ageOFocc)) +
geom_boxplot(aes(fill = factor(injSeverity)), alpha = 0.7) +
geom_jitter(width = 0.2, alpha = 0.5, size = 1, color = "darkred") +
labs(title = "Relationship Between Injury Severity and Occupant Age in Fatal Accidents",
subtitle = paste("Analysis of", fatal_count, "fatal cases"),
x = "Injury Severity Level",
y = "Occupant Age (years)",
caption = "Each point represents one fatal case") +
theme_minimal() +
theme(legend.position = "none") +
stat_summary(fun = mean, geom = "point", shape = 18, size = 3, color = "blue")This creates a visualization showing how age distributes across different injury severity levels.
(7) Complete SINGLE-for-all function
# 4.7 Complete function that returns both numerical and graphical outputs
analyze_fatal_accidents <- function(nassCDS) {
# 4.1 - Filter fatal cases
fatal_cases <- nassCDS %>% filter(dead == "dead")
# 4.2 - Calculate death percentage
total_obs <- nrow(nassCDS)
fatal_count <- nrow(fatal_cases)
death_pct <- (fatal_count / total_obs) * 100
# 4.3 - Gender percentages
gender_pct <- fatal_cases %>%
count(sex) %>%
mutate(percentage = (n / fatal_count) * 100)
# 4.4 - Most frequent injury severity
most_severe <- fatal_cases %>%
count(injSeverity) %>%
arrange(desc(n)) %>%
slice(1)
# 4.5 - Age range
min_age <- min(fatal_cases$ageOFocc, na.rm = TRUE)
max_age <- max(fatal_cases$ageOFocc, na.rm = TRUE)
# Create numerical output table
numerical_output <- data.frame(
Metric = c("Death Percentage", "Female Fatalities %", "Male Fatalities %",
"Most Frequent Severity", "Min Age", "Max Age"),
Value = c(round(death_pct, 2),
round(gender_pct$percentage[gender_pct$sex == "f"], 2),
round(gender_pct$percentage[gender_pct$sex == "m"], 2),
most_severe$injSeverity,
round(min_age, 1),
round(max_age, 1))
)
# 4.6 - Create plot
graphical_output <- ggplot(fatal_cases, aes(x = factor(injSeverity), y = ageOFocc)) +
geom_boxplot(aes(fill = factor(injSeverity)), alpha = 0.7) +
labs(title = "Injury Severity vs Age in Fatal Accidents",
x = "Injury Severity", y = "Occupant Age") +
theme_minimal() +
theme(legend.position = "none")
return(list(numerical = numerical_output, plot = graphical_output))
}
# Execute the complete function
results <- analyze_fatal_accidents(nassCDS)print(results$numerical) Metric Value
1 Death Percentage 4.50
2 Female Fatalities % 39.32
3 Male Fatalities % 60.68
4 Most Frequent Severity 4.00
5 Min Age 16.00
6 Max Age 97.00
print(results$plot)Question 5: Seatbelt Users Summary
seatbelt_users <- nassCDS[nassCDS$seatbelt=="belted", ]
nrow(seatbelt_users)[1] 18573
table(seatbelt_users$dead)
alive dead
18073 500
table(seatbelt_users$dead, seatbelt_users$occRole)
driver pass
alive 14550 3523
dead 363 137
seatbelt_users <- seatbelt_users[order(seatbelt_users$injSeverity, seatbelt_users$ageOFocc), ]
head(seatbelt_users[order(-seatbelt_users$weight), ], 25) dvcat weight dead airbag seatbelt frontal sex ageOFocc yearacc
6888 10-24 57871.59 alive airbag belted 1 f 16 1998
6889 10-24 57871.59 alive airbag belted 1 m 16 1998
6844 10-24 57871.59 alive airbag belted 1 f 59 1998
2630 10-24 47463.09 alive airbag belted 0 f 24 1997
25422 10-24 31694.04 alive airbag belted 1 m 33 2002
25423 10-24 31694.04 alive airbag belted 1 f 47 2002
10596 10-24 29533.13 alive airbag belted 1 m 19 1999
24332 10-24 29301.14 alive none belted 1 m 23 2002
10572 10-24 28281.11 alive none belted 0 m 43 1999
20993 25-39 28215.77 alive none belted 1 m 35 2001
20994 25-39 28215.77 alive none belted 1 f 37 2001
11092 10-24 26789.34 alive airbag belted 0 m 30 1999
10538 10-24 25988.01 alive none belted 0 f 34 1999
2507 1-9km/h 25688.37 alive airbag belted 0 m 36 1997
19732 10-24 25029.20 alive airbag belted 1 f 31 2001
19733 10-24 25029.20 alive none belted 1 m 37 2001
19704 1-9km/h 23428.61 alive none belted 0 f 31 2001
15683 1-9km/h 23131.14 alive airbag belted 0 m 42 2000
15684 1-9km/h 23131.14 alive airbag belted 0 f 43 2000
15682 10-24 23131.14 alive airbag belted 1 m 18 2000
19612 10-24 22232.64 alive none belted 1 m 36 2001
10521 1-9km/h 20296.81 alive none belted 0 m 16 1999
10522 1-9km/h 20296.81 alive none belted 0 m 17 1999
24243 10-24 20081.63 alive airbag belted 0 f 21 2002
24242 10-24 20081.63 alive airbag belted 0 m 26 2002
yearVeh abcat occRole deploy injSeverity caseid AgeOFocc_class
6888 1998 nodeploy driver 0 0 48:139:1 0
6889 1998 nodeploy pass 0 0 48:139:1 0
6844 1990 deploy driver 1 2 48:97:1 1
2630 1995 nodeploy driver 0 0 48:92:2 0
25422 1994 nodeploy driver 0 0 75:24:2 0
25423 1994 nodeploy pass 0 0 75:24:2 0
10596 1995 deploy driver 1 0 43:191:1 0
24332 1984 unavail driver 0 1 48:96:1 0
10572 1992 unavail driver 0 0 43:174:1 0
20993 1987 unavail driver 0 0 76:113:2 0
20994 1987 unavail pass 0 1 76:113:2 0
11092 1996 deploy driver 1 3 48:131:1 0
10538 1993 unavail driver 0 0 43:151:1 0
2507 1993 nodeploy driver 0 0 45:169:1 0
19732 1994 deploy driver 1 0 48:117:1 0
19733 1994 unavail pass 0 0 48:117:1 0
19704 1993 unavail driver 0 3 48:94:2 0
15683 1998 nodeploy driver 0 0 48:164:2 0
15684 1998 nodeploy pass 0 0 48:164:2 0
15682 2000 nodeploy driver 0 2 48:164:1 0
19612 1991 unavail driver 0 0 48:8:2 0
10521 1990 unavail driver 0 0 43:135:2 0
10522 1990 unavail pass 0 0 43:135:2 0
24243 1996 nodeploy pass 0 0 48:34:2 0
24242 1996 nodeploy driver 0 0 48:34:2 0
(1) New df containing only occupants who used seatbel
# Create a new data frame which contains only occupants who used seatbelt
seatbelt_users <- nassCDS %>% filter(seatbelt == "belted")
# Check the result
cat("Created new data frame: seatbelt_users\n")Created new data frame: seatbelt_users
cat("Dimensions:", dim(seatbelt_users), "(rows × columns)\n")Dimensions: 18573 16 (rows × columns)
cat("First few rows:\n")First few rows:
head(seatbelt_users) dvcat weight dead airbag seatbelt frontal sex ageOFocc yearacc yearVeh
1 25-39 25.069 alive none belted 1 f 26 1997 1990
2 10-24 25.069 alive airbag belted 1 f 72 1997 1995
4 25-39 495.444 alive airbag belted 1 f 53 1997 1995
5 25-39 25.069 alive none belted 1 f 32 1997 1988
6 40-54 25.069 alive none belted 1 f 22 1997 1985
7 55+ 27.078 alive none belted 1 m 22 1997 1984
abcat occRole deploy injSeverity caseid AgeOFocc_class
1 unavail driver 0 3 2:3:1 0
2 deploy driver 1 1 2:3:2 1
4 deploy driver 1 1 2:10:1 1
5 unavail driver 0 3 2:11:1 0
6 unavail driver 0 3 2:11:2 0
7 unavail driver 0 3 2:13:1 0
(2) How many occupants used seatbelt ?
total_seatbelt_users <- nrow(seatbelt_users)
cat("Occupants who used seatbelt:", total_seatbelt_users, "\n")Occupants who used seatbelt: 18573
(3) Survival outcomes among seatbelt users
# Among seatbelt users, how many died and how many survived?
survival_breakdown <- seatbelt_users %>%
count(dead) %>%
mutate(percentage = (n / total_seatbelt_users) * 100)
# Calculate fatality rate
fatalities <- survival_breakdown$n[survival_breakdown$dead == "dead"]
survivors <- survival_breakdown$n[survival_breakdown$dead == "alive"]
cat(
"Seatbelt users who survived:",
survivors,
"(", round(survivors/total_seatbelt_users*100, 2),
"%)\n"
)Seatbelt users who survived: 18073 ( 97.31 %)
cat(
"Seatbelt users who died:",
fatalities,
"(", round(fatalities/total_seatbelt_users*100, 2),
"%)\n"
)Seatbelt users who died: 500 ( 2.69 %)
(4) Role analysis among seatbelt users
# Analyze drivers vs passengers among different outcomes
role_analysis <- seatbelt_users %>%
group_by(dead, occRole) %>%
summarise(count = n(), .groups = 'drop') %>%
group_by(dead) %>%
mutate(percentage = (count / sum(count)) * 100)
cat("Role distribution among seatbelt users by outcome:\n")Role distribution among seatbelt users by outcome:
print(role_analysis)# A tibble: 4 × 4
# Groups: dead [2]
dead occRole count percentage
<fct> <chr> <int> <dbl>
1 alive driver 14550 80.5
2 alive pass 3523 19.5
3 dead driver 363 72.6
4 dead pass 137 27.4
# Specific answers for the question
drivers_died <- seatbelt_users %>%
filter(dead == "dead" & occRole == "driver") %>%
nrow()
passengers_survived <- seatbelt_users %>%
filter(dead == "alive" & occRole == "passenger") %>%
nrow()
cat("\nSpecific counts requested:\n")
Specific counts requested:
cat("Drivers among seatbelt users who died:", drivers_died, "\n")Drivers among seatbelt users who died: 363
cat("Passengers among seatbelt users who survived:", passengers_survived, "\n")Passengers among seatbelt users who survived: 0
# Additional insight: compare role distribution
cat("\nAdditional insight - Role distribution:\n")
Additional insight - Role distribution:
role_summary <- seatbelt_users %>% count(occRole)
print(role_summary) occRole n
1 driver 14913
2 pass 3660
(5) Sort by injury severity and age
# Sort the data frame according to injury severity and occupant age
seatbelt_sorted <- seatbelt_users %>%
arrange(desc(injSeverity), desc(ageOFocc))
cat("Data frame sorted by injury severity (descending) and age (descending)\n")Data frame sorted by injury severity (descending) and age (descending)
cat("First 10 rows of sorted data:\n")First 10 rows of sorted data:
print(seatbelt_sorted[1:10, c("injSeverity", "ageOFocc", "dead", "occRole", "weight")]) injSeverity ageOFocc dead occRole weight
8618 6 68 alive driver 25.089
1354 6 57 alive driver 31.342
23855 5 90 alive driver 42.379
20225 5 84 alive pass 190.091
21345 5 84 alive pass 28.693
17673 5 83 alive driver 772.047
17954 5 82 alive driver 225.811
21925 5 81 alive driver 134.640
21856 5 80 alive driver 314.908
21872 5 79 alive driver 44.780
# Alternative: ascending order for age
seatbelt_sorted_alt <- seatbelt_users %>%
arrange(desc(injSeverity), ageOFocc)
cat("\nAlternative: Sorted by injury severity (desc) and age (asc)\n")
Alternative: Sorted by injury severity (desc) and age (asc)
cat("First 10 rows:\n")First 10 rows:
print(seatbelt_sorted_alt[1:10, c("injSeverity", "ageOFocc", "dead", "occRole", "weight")]) injSeverity ageOFocc dead occRole weight
1354 6 57 alive driver 31.342
8618 6 68 alive driver 25.089
5130 5 16 dead driver 49.483
10028 5 16 alive pass 258.285
2185 5 17 alive driver 404.961
17397 5 17 alive driver 65.680
655 5 18 alive pass 33.288
8982 5 18 alive driver 1408.990
21482 5 18 alive driver 367.552
25994 5 18 alive pass 24.828
# Show range of injury severity
cat("\nInjury severity range in seatbelt users:\n")
Injury severity range in seatbelt users:
cat("Min severity:", min(seatbelt_users$injSeverity, na.rm = TRUE), "\n")Min severity: 0
cat("Max severity:", max(seatbelt_users$injSeverity, na.rm = TRUE), "\n")Max severity: 6
cat("Mean severity:", round(mean(seatbelt_users$injSeverity, na.rm = TRUE), 2), "\n")Mean severity: 1.5
This sorts the seatbelt users dataframe first by injury severity (most severe first) and then by age (oldest first within each severity level)
(6) Top 25 occupants by weight
# Print the 25 occupants with the highest weight
top_25_weight <- seatbelt_users %>%
arrange(desc(weight)) %>%
head(25)
cat("25 seatbelt users with highest weight:\n")25 seatbelt users with highest weight:
print(top_25_weight[, c("weight", "ageOFocc", "dead", "injSeverity", "occRole", "sex")]) weight ageOFocc dead injSeverity occRole sex
6844 57871.59 59 alive 2 driver f
6888 57871.59 16 alive 0 driver f
6889 57871.59 16 alive 0 pass m
2630 47463.09 24 alive 0 driver f
25422 31694.04 33 alive 0 driver m
25423 31694.04 47 alive 0 pass f
10596 29533.13 19 alive 0 driver m
24332 29301.14 23 alive 1 driver m
10572 28281.11 43 alive 0 driver m
20993 28215.77 35 alive 0 driver m
20994 28215.77 37 alive 1 pass f
11092 26789.34 30 alive 3 driver m
10538 25988.01 34 alive 0 driver f
2507 25688.37 36 alive 0 driver m
19732 25029.20 31 alive 0 driver f
19733 25029.20 37 alive 0 pass m
19704 23428.61 31 alive 3 driver f
15682 23131.14 18 alive 2 driver m
15683 23131.14 42 alive 0 driver m
15684 23131.14 43 alive 0 pass f
19612 22232.64 36 alive 0 driver m
10521 20296.81 16 alive 0 driver m
10522 20296.81 17 alive 0 pass m
24242 20081.63 26 alive 0 driver m
24243 20081.63 21 alive 0 pass f
Question 6: Age, Seatbelt, and Airbag Relationship
par(mfrow=c(1,2))
with(nassCDS, {
boxplot(ageOFocc ~ injSeverity + seatbelt,
main="Age by Injury Severity (Seatbelt)", col=c("skyblue","lightgreen"))
boxplot(ageOFocc ~ injSeverity + airbag,
main="Age by Injury Severity (Airbag)", col=c("pink","lightyellow"))
})