本報告旨在展示本學期 R 課程所學之資料處理、資料清理、迴圈、條件判斷、自訂函數及資料視覺化技巧。資料來源為臺灣環境部公開之空氣品質指標(AQI),內容包含細懸浮微粒(PM2.5)、懸浮微粒(PM10)、臭氧(O₃)等污染物指標。本報告將示範如何匯入資料、處理欄位、建立自訂分類函數、使用迴圈生成新變數,並以圖表呈現不同縣市間的空氣品質差異。
空氣品質對人體健康影響深遠,尤其 PM2.5 等細懸浮微粒已知會提高心血管疾病與呼吸道疾病的風險。環境部發布的 AQI(Air Quality Index)整合多項污染物,包含 PM2.5、PM10、臭氧、二氧化硫、一氧化碳、氮氧化物等,可作為判斷空氣品質優劣的重要依據。
本報告使用環境部開放資料平台之即時空氣品質資料,針對臺灣不同縣市的空氣污染程度進行觀察與分析。
資料來自:
環境部空氣品質監測網 (Open Data)
資料格式:CSV
主要欄位:
| 欄位名稱 | 說明 |
|---|---|
| sitename | 測站名稱 |
| county | 所在縣市 |
| aqi | 空氣品質指標 |
| pollutant | 空氣污染指標物 |
| status | 狀態 |
| so2 | 二氧化硫 (ppb) |
| co | 一氧化碳 (ppm) |
| o3 | 臭氧 (ppb) |
| o3_8hr | 臭氧8小時移動平均 (ppb) |
| pm10 | 懸浮微粒 (μg/m3) |
| pm2.5 | 細懸浮微粒 (μg/m3) |
| no2 | 二氧化氮 (ppb) |
| nox | 氮氧化物 |
| no | 一氧化氮 |
| wind_speed | 風速 (m/sec) |
| wind_direc | 風向 (degrees) |
| publishtime | 資料發布時間 |
| longitude / latitude | 測站座標 |
| siteid | 測站編號 |
aqi <- read_csv("aqi.csv")
## Rows: 88 Columns: 24
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (20): sitename, county, pollutant, status, so2, co, o3, o3_8hr, pm10, pm...
## dbl (4): aqi, longitude, latitude, siteid
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# 顯示前幾筆資料
head(aqi)
## # A tibble: 6 × 24
## sitename county aqi pollutant status so2 co o3 o3_8hr pm10 pm2.5
## <chr> <chr> <dbl> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 嘉義(東區)…… 嘉義市 74 懸浮微粒 普通 1.8 0.45 13 32 - <NA>
## 2 屏東(枋山) 屏東縣 60 細懸浮微粒…… 普通 0.5 0.13 55 54 29 9
## 3 臺南(南化)…… 臺南市 42 <NA> 良好 0.4 0.15 8 29 19 10
## 4 新北(樹林) 新北市 40 <NA> 良好 0.2 0.24 26 18 6 4
## 5 台中(和平)…… 臺中市 37 <NA> 良好 0.3 0.19 5 15 11 6
## 6 屏東(琉球)…… 屏東縣 57 懸浮微粒 普通 0.6 0.18 26 42 28 15
## # ℹ 13 more variables: no2 <chr>, nox <chr>, no <chr>, wind_speed <chr>,
## # wind_direc <chr>, publishtime <chr>, co_8hr <chr>, pm2.5_avg <chr>,
## # pm10_avg <chr>, so2_avg <chr>, longitude <dbl>, latitude <dbl>,
## # siteid <dbl>
# 資料筆數與欄位
nrow(aqi)
## [1] 88
colnames(aqi)
## [1] "sitename" "county" "aqi" "pollutant" "status"
## [6] "so2" "co" "o3" "o3_8hr" "pm10"
## [11] "pm2.5" "no2" "nox" "no" "wind_speed"
## [16] "wind_direc" "publishtime" "co_8hr" "pm2.5_avg" "pm10_avg"
## [21] "so2_avg" "longitude" "latitude" "siteid"
# 修正資料格式:把 "-" 變成 NA,並把 pm10 轉成數字
aqi <- aqi %>%
mutate(pm10 = na_if(pm10, "-"),
pm10 = as.numeric(pm10))
pm25_level <- function(value){
if(is.na(value)){
return(NA)
} else if(value <= 15){
return("良好 Good")
} else if(value <= 35){
return("普通 Moderate")
} else{
return("對敏感族群不健康 Unhealthy")
}
}
pm25_category <- c()
for(i in 1:nrow(aqi)){
pm25_category[i] <- pm25_level(aqi$`pm2.5`[i])
}
aqi$PM25_Category <- pm25_category
head(aqi[, c("county", "pm2.5", "PM25_Category")])
## # A tibble: 6 × 3
## county pm2.5 PM25_Category
## <chr> <chr> <chr>
## 1 嘉義市 <NA> <NA>
## 2 屏東縣 9 對敏感族群不健康 Unhealthy
## 3 臺南市 10 良好 Good
## 4 新北市 4 對敏感族群不健康 Unhealthy
## 5 臺中市 6 對敏感族群不健康 Unhealthy
## 6 屏東縣 15 良好 Good
aqi_summary <- aqi %>%
group_by(county) %>%
summarise(
mean_AQI = mean(aqi, na.rm = TRUE),
mean_PM25 = mean(`pm2.5`, na.rm = TRUE)
) %>%
arrange(desc(mean_AQI))
## Warning: There were 22 warnings in `summarise()`.
## The first warning was:
## ℹ In argument: `mean_PM25 = mean(pm2.5, na.rm = TRUE)`.
## ℹ In group 1: `county = "南投縣"`.
## Caused by warning in `mean.default()`:
## ! argument is not numeric or logical: returning NA
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 21 remaining warnings.
head(aqi_summary)
## # A tibble: 6 × 3
## county mean_AQI mean_PM25
## <chr> <dbl> <dbl>
## 1 連江縣 150 NA
## 2 嘉義市 77.5 NA
## 3 高雄市 70.5 NA
## 4 雲林縣 67.2 NA
## 5 臺南市 64.2 NA
## 6 屏東縣 61.8 NA
ggplot(aqi_summary, aes(x = reorder(county, mean_AQI), y = mean_AQI)) +
geom_col() +
coord_flip() +
labs(title = "各縣市平均 AQI",
x = "縣市",
y = "平均 AQI")
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_col()`).
# 修正數據格式
aqi <- aqi %>%
mutate(pm2.5 = as.numeric(pm2.5),
longitude = as.numeric(longitude),
latitude = as.numeric(latitude))
## Warning: There was 1 warning in `mutate()`.
## ℹ In argument: `pm2.5 = as.numeric(pm2.5)`.
## Caused by warning:
## ! NAs introduced by coercion
ggplot(aqi, aes(x = longitude, y = latitude, color = pm2.5)) +
geom_point(size = 3) +
scale_color_gradient(low = "blue", high = "red") +
labs(title = "全台 PM2.5 測站分布圖",
x = "經度",
y = "緯度",
color = "PM2.5") +
theme_minimal()
根據平均 AQI 的結果顯示,不同縣市的空氣品質存在差異。例如部分工業較密集或位於中南部平原地區的縣市,平均 AQI 可能偏高;而其他地區則因地形與風場條件,污染物較易擴散。
PM2.5 的分級結果顯示,多數測站落在「良好」或「普通」的範圍,但在部分時段或地區,仍會出現「對敏感族群不健康」的情況,提醒民眾與相關單位仍需重視空氣品質管理與防護措施。
本分析僅以單一時間或短期資料為主,尚不足以對季節變化或長期趨勢做出結論,未來若能結合更多時間點及氣象資料,將可進行更完整的時間序列與因果分析。
本報告示範了如何使用 R Markdown 與 R 語言:
透過這些練習,不僅熟悉了本學期所學之 R 語言語法與工具,也更加理解空氣品質指標在實務上的應用方式。
sessionInfo()
## R version 4.4.2 (2024-10-31 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 26100)
##
## Matrix products: default
##
##
## locale:
## [1] LC_COLLATE=Chinese (Traditional)_Taiwan.utf8
## [2] LC_CTYPE=Chinese (Traditional)_Taiwan.utf8
## [3] LC_MONETARY=Chinese (Traditional)_Taiwan.utf8
## [4] LC_NUMERIC=C
## [5] LC_TIME=Chinese (Traditional)_Taiwan.utf8
##
## time zone: Asia/Taipei
## tzcode source: internal
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] ggplot2_3.5.2 dplyr_1.1.4 readr_2.1.6
##
## loaded via a namespace (and not attached):
## [1] bit_4.6.0 gtable_0.3.6 jsonlite_1.9.1 crayon_1.5.3
## [5] compiler_4.4.2 tidyselect_1.2.1 parallel_4.4.2 jquerylib_0.1.4
## [9] scales_1.3.0 yaml_2.3.10 fastmap_1.2.0 R6_2.6.1
## [13] labeling_0.4.3 generics_0.1.4 knitr_1.50 tibble_3.2.1
## [17] munsell_0.5.1 bslib_0.9.0 pillar_1.10.1 tzdb_0.5.0
## [21] rlang_1.1.5 utf8_1.2.4 cachem_1.1.0 xfun_0.51
## [25] sass_0.4.9 bit64_4.6.0-1 cli_3.6.4 withr_3.0.2
## [29] magrittr_2.0.3 digest_0.6.37 grid_4.4.2 vroom_1.6.6
## [33] rstudioapi_0.17.1 hms_1.1.4 lifecycle_1.0.4 vctrs_0.6.5
## [37] evaluate_1.0.3 glue_1.8.0 farver_2.1.2 colorspace_2.1-1
## [41] rmarkdown_2.29 tools_4.4.2 pkgconfig_2.0.3 htmltools_0.5.8.1