Urban air pollution is an important smart-city issue because it affects public health, transport planning, and environmental management. This project explores air-quality and weather measurements in the TRAQID dataset using R, tidyverse, and ggplot2.
The supplied TRAQID.csv contains traffic-related
air-quality observations with timestamps, PM2.5, PM10, temperature,
humidity, AQI, season, day/night period, AQI category, and image
identifiers. It contains 26,678 rows and 10 original columns. The period
spans 22 October 2022 to 9 July 2024.
The workflow parses created_at as date-time, derives
date and hour fields, checks missing values, removes exact duplicate
rows, and writes a cleaned CSV. Implausible temperature values are
flagged separately rather than silently removed. Any filtered analysis
should disclose the threshold and rationale.
library(tidyverse)
library(lubridate)
raw <- read_csv("data/TRAQID.csv", show_col_types = FALSE)
data <- raw %>%
mutate(created_at = ymd_hms(created_at),
date = as.Date(created_at),
hour = hour(created_at),
Season = factor(Season, levels = c("Summer","Monsoon","Winter")),
Day_or_Night = factor(Day_or_Night, levels = c("Day","Night")),
aqi_cat = factor(aqi_cat,
levels = c("Good","Satisfactory","Moderate","Poor","Very Poor","Severe"))) %>%
distinct()
glimpse(data)
## Rows: 26,678
## Columns: 12
## $ created_at <dttm> 2022-10-22 18:00:00, 2022-10-22 18:00:00, 2022-10-22 18:…
## $ Image <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17…
## $ PM2.5 <dbl> 26.115, 26.823, 26.823, 27.118, 26.882, 26.764, 27.000, 2…
## $ PM10 <dbl> 41.0112, 41.9240, 41.3698, 41.0438, 40.1962, 39.5116, 40.…
## $ Temperature <dbl> 26.95, 26.96, 26.98, 26.99, 26.96, 26.97, 26.97, 26.93, 2…
## $ Humidity <dbl> 43.451, 43.463, 43.566, 43.598, 43.676, 43.757, 43.859, 4…
## $ aqi <dbl> 43.52500, 44.70500, 44.70500, 45.19667, 44.80333, 44.6066…
## $ Season <fct> Monsoon, Monsoon, Monsoon, Monsoon, Monsoon, Monsoon, Mon…
## $ Day_or_Night <fct> Night, Night, Night, Night, Night, Night, Night, Night, N…
## $ aqi_cat <fct> Good, Good, Good, Good, Good, Good, Good, Good, Good, Goo…
## $ date <date> 2022-10-22, 2022-10-22, 2022-10-22, 2022-10-22, 2022-10-…
## $ hour <int> 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 1…
summarise(data, rows=n(), missing_cells=sum(is.na(across(everything()))))
## # A tibble: 1 × 2
## rows missing_cells
## <int> <int>
## 1 26678 0
data %>% count(Season)
## # A tibble: 3 × 2
## Season n
## <fct> <int>
## 1 Summer 5901
## 2 Monsoon 10567
## 3 Winter 10210
data %>% count(Day_or_Night)
## # A tibble: 2 × 2
## Day_or_Night n
## <fct> <int>
## 1 Day 13789
## 2 Night 12889
data %>% count(aqi_cat)
## # A tibble: 6 × 2
## aqi_cat n
## <fct> <int>
## 1 Good 744
## 2 Satisfactory 13033
## 3 Moderate 7453
## 4 Poor 2283
## 5 Very Poor 2233
## 6 Severe 932
summary(select(data, `PM2.5`, PM10, Temperature, Humidity, aqi))
## PM2.5 PM10 Temperature Humidity
## Min. : 12.92 Min. : 32.18 Min. :-93.47 Min. : 9.408
## 1st Qu.: 39.09 1st Qu.: 57.77 1st Qu.: 28.17 1st Qu.:29.630
## Median : 52.37 Median : 72.73 Median : 30.94 Median :38.177
## Mean : 66.57 Mean :126.18 Mean : 31.01 Mean :38.602
## 3rd Qu.: 73.44 3rd Qu.:157.02 3rd Qu.: 33.74 3rd Qu.:46.527
## Max. :400.86 Max. :669.85 Max. :181.37 Max. :76.167
## aqi
## Min. : 36.55
## 1st Qu.: 69.78
## Median : 97.12
## Mean :143.60
## 3rd Qu.:171.32
## Max. :599.95
data %>% group_by(Season) %>%
summarise(mean_aqi=mean(aqi, na.rm=TRUE), .groups="drop") %>%
ggplot(aes(Season, mean_aqi, fill=Season)) + geom_col() +
labs(title="Average AQI by Season", x="Season", y="Mean AQI") + theme_minimal()
data %>% group_by(Day_or_Night) %>%
summarise(mean_aqi=mean(aqi, na.rm=TRUE), .groups="drop") %>%
ggplot(aes(Day_or_Night, mean_aqi, fill=Day_or_Night)) + geom_col() +
labs(title="Average AQI: Day vs Night", x="Period", y="Mean AQI") + theme_minimal()
data %>% count(aqi_cat) %>%
ggplot(aes(aqi_cat, n, fill=aqi_cat)) + geom_col() +
labs(title="Distribution of AQI Categories", x="AQI category", y="Observations") +
theme_minimal() + theme(axis.text.x=element_text(angle=25,hjust=1))
ggplot(data, aes(`PM2.5`, aqi)) + geom_point(alpha=.2) +
geom_smooth(method="lm", se=TRUE) +
labs(title="PM2.5 vs AQI", x="PM2.5", y="AQI") + theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
daily <- data %>% group_by(date) %>% summarise(mean_aqi=mean(aqi, na.rm=TRUE), .groups="drop")
ggplot(daily, aes(date, mean_aqi)) + geom_line() + geom_smooth(se=FALSE, method="loess") +
labs(title="Daily Average AQI Over Time", x="Date", y="Mean AQI") + theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
cor_data <- data %>% select(`PM2.5`, PM10, Temperature, Humidity, aqi)
cor_long <- cor(cor_data, use="pairwise.complete.obs") %>% as.data.frame() %>%
rownames_to_column("variable") %>% pivot_longer(-variable, names_to="variable2", values_to="r")
ggplot(cor_long, aes(variable, variable2, fill=r)) + geom_tile() +
geom_text(aes(label=round(r,2))) + scale_fill_gradient2() +
labs(title="Correlation Matrix", x=NULL, y=NULL, fill="Pearson r") + theme_minimal()
The visualizations show the seasonal and day/night distribution of AQI, AQI category frequencies, particulate matter association with AQI, daily change over time, and pairwise numeric correlations. Exact interpretations should be tied to the generated output and should not be treated as causal claims.
cor(select(data, `PM2.5`, PM10, Temperature, Humidity, aqi), use="complete.obs")
## PM2.5 PM10 Temperature Humidity aqi
## PM2.5 1.00000000 0.7511374 -0.05117279 -0.1433395 0.92203749
## PM10 0.75113743 1.0000000 0.11375038 -0.3635268 0.89363236
## Temperature -0.05117279 0.1137504 1.00000000 -0.4295664 0.02610646
## Humidity -0.14333949 -0.3635268 -0.42956642 1.0000000 -0.23453439
## aqi 0.92203749 0.8936324 0.02610646 -0.2345344 1.00000000
model <- lm(aqi ~ `PM2.5` + PM10 + Temperature + Humidity + Season + Day_or_Night, data=data)
summary(model)
##
## Call:
## lm(formula = aqi ~ PM2.5 + PM10 + Temperature + Humidity + Season +
## Day_or_Night, data = data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -201.416 -11.306 -4.568 4.764 240.035
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -17.877300 1.617687 -11.051 < 2e-16 ***
## PM2.5 1.333489 0.005560 239.827 < 2e-16 ***
## PM10 0.457367 0.002634 173.614 < 2e-16 ***
## Temperature 0.298580 0.034896 8.556 < 2e-16 ***
## Humidity 0.098826 0.017976 5.498 3.89e-08 ***
## SeasonMonsoon 4.162078 0.698923 5.955 2.63e-09 ***
## SeasonWinter -2.215632 0.540589 -4.099 4.17e-05 ***
## Day_or_NightNight 2.313597 0.363742 6.361 2.04e-10 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 25.82 on 26670 degrees of freedom
## Multiple R-squared: 0.9439, Adjusted R-squared: 0.9439
## F-statistic: 6.415e+04 on 7 and 26670 DF, p-value: < 2.2e-16
The linear model estimates associations between AQI and particulate/weather/time variables. It is exploratory: correlated predictors, temporal dependence, and unusual sensor values may affect coefficients. It does not establish causality.
The data contain substantial variation in AQI and particulate measurements. Seasonal and day/night comparisons can identify patterns worth investigating. AQI category counts show that observations are distributed across multiple air-quality levels. The PM2.5–AQI plot and correlation matrix help quantify relationships among the measured variables. Confirm the exact numerical interpretation after running the report.
This project demonstrates a reproducible R workflow for preparing urban air-quality observations, exploring temporal and categorical patterns, visualizing relationships with ggplot2, and fitting an exploratory statistical model. Future work could join a separate traffic-volume or public-transport dataset by compatible time/location fields, if suitable matched records are available.