Road accidents are an important road-safety concern. Exploring how recorded crashes vary by time, weekday, road type, weather, and severity can help identify patterns for further investigation. This report uses R and ggplot2 to summarize a supplied cleaned dataset and applies a chi-square test to examine the association between road type and accident severity.
The supplied dataset is described as containing 20,000 rows and 24
columns, including date, time, city, state, road type, weather,
visibility, accident severity, vehicles involved, and casualties. The
report reads cleaned_road_accidents.csv from the working
directory or its data/ subfolder. Header variants are
normalized for the fields used here. If your source uses different
names, update the alias list in the setup chunk.
The dataset was obtained from a community repository. Its provenance and accuracy as a representation of actual Indian road accidents have not been independently verified. Results should be understood as patterns in this supplied file, not official road-safety statistics.
The setup code checks that the CSV is present and non-empty, normalizes common column name variants, parses dates and hours, and treats blank category values as missing. Invalid or unparseable values are retained as missing rather than silently converted to valid values. Each chart excludes records missing the variables required for that chart.
cat("Rows read:", nrow(clean_accidents), "\n")
## Rows read: 20000
cat("Columns read:", ncol(clean_accidents), "\n")
## Columns read: 24
cat("Exact duplicate rows:", sum(duplicated(clean_accidents)), "\n")
## Exact duplicate rows: 0
cat("Rows with any missing value:", sum(!complete.cases(clean_accidents)), "\n")
## Rows with any missing value: 0
if ("date" %in% names(clean_accidents)) {
cat("Missing or invalid dates:", sum(is.na(clean_accidents$date)), "\n")
}
## Missing or invalid dates: 0
cat("Missing or invalid hours:", sum(is.na(clean_accidents$hour) |
clean_accidents$hour < 0 |
clean_accidents$hour > 23, na.rm = TRUE), "\n")
## Missing or invalid hours: 0
Exact duplicates are reported, not removed, so the analysis preserves the supplied records. Check the source and data dictionary before deciding whether repeated rows represent duplicate entries or separate events.
The plots show counts of records in the file. They are not population rates: there are no exposure denominators such as traffic volume, distance traveled, or time spent on the road.
hour_data <- clean_accidents[!is.na(clean_accidents$hour) &
clean_accidents$hour >= 0 & clean_accidents$hour <= 23, ]
ggplot(hour_data, aes(x = hour)) +
geom_bar(fill = "#2878B5", width = 0.8) +
scale_x_continuous(breaks = 0:23) +
labs(title = "Recorded Accidents by Hour", x = "Hour of day", y = "Records") +
theme_minimal()
weekday_levels <- c("monday", "tuesday", "wednesday", "thursday", "friday",
"saturday", "sunday")
weekday_data <- clean_accidents[!is.na(clean_accidents$weekday), ]
weekday_values <- tolower(weekday_data$weekday)
weekday_data$weekday_plot <- factor(weekday_values,
levels = c(weekday_levels, setdiff(unique(weekday_values), weekday_levels)))
ggplot(weekday_data, aes(x = weekday_plot)) +
geom_bar(fill = "#55A868") +
labs(title = "Recorded Accidents by Weekday", x = "Weekday", y = "Records") +
theme_minimal() + theme(axis.text.x = element_text(angle = 35, hjust = 1))
road_data <- clean_accidents[!is.na(clean_accidents$road_type), ]
ggplot(road_data, aes(x = reorder(road_type, road_type, FUN = length))) +
geom_bar(fill = "#C44E52") +
coord_flip() +
labs(title = "Recorded Accidents by Road Type", x = "Road type", y = "Records") +
theme_minimal()
severity_road_data <- clean_accidents[!is.na(clean_accidents$severity) &
!is.na(clean_accidents$road_type), ]
ggplot(severity_road_data, aes(x = road_type, fill = severity)) +
geom_bar(position = "fill") +
coord_flip() +
scale_y_continuous(labels = function(x) paste0(round(100 * x), "%")) +
labs(title = "Severity Composition by Road Type", x = "Road type",
y = "Share of records", fill = "Severity") +
theme_minimal()
severity_weather_data <- clean_accidents[!is.na(clean_accidents$severity) &
!is.na(clean_accidents$weather), ]
ggplot(severity_weather_data, aes(x = weather, fill = severity)) +
geom_bar(position = "fill") +
coord_flip() +
scale_y_continuous(labels = function(x) paste0(round(100 * x), "%")) +
labs(title = "Severity Composition by Weather Condition", x = "Weather",
y = "Share of records", fill = "Severity") +
theme_minimal()
The chi-square test of independence evaluates whether the distribution of recorded severity differs across road-type categories. It assumes independent records and adequate expected cell counts. A small p-value is evidence of an association in this dataset; it does not show that road type causes severity.
test_data <- clean_accidents[!is.na(clean_accidents$road_type) &
!is.na(clean_accidents$severity), ]
test_data$road_type <- droplevels(factor(test_data$road_type))
test_data$severity <- droplevels(factor(test_data$severity))
test_table <- table(test_data$road_type, test_data$severity)
if (nrow(test_table) < 2 || ncol(test_table) < 2) {
cat("The test was not run: at least two road types and two severity categories are required.\n")
} else {
chi_result <- suppressWarnings(chisq.test(test_table, correct = FALSE))
print(test_table)
print(chi_result)
cat("\nInterpretation: ")
if (any(chi_result$expected < 5)) {
cat("Some expected cell counts are below 5, so the chi-square approximation may be unreliable. Consider combining substantively similar categories or using a simulated p-value.\n")
} else if (chi_result$p.value < 0.05) {
cat("At the 5% significance level, the data provide evidence of an association between road type and severity (p = ",
format.pval(chi_result$p.value, digits = 3), "). This is an association, not a causal effect.\n", sep = "")
} else {
cat("At the 5% significance level, the data do not provide sufficient evidence of an association between road type and severity (p = ",
format.pval(chi_result$p.value, digits = 3), "). This does not prove that no association exists.\n", sep = "")
}
}
##
## fatal major minor
## highway 983 1967 3666
## rural 965 2014 3660
## urban 1039 2007 3699
##
## Pearson's Chi-squared test
##
## data: test_table
## X-squared = 2.448, df = 4, p-value = 0.654
##
##
## Interpretation: At the 5% significance level, the data do not provide sufficient evidence of an association between road type and severity (p = 0.654). This does not prove that no association exists.
This report provides a reproducible descriptive analysis of the supplied road-accident records, with five visualizations and a test of association between road type and severity. The plots and test output describe the data that were provided. They should guide questions for further investigation rather than be treated as estimates of real-world accident risk or as evidence of causal effects. Stronger conclusions would require verified data provenance, consistent definitions, and exposure information.