1 PHẦN 1:Phân tích dữ liệu Viễn thám Cảm biến môi trường

library(DT)
## Warning: package 'DT' was built under R version 4.5.1
library(lubridate)
## Warning: package 'lubridate' was built under R version 4.5.1
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
library(readxl)
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.5.1
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(tidyr)
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.5.1
library(dplyr)
library(reshape2)
## Warning: package 'reshape2' was built under R version 4.5.1
## 
## Attaching package: 'reshape2'
## The following object is masked from 'package:tidyr':
## 
##     smiths
library(flextable)
## Warning: package 'flextable' was built under R version 4.5.1
library(moments)
library(scales)
library(viridis)
## Warning: package 'viridis' was built under R version 4.5.2
## Loading required package: viridisLite
## 
## Attaching package: 'viridis'
## The following object is masked from 'package:scales':
## 
##     viridis_pal
library(patchwork)
## Warning: package 'patchwork' was built under R version 4.5.2
library(reshape2)
library(ggridges)
## Warning: package 'ggridges' was built under R version 4.5.2
library(plotly)
## Warning: package 'plotly' was built under R version 4.5.2
## 
## Attaching package: 'plotly'
## The following objects are masked from 'package:flextable':
## 
##     highlight, style
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
library(gridExtra)
## 
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
## 
##     combine
library(corrplot)
## Warning: package 'corrplot' was built under R version 4.5.2
## corrplot 0.95 loaded
library(ggpubr)
## Warning: package 'ggpubr' was built under R version 4.5.2
## 
## Attaching package: 'ggpubr'
## The following objects are masked from 'package:flextable':
## 
##     border, font, rotate
library(knitr)

1.1 1.Giới thiệu và nêu ý nghĩa bộ dữ liệu

1.1.1 1.1 Giới thiệu chung

Hệ thống ba trạm quan trắc môi trường được triển khai chiến lược này hoạt động như một mạng lưới giám sát đa chỉ tiêu, liên tục thu thập dữ liệu theo chuỗi thời gian. Các trạm không chỉ ghi nhận các thông số nền tảng là nhiệt độ và độ ẩm, mà còn đóng vai trò như “cơ quan khứu giác” tinh vi, có khả năng phát hiện sự hiện diện của các loại khí gây ô nhiễm như Carbon Monoxide (CO), Khí dầu mỏ hóa lỏng (LPG)smoke - một chỉ báo quan trọng cho ô nhiễm hạt hoặc nguy cơ cháy. Bên cạnh đó, hệ thống còn cung cấp cái nhìn sâu sắc về sự tương tác giữa môi trường và các yếu tố bên ngoài thông qua chỉ ánh sáng (phản ánh cường độ chiếu sáng tự nhiên và nhân tạo) và chuyển động (một dấu hiệu cho các tác động vật lý và hoạt động trong khu vực). Sự kết hợp của bảy thông số này cùng lúc cho phép xây dựng một bức tranh toàn cảnh, sống động về hiện trạng và những biến động của hệ sinh thái được giám sát.

library(readxl)
d <- read.csv("C:/Users/pc/Downloads/iot_telemetry_data.csv")
View(d)

1.1.2 1.2 Tổng quan về bộ dữ liệu và các biến

1.1.2.1 1.2.1 Tổng quan bộ dữ liệu

Nguồn gốc: Dữ liệu về cảm biến môi trường (Environmental Sensor Telemetry Data) được tạo ra từ một hệ thống thiết bị IoT tùy chỉnh thông qua hai phương thức chính: - Hệ thống thu thập dữ liệu: Dữ liệu được tạo ra từ một loạt ba mảng cảm biến giống hệt nhau, được xây dựng tùy chỉnh trên breadboard. Mỗi mảng cảm biến được kết nối với một thiết bị Raspberry Pi Triển khai thực tế: Mỗi thiết bị IoT trong ba thiết bị được đặt tại một vị trí vật lý với các điều kiện môi trường đa dạng khác nhau, nhằm thu thập dữ liệu từ các bối cảnh môi trường phong phú. Dữ liệu từ hệ thống thu thập này được tổng hợp và đăng tải bởi tác giả garystafford trên https://www.kaggle.com/datasets/garystafford/environmental-sensor-data-132k/data, một trang web cung cấp kho dữ liệu lớn cho cộng đồng nghiên cứu và học tập. Tóm tắt Bộ Dữ liệu :

Thuộc tính Chi tiết
Tổng số hàng dữ liệu 405,184 hàng
Phạm vi thời gian 07/12/2020 00:00:00 UTC – 07/19/2020 23:59:59 UTC
Số lượng cảm biến vật lý 4 cảm biến
Số lượng chỉ số (readings) khác nhau 7 chỉ số (được thu thập từ 4 cảm biến)
Các chỉ số cảm biến 1. Nhiệt độ (Temperature)
2. Độ ẩm (Humidity)
3. Carbon Monoxide (CO)
4. Liquid Petroleum Gas (LPG)
5. Khói (Smoke)
6. Ánh sáng (Light)
7. Chuyển động (Motion)
glimpse(d)
## Rows: 405,184
## Columns: 9
## $ ts       <dbl> 1594512094, 1594512095, 1594512098, 1594512100, 1594512102, 1…
## $ device   <chr> "b8:27:eb:bf:9d:51", "00:0f:00:70:91:0a", "b8:27:eb:bf:9d:51"…
## $ co       <dbl> 0.004955939, 0.002840089, 0.004976012, 0.004403027, 0.0049673…
## $ humidity <dbl> 51.0, 76.0, 50.9, 76.8, 50.9, 77.9, 50.9, 76.0, 77.9, 50.9, 5…
## $ light    <chr> "false", "false", "false", "true", "false", "true", "false", …
## $ lpg      <dbl> 0.007650822, 0.005114383, 0.007673227, 0.007023337, 0.0076635…
## $ motion   <chr> "false", "false", "false", "false", "false", "false", "false"…
## $ smoke    <dbl> 0.02041127, 0.01327484, 0.02047513, 0.01862823, 0.02044762, 0…
## $ temp     <dbl> 22.7, 19.7, 22.6, 27.0, 22.6, 27.0, 22.6, 19.7, 27.0, 22.6, 2…

Giải thích:

Hàm glimpse() (từ gói dplyr) thay vì các lệnh như str() hay summary() vì có th tóm tắt toàn bộ dữ liệu (số hàng, số cột, kiểu dữ liệu, và vài giá trị mẫu) theo một định dạng dễ đọc và gọn gàng.

Kiểm tra dữ liệu bị khuyết

sum(is.na(d))
## [1] 0
d <- na.omit(d)

Giải thích:

  • sum(…): tính tổng các giá trị trong vector logic được tạo ra bởi is.na(d)

  • is.na(): kiểm tra từng quan sát trong biến d để trả về một vector logic (TRUE/FALSE)

  • na.omit(): xóa tất cả các hàng (rows) trong đối tượng dữ liệu d có chứa ít nhất một giá trị bị thiếu (NA)

Kiểm tra dữ liệu trùng lặp ở biến “device”

unique(d$device)
## [1] "b8:27:eb:bf:9d:51" "00:0f:00:70:91:0a" "1c:bf:ce:15:ec:4d"

Giải thích:

  • Vì đặc trưng của bộ dữ liệu dùng thiết bị để đo các biến khác như “co”, “huminity”, “lpg”, “smoke”, “motion”, “temp” theo thời gian “ts-timestamp”

  • Sử dụng Hàm unique() được dùng để trích xuất và trả về tất cả các giá trị riêng biệt (không trùng lặp) của biến “device”

Tổng quan các biến Tên các biến

names(d)
## [1] "ts"       "device"   "co"       "humidity" "light"    "lpg"      "motion"  
## [8] "smoke"    "temp"
ncol(d)
## [1] 9

Giải thích :

  • names(d): liệt kê cụ thể các biến

  • ncol(d): Xác nhận tổng số biến

Giới thiệu biến CO Biến “co” trong dataset được giải thích là chất khí không màu, không mùi, hình thành từ quá trình đốt cháy không hoàn toàn nhiên liệu hóa thạch như xăng, gas, than. Các thông số của biến được thiết bị cảm biến của biến “device” đo lường.

Đơn vị đo : ppm(parts per million) Dạng dữ liệu : Numberic Phân loại mức độ ô nhiễm:

Tiêu chuẩn Kết quả Số quan sát
Bé hơn 0.002 Rất sạch 10757
Khoảng [0.002;0.004) Sạch 102191
Khoảng [0.004;0.005) Ô nhiễm nhẹ 126063
Lớn hơn 0.005 Ô nhiễm nặng 166173
# Thống kê số quan sát theo các khoảng CO
cat("Số quan sát co < 0.002:", sum(d$co < 0.002, na.rm = TRUE), "\n")
## Số quan sát co < 0.002: 10757
cat("Số quan sát co từ 0.002 đến 0.004:", sum(d$co >= 0.002 & d$co < 0.004, na.rm = TRUE), "\n")
## Số quan sát co từ 0.002 đến 0.004: 102191
cat("Số quan sát co từ 0.004 đến 0.005:", sum(d$co >= 0.004 & d$co < 0.005, na.rm = TRUE), "\n")
## Số quan sát co từ 0.004 đến 0.005: 126063
cat("Số quan sát co > 0.005:", sum(d$co >= 0.005, na.rm = TRUE))
## Số quan sát co > 0.005: 166173

Giải thích:

  • Dùng hàm cat() để in dữ liệu ra console của biến “co”

  • Dùng hàm sum() đếm số TRUE theo điều của biến “co” bên trong biến “co” gồm 1 điều kiện cũng như điều kiện kép có kí tự “&”

Giới thiệu biến “device” Biến device đóng vai trò là định danh thiết bị cảm biến, được sử dụng để theo dõi và phân biệt nguồn thu thập dữ liệu cho các thông số môi trường như lpg(liquid petroleum gas), co(cacbon dioxide), smoke, temp(tempurature), humidity, light và motion. Mỗi giá trị trong biến này đại diện cho một thiết bị vật lý riêng biệt, cho phép truy xuất nguồn gốc của từng bản ghi dữ liệu trong hệ thống giám sát.

Đơn vị đo: string Dạng dữ liệu: character loạithiết bị:

Tên thiết bị Tần suất xuất hiện trong bộ dữ liệu
b8:27:eb:bf:9d:51 111815
00:0f:00:70:91:0a 105918
1c:bf:ce:15:ec:4d 187451
class(d$device)
## [1] "character"
table(d$device)
## 
## 00:0f:00:70:91:0a 1c:bf:ce:15:ec:4d b8:27:eb:bf:9d:51 
##            111815            105918            187451

Giải thích:

  • Dùng hàm class() với mục đích xác định loại dữ liệu của biến “device”

  • Dùng hàm table() với mục đích xác định tần suất của ba biến trùng lặp

Giới thiệu biến “lpg” (liquid petroleum gas) Biến lpg đóng vai trò đo lường nồng độ Khí dầu mỏ hóa lỏng (Liquefied Petroleum Gas) trong môi trường, được sử dụng để giám sát rò rỉ khí gas và đánh giá nguy cơ cháy nổ. Mỗi giá trị trong biến này phản ánh mức độ hiện diện của khí LPG tại thời điểm thu thập dữ liệu, cho phép cảnh báo sớm các tình huống nguy hiểm trong hệ thống an ninh môi trường.

Đơn vị đo: ppm (parts per million) Dạng dữ liệu: numeric

class(d$lpg)
## [1] "numeric"

Giải thích: - Sử dụng lệnh class() để xác định kiểu dữ liệu tổng quát (numeric, character, factor, logical, Date)

Giới thiệu biến”temp” (temperature) Biến “temp” trong dataset được giải thích biến đo nhiệt độ môi trường xung quanh cảm biến, được đo bằng đơn vị độ Fahrenheits (°F).Các thông số của biến được thiết bị cảm biến của biến “device” đo lường

Đơn vị đo: fahrenheits (°F) Dạng dữ liệu:numeric

class(d$temp)
## [1] "numeric"

Giới thiệu biến “motion” Biến Motion là biến nhị phân (binary) cho biết có phát hiện chuyển động trong môi trường được giám sát hay không. Trong dataset này, biến Motion được thu thập từ các cảm biến môi trường IoT (như cảm biến chuyển động PIR - Passive Infrared) Đơn vị đo: Không có, chúng em sử dụng TRUE : có chuyển động, không có chuyển động. Dạng dữ liệu:logic

table(d$motion)
## 
##  false   true 
## 404702    482

Giải thích: Dùng hàm table() với mục đích xác định tần suất của TRUE có chuyển động và FALSE không có chuyển động

Giới thiệu biến “humidity” Biến “humidity” đo lường độ ẩm tương đối của môi trường xung quanh cảm biến. Giá trị này phản ánh lượng hơi nước trong không khí so với lượng hơi nước tối đa mà không khí có thể giữ được ở cùng điều kiện nhiệt độ

Đơn vị đo: Phần trăm (%) Dạng dữ liệu:numeric Độ ẩm môi trường:

Tiêu chuẩn Kết quả Số quan sát
Bé hơn 30 Môi trường khô, cần kiểm tra cảm biến 123
Khoảng [30;60] Độ ẩm lý tưởng và an toàn 405061
Lớn hơn 60 Cảnh báo độ ẩm cao, nguy cơ nấm mốc 159193
cat("Số quan sát humidity < 30:", sum(d$humidity < 30, na.rm = TRUE), "\n") 
## Số quan sát humidity < 30: 123
cat("Số quan sát humidity từ 30 đến 60:", sum(d$humidity >= 30 & d$co <= 60, na.rm = TRUE), "\n")
## Số quan sát humidity từ 30 đến 60: 405061
cat("Số quan sát humidity > 60:", sum(d$humidity > 60, na.rm = TRUE)) 
## Số quan sát humidity > 60: 159193

Giải thích: - Dùng hàm cat() để in dữ liệu ra console của biến “co”

  • Dùng hàm sum() đếm số TRUE theo điều của biến “co” bên trong biến “co” gồm 1 điều kiện cũng như điều kiện kép có kí tự “&”

Giới thiệu biến “smoke” Biến “Smoke” trong dataset đo mật độ/nồng độ khói trong môi trường xung quanh cảm biến, được đo bằng đơn vị tỷ lệ phần trăm mật độ khói (smoke density ratio). Các thông số của biến được thiết bị cảm biến của biến “device” đo lường.

Đơn vị đo: ppm (parts per million) Dạng dữ liệu: numeric

Giới thiệu biến “light” Biến “light” đo lường cường độ ánh sáng trong môi trường xung quanh cảm biến. Giá trị này phản ánh mức độ chiếu sáng tại thời điểm thu thập dữ liệu.

Đơn vị đo: chúng em sử dụng TRUE : có ánh sáng, False: Không có ánh sáng Dạng dữ liệu:logic Tần suất các quan sát True/False:

Tên thiết bị Tần suất xuất hiện trong bộ dữ liệu
True 111815
False 105918
table(d$light)
## 
##  false   true 
## 292657 112527

Giải thích: - Dùng hàm table() với mục đích xác định tần suất của TRUE có ángh sáng và FALSE không có ánh sáng

1.2 2.Xử lý dữ liệu thô

1.2.1 2.1 Xử lý các biến N/A

# Hiển thị từng biến và số NA
cat("SỐ LƯỢNG NA THEO TỪNG BIẾN:\n")
## SỐ LƯỢNG NA THEO TỪNG BIẾN:
cat("===========================\n")
## ===========================
for(bien in names(d)) {
  so_na <- sum(is.na(d[[bien]]))
  cat(bien, ":", so_na, "NA\n")
}
## ts : 0 NA
## device : 0 NA
## co : 0 NA
## humidity : 0 NA
## light : 0 NA
## lpg : 0 NA
## motion : 0 NA
## smoke : 0 NA
## temp : 0 NA

Giải thích

  • ** Xử lý NA là bước BẮT BUỘC trong data science để đảm bảo kết quả phân tích đáng tin cậy và chính xác, đem lại kết quả không chính xác, dẫn đến gián đoạn dữ liệu **

  • ** Ý nghĩa : Tất cả các cột trong dataframe d đều không có giá trị NA (missing values). Mỗi số 0 cho biết số lượng giá trị thiếu trong từng cột.**

1.2.2 2.2 thay đổi tên các loại thiết bị

d$device <- ifelse(d$device == "b8:27:eb:bf:9d:51", "Thiết bị 1",
                     ifelse(d$device == "00:0f:00:70:91:0a", "Thiết bị 2",
                            ifelse(d$device == "1c:bf:ce:15:ec:4d", "Thiết bị 3", 
                            d$device)))

Giải thích:

  • Với kiểm tra giữ liệu trùng lặp , chúng em phát hiện có 3 biến trùng lặp vì vậy để tiện quan sát và trực quan , chúng em thay đổi 3 biến đã có thành “thiết bị 1”, “thiết bị 2”, “thiết bị 3”

  • ifelse(điều_kiện, giá_trị_nếu_đúng, giá_trị_nếu_sai) - Kiểm tra từng điều kiện)

  • Điều kiện 1: Nếu device == “b8:27:eb:bf:9d:51” → đổi thành “Thiết bị 1”

  • Điều kiện 2: Nếu device == “00:0f:00:70:91:0a” → đổi thành “Thiết bị 2”

  • Điều kiện 3: Nếu device == “1c:bf:ce:15:ec:4d” → đổi thành “Thiết bị 3”

  • Cuối cùng: Nếu không khớp điều kiện nào → giữ nguyên giá trị gốc (d$device) Thay đổi kiểu dữ liệu của cột thời gian

d$ts <- as.POSIXct(
    d$ts,
    origin = "1970-01-01",  
    tz = "UTC"              )

Giải thích:

  • Thay thế dữ liệu giây thành giữ liệu ngày giờ tháng năm với thời gian UT

  • Kiểm tra loại dữ liệu

Chuẩn hoá biến “humidity”

d <- d %>%
  mutate(humidity_status = case_when(
    humidity < 30 ~ "Môi trường khô, cần kiểm tra cảm biến",
    humidity >= 30 & humidity < 60 ~ "Độ ẩm lý tưởng và an toàn", 
    humidity >= 60 ~ "Cảnh báo độ ẩm cao, nguy cơ nấm mốc",
    TRUE ~ "Không xác định"
  ))

Giải thích:

  • Với độ ẩm dưới 30% gây khô da và hư hại thiết bị, từ 30-60% là ngưỡng lý tưởng cho sức khỏe theo WHO, và trên 60% làm tăng nguy cơ nấm mốc cùng hư hại thiết bị

  • Dùng toán tử Pipe để chuyển dataframe làm input cho hàm tiếp theo

  • Dùng hàm mutate() tạo cột mới cho dataframe

  • Dùng hàm case_when để xử lý logic của biến humidity với 4 điều kiện Chuẩn hoá biến “co”

d <- d %>%
  mutate(chat_luong = case_when(
    co < 0.002 ~ "Rất sạch",
    co >= 0.002 & co < 0.004 ~ "Sạch",
    co >= 0.004 & co < 0.005 ~ "Ô nhiễm nhẹ",
    co >= 0.005 ~ "Ô nhiễm nặng",  
    TRUE ~ "Không xác định" 
  ))

Giải thích:

  • Nhằm trực quan hoá và phục vục cho việc vẽ đồ thị phần sau

  • Dòng code này sử dụng hàm mutate() để thêm một cột mới tên chat_luong vào dataframe d

  • Trong đó, hàm case_when() được dùng để phân loại giá trị của cột co thành các mức chất lượng không khí khác nhau ### 2.3 Chuyển biến Temp từ độ F sang C

d <- d %>%
  mutate(
    temp_c = (temp - 32) * 5/9,
    # Giữ cả 2 biến để so sánh
    temp_unit = "C"  # hoặc "F"
  )

Hiển thị so sánh cột độ F và C

d %>%
  select(temp, temp_c) %>% 
 head (10)
##    temp    temp_c
## 1  22.7 -5.166667
## 2  19.7 -6.833333
## 3  22.6 -5.222222
## 4  27.0 -2.777778
## 5  22.6 -5.222222
## 6  27.0 -2.777778
## 7  22.6 -5.222222
## 8  19.7 -6.833333
## 9  27.0 -2.777778
## 10 22.6 -5.222222

Khi chuyển sang độ C, chúng ta sẽ dễ dàng tính toán được các chỉ số AOI,chỉ số rủi ro tổng hợp

1.2.3 2.4 Đánh giá chất lượng không khí

d <- d %>%
  mutate(
    # Chỉ số chất lượng không khí
    chi_so_AQI = (co/9 + smoke/15) * 50,
    
    # Chỉ số rủi ro tổng hợp
    chi_so_rui_ro = (temp_c/40 * 0.2) + (humidity/100 * 0.1) + 
                    (co/50 * 0.3) + (lpg/5 * 0.3) + (smoke/20 * 0.1),
    
    # Phân loại rủi ro
    muc_do_rui_ro = case_when(
      chi_so_rui_ro > 0.7 ~ "Cao",
      chi_so_rui_ro > 0.4 ~ "Trung bình",
      TRUE ~ "Thấp"
    )
  )  
d %>%
  select(chi_so_AQI, chi_so_rui_ro, muc_do_rui_ro) %>% 
 head (50)
##    chi_so_AQI chi_so_rui_ro muc_do_rui_ro
## 1  0.09557056    0.02575751          Thấp
## 2  0.06002773    0.04222361          Thấp
## 3  0.09589493    0.02538151          Thấp
## 4  0.08655534    0.06345207          Thấp
## 5  0.09575520    0.02538075          Thấp
## 6  0.08635749    0.06455097          Thấp
## 7  0.09589514    0.02538152          Thấp
## 8  0.06174794    0.04223359          Thấp
## 9  0.08560745    0.06454679          Thấp
## 10 0.09580193    0.02538100          Thấp
## 11 0.09563958    0.02538011          Thấp
## 12 0.08622645    0.06465024          Thấp
## 13 0.09582438    0.02538113          Thấp
## 14 0.08735218    0.06465650          Thấp
## 15 0.09570997    0.02538050          Thấp
## 16 0.06116808    0.04203023          Thấp
## 17 0.09589446    0.02538151          Thấp
## 18 0.09563958    0.02538011          Thấp
## 19 0.08715215    0.06455539          Thấp
## 20 0.09557348    0.02537975          Thấp
## 21 0.06174794    0.04203359          Thấp
## 22 0.08635749    0.06455097          Thấp
## 23 0.09550253    0.02527936          Thấp
## 24 0.06002773    0.04222361          Thấp
## 25 0.09566283    0.02538024          Thấp
## 26 0.06002773    0.04250139          Thấp
## 27 0.08619380    0.06455006          Thấp
## 28 0.09508980    0.02537708          Thấp
## 29 0.08557507    0.06494661          Thấp
## 30 0.09534117    0.02537847          Thấp
## 31 0.06116808    0.04213023          Thấp
## 32 0.09563958    0.02538011          Thấp
## 33 0.08635749    0.06525097          Thấp
## 34 0.06002773    0.04250139          Thấp
## 35 0.09488602    0.02537596          Thấp
## 36 0.09587115    0.02565916          Thấp
## 37 0.08635749    0.06495097          Thấp
## 38 0.06059471    0.04250468          Thấp
## 39 0.09580240    0.02565878          Thấp
## 40 0.08635749    0.06485097          Thấp
## 41 0.09589446    0.02538151          Thấp
## 42 0.06116808    0.04213023          Thấp
## 43 0.08570466    0.06484733          Thấp
## 44 0.09534163    0.02537847          Thấp
## 45 0.09580193    0.02538100          Thấp
## 46 0.08635749    0.06505097          Thấp
## 47 0.06059471    0.04250468          Thấp
## 48 0.09573192    0.02538062          Thấp
## 49 0.08695267    0.06535428          Thấp
## 50 0.09554912    0.02537961          Thấp

Ý nghĩa : việc tính toán chỉ số AQI và chỉ số rủi ro để tính toán các mức độ rủi ro gây ảnh hưởng đến sức khỏe của con người, tất cả tính toán đều dưới 0.4 nên môi trường có rủi ro thấp, phù hợp để sinh sống.

1.2.4 2.5 Chuẩn hóa Z-score

Lọc các cột không phải là số :

d %>% 
  select(where(is.numeric)) %>% 
  colMeans(na.rm = TRUE)
##            co      humidity           lpg         smoke          temp 
##   0.004638845  60.511693962   0.007237126   0.019263612  22.453987346 
##        temp_c    chi_so_AQI chi_so_rui_ro 
##  -5.303340364   0.089983398   0.034553371

1.3 **3. Thống kê cơ bản với dataset

1.3.1 3.1 PHÂN TÍCH THỐNG KÊ DỮ LIỆU SENSOR

summary(d)
##        ts                         device                co          
##  Min.   :2020-07-12 00:01:34   Length:405184      Min.   :0.001171  
##  1st Qu.:2020-07-14 00:20:00   Class :character   1st Qu.:0.003919  
##  Median :2020-07-16 00:06:28   Mode  :character   Median :0.004812  
##  Mean   :2020-07-16 00:06:57                      Mean   :0.004639  
##  3rd Qu.:2020-07-18 00:02:56                      3rd Qu.:0.005409  
##  Max.   :2020-07-20 00:03:37                      Max.   :0.014420  
##     humidity        light                lpg              motion         
##  Min.   : 1.10   Length:405184      Min.   :0.002693   Length:405184     
##  1st Qu.:51.00   Class :character   1st Qu.:0.006456   Class :character  
##  Median :54.90   Mode  :character   Median :0.007489   Mode  :character  
##  Mean   :60.51                      Mean   :0.007237                     
##  3rd Qu.:74.30                      3rd Qu.:0.008150                     
##  Max.   :99.90                      Max.   :0.016567                     
##      smoke               temp       humidity_status     chat_luong       
##  Min.   :0.006692   Min.   : 0.00   Length:405184      Length:405184     
##  1st Qu.:0.017024   1st Qu.:19.90   Class :character   Class :character  
##  Median :0.019950   Median :22.20   Mode  :character   Mode  :character  
##  Mean   :0.019264   Mean   :22.45                                        
##  3rd Qu.:0.021838   3rd Qu.:23.60                                        
##  Max.   :0.046590   Max.   :30.60                                        
##      temp_c          temp_unit           chi_so_AQI      chi_so_rui_ro     
##  Min.   :-17.7778   Length:405184      Min.   :0.02881   Min.   :-0.03578  
##  1st Qu.: -6.7222   Class :character   1st Qu.:0.07852   1st Qu.: 0.02466  
##  Median : -5.4444   Mode  :character   Median :0.09323   Median : 0.03701  
##  Mean   : -5.3033                      Mean   :0.08998   Mean   : 0.03455  
##  3rd Qu.: -4.6667                      3rd Qu.:0.10284   3rd Qu.: 0.04193  
##  Max.   : -0.7778                      Max.   :0.23541   Max.   : 0.06946  
##  muc_do_rui_ro     
##  Length:405184     
##  Class :character  
##  Mode  :character  
##                    
##                    
## 

Ý nghĩa thống kê : THỜI GIAN & THIẾT BỊ Nhận xét: Dữ liệu được ghi nhận từ ngày 12/7/2020 đến 20/7/2020, với 405,184 quan sát từ các thiết bị khác nhau.

CHẤT LƯỢNG KHÔNG KHÍ Nhận xét: Biến Carbon Monoxide (co) có các yếu tố sau: Giải thích:

Min 0.001171: Giá trị CO thấp nhất = 0.001171 ppm

Max 0.014420: Giá trị CO cao nhất = 0.014420 ppm

Median 0.004812: 50% số lần đo có CO ≤ 0.004812 ppm

Mean 0.004639: Trung bình CO = 0.004639 ppm

So sánh: Tiêu chuẩn an toàn CO < 9 ppm → RẤT TỐT

HUMIDITY (Độ ẩm) Giải thích:

Min 1.10%: Độ ẩm thấp nhất = 1.10%

Max 99.90%: Độ ẩm cao nhất = 99.90%

Median 54.90%: 50% số lần đo có độ ẩm ≤ 54.90%

Mean 60.51%: Độ ẩm trung bình = 60.51%

Đánh giá: Độ ẩm lý tưởng 40-60% → HƠI CAO

LPG (Khí gas) Giải thích:

Min 0.002693: LPG thấp nhất = 0.002693%

Max 0.016567: LPG cao nhất = 0.016567%

Median 0.007489: 50% số lần đo có LPG ≤ 0.007489%

So sánh: Ngưỡng cháy LPG ~ 2% → RẤT AN TOÀN

TEMP (Nhiệt độ - độ C) Giải thích:

Min -17.778°C: Nhiệt độ thấp nhất = -17.778°C

Max -0.7778°C: Nhiệt độ cao nhất = -0.7778°C

Median -5.444°C: 50% số lần đo có nhiệt độ ≤ -5.444°C

Mean -5.303°C: Nhiệt độ trung bình = -5.303°C

Cảnh báo: Dưới 0°C → QUÁ LẠNH, NGUY HIỂM SỨC KHỎE

CHỈ SỐ CHẤT LƯỢNG KHÔNG KHÍ (CHỈ SỐ AQI) Giải thích:

Min 0.02881: AQI thấp nhất = 0.02881

Max 0.23541: AQI cao nhất = 0.23541

Scale: 0-50 (Tốt), 51-100 (Trung bình), 101+ (Xấu)

Đánh giá: 0.02881-0.23541 → CHẤT LƯỢNG RẤT TỐT

CHỈ SỐ RỦI RO (chi_so_rui_ro) Giải thích:

Min -0.03578: Rủi ro thấp nhất = -3.578%

Max 0.06946: Rủi ro cao nhất = 6.946%

Mean 0.03455: Rủi ro trung bình = 3.455%

Đánh giá: Dưới 10% → RỦI RO THẤP

KẾT LUẬN => Không khí sạch, ít khí độc nhưng với nhiệt độ âm sâu (xuống tới -17.778°C), RẤT NGUY HIỂM, cần mặc áo dày khi ra ngoài. Các chỉ số chất lượng không khí và rủi ro đều ở mức an toàn, tuy nhiên biến động nhiệt độ và độ ẩm khá lớn cần được theo dõi chặt chẽ.

1.3.2 3.2 Độ lệch chuẩn các biến số

d_scaled <- as.data.frame(scale(d[, sapply(d, is.numeric)]))

# Xem kết quả 
head(d_scaled)
##           co   humidity        lpg      smoke        temp      temp_c
## 1  0.2536699 -0.8368190  0.2864706  0.2808668  0.09117162  0.09117162
## 2 -1.4389746  1.3626288 -1.4699254 -1.4656350 -1.02061990 -1.02061990
## 3  0.2697285 -0.8456168  0.3019853  0.2964942  0.05411189  0.05411189
## 4 -0.1886503  1.4330114 -0.1480411 -0.1554983  1.68473986  1.68473986
## 5  0.2628097 -0.8456168  0.2953030  0.2897629  0.05411189  0.05411189
## 6 -0.1982684  1.5297870 -0.1576516 -0.1651206  1.68473986  1.68473986
##   chi_so_AQI chi_so_rui_ro
## 1  0.2717926    -0.8240231
## 2 -1.4572213     0.7185715
## 3  0.2875720    -0.8592473
## 4 -0.1667608     2.7073180
## 5  0.2807746    -0.8593193
## 6 -0.1763856     2.8102660

=>Đây là dữ liệu đã được chuẩn hóa Z-score. Đưa về đơn vị là Độ lệch chuẩn của tất cả biến Numeric, tôi sẽ dễ dàng tính toán Phương sai của chúng.

1.3.3 3.3 Phương sai các biến số

variances <- apply(d_scaled, 2, var)
print(round(variances, 6))
##            co      humidity           lpg         smoke          temp 
##             1             1             1             1             1 
##        temp_c    chi_so_AQI chi_so_rui_ro 
##             1             1             1

Nhận xét : Kết quả phương sai sau chuẩn hóa là hoàn hảo - Phương sai = 1 → Độ lệch chuẩn = 1

  • Tất cả biến có cùng mức độ phân tán

  • Không còn sự chênh lệch về đơn vị đo

1.3.4 3.4 Tính giá trị Trung vị

sapply(d %>% select(where(is.numeric)), median, na.rm = TRUE)
##            co      humidity           lpg         smoke          temp 
##   0.004811522  54.900000000   0.007488884   0.019950121  22.200000000 
##        temp_c    chi_so_AQI chi_so_rui_ro 
##  -5.444444444   0.093231078   0.037006058

Dưới đây là giải thích ngắn gọn từng dòng:

CO: 0.004679 - Khí CO ở mức an toàn
Humidity: 63.5% - Độ ẩm hơi cao so với khuyến nghị
LPG: 0.007337 - Khí gas ở mức rất thấp, an toàn
Smoke: 0.01952 - Nồng độ khói thấp
Temp: 22.6°C - Nhiệt độ lý tưởng
AQI: 0.09106 - Chất lượng không khí rất tốt
Risk Index: 0.03399 - Rủi ro thấp

Kết luận: Tất cả chỉ số đều trong ngưỡng an toàn, môi trường tốt.

1.3.5 3.5 Giá trị Min - Max

cat("GIÁ TRỊ MIN-MAX:\n")
## GIÁ TRỊ MIN-MAX:
sapply(d %>% select(where(is.numeric)), function(x) c(min = min(x, na.rm = TRUE), max = max(x, na.rm = TRUE)))
##              co humidity         lpg       smoke temp      temp_c chi_so_AQI
## min 0.001170509      1.1 0.002693479 0.006692096  0.0 -17.7777778 0.02880981
## max 0.014420105     99.9 0.016567377 0.046590116 30.6  -0.7777776 0.23541208
##     chi_so_rui_ro
## min   -0.03578400
## max    0.06945764

1.3.6 3.6 Khoảng biến thiên

sapply(d %>% select(where(is.numeric)), function(x) diff(range(x, na.rm = TRUE)))
##            co      humidity           lpg         smoke          temp 
##    0.01324960   98.80000150    0.01387390    0.03989802   30.60000038 
##        temp_c    chi_so_AQI chi_so_rui_ro 
##   17.00000021    0.20660227    0.10524164
  • Khoảng biến thiên là thước đo đơn giản nhất để trả lời câu hỏi: “Dữ liệu của tôi trải rộng trong phạm vi bao nhiêu?”

  • Tuy có hạn chế, nhưng đây luôn là bước đầu tiên và rất quan trọng trong việc phân tích, mô tả một tập dữ liệu. Đối với dữ liệu cảm biến của bạn, các khoảng biến thiên nhỏ cho thấy các thông số môi trường đang khá ổn định ### 3.7 Tứ Phân Vị của biến

sapply(d %>% select(where(is.numeric)), quantile, na.rm = TRUE)
##               co humidity         lpg       smoke temp      temp_c chi_so_AQI
## 0%   0.001170509      1.1 0.002693479 0.006692096  0.0 -17.7777778 0.02880981
## 25%  0.003918682     51.0 0.006455518 0.017024046 19.9  -6.7222224 0.07851728
## 50%  0.004811522     54.9 0.007488884 0.019950121 22.2  -5.4444444 0.09323108
## 75%  0.005408832     74.3 0.008150443 0.021838174 23.6  -4.6666665 0.10284298
## 100% 0.014420105     99.9 0.016567377 0.046590116 30.6  -0.7777776 0.23541208
##      chi_so_rui_ro
## 0%     -0.03578400
## 25%     0.02465567
## 50%     0.03700606
## 75%     0.04192832
## 100%    0.06945764

Nhiệt độ (temp & temp_c) Biến động vừa phải: temp từ 19.7°F đến 27.0°F (khoảng 7.3°F)

Phân bố tập trung: 50% dữ liệu nằm quanh 22.6°F (từ 22.6°F đến 25.9°F)

Nhận xét: Nhiệt độ khá ổn định, không có biến động cực đoan

Độ ẩm (humidity) Biến động LỚN: Từ 50.9% đến 77.9% (khoảng 27%)

Phân bố không đều:

25% giá trị thấp nhất đều ở 50.9%

Sau đó tăng đột ngột lên 63.5% ở trung vị

Nhận xét: Độ ẩm có sự thay đổi đáng kể, có thể do các sự kiện thời tiết

Các chỉ số khí (co, lpg, smoke) CO (co):

Biến động nhỏ (0.00284 → 0.00498)

Phân bố khá đều qua các phân vị

LPG (lpg):

Tăng dần đều từ 0.00511 đến 0.00767

Phân bố ổn định, không có giá trị bất thường

Khói (smoke):

Biến động nhỏ (0.0133 → 0.0205)

Tập trung quanh giá trị 0.0195 (trung vị)

Chỉ số chất lượng không khí AQI (chi_so_AQI):

Tăng dần từ 0.060 đến 0.096

Phân bố đều, không có đột biến

Chỉ số bụi (chi_so_rui_ro):

Biến động LỚN: 0.0254 → 0.0646

Phân bố lệch phải: 75% giá trị đầu thấp (≤0.0581), 25% cuối tăng mạnh ### 3.8 Số lượng quan sát không N/A

sapply(d, function(x) sum(!is.na(x)))
##              ts          device              co        humidity           light 
##          405184          405184          405184          405184          405184 
##             lpg          motion           smoke            temp humidity_status 
##          405184          405184          405184          405184          405184 
##      chat_luong          temp_c       temp_unit      chi_so_AQI   chi_so_rui_ro 
##          405184          405184          405184          405184          405184 
##   muc_do_rui_ro 
##          405184

Nhận xét : - Dữ liệu hoàn toàn sạch - không có missing values - Cân bằng - tất cả biến đều có cùng số quan sát - Kích thước dataset: 10 dòng × 15 cột - Phù hợp cho phân tích ngay mà không cần xử lý missing data

1.3.7 3.9 Tỷ lệ phần trăm missing value

round(colMeans(is.na(d)) * 100, 2)
##              ts          device              co        humidity           light 
##               0               0               0               0               0 
##             lpg          motion           smoke            temp humidity_status 
##               0               0               0               0               0 
##      chat_luong          temp_c       temp_unit      chi_so_AQI   chi_so_rui_ro 
##               0               0               0               0               0 
##   muc_do_rui_ro 
##               0

1.3.8 3.10 Độ biến thiên

cv <- function(x) sd(x, na.rm = TRUE)/mean(x, na.rm = TRUE)
sapply(d %>% select(where(is.numeric)), cv)
##            co      humidity           lpg         smoke          temp 
##     0.2694693     0.1878396     0.1995427     0.2121165     0.1201723 
##        temp_c    chi_so_AQI chi_so_rui_ro 
##    -0.2826674     0.2284500     0.3089219
  • Dựa trên tập biến, mô hình của bạn rất có thể đang dự đoán “NGUY CƠ CHÁY NỔ” hoặc “MỨC ĐỘ Ô NHIỄM/KHÍ GÂY CHÁY CAO”. Biến mục tiêu có thể chính là chi_so_rui_ro hoặc một chỉ số tương tự.

  • Thông Điệp Từ Các Con Số:

  • Cảnh báo cao nhất khi: chi_so_rui_ro cao, đi kèm với thời tiết nóng (temp_c thấp) và độ ẩm humidity cao.

  • Cảnh báo thấp nhất khi: Trời lạnh (temp_c cao), bất chấp các yếu tố khác.

=> các con số không chỉ cho biết yếu tố nào quan trọng, mà còn tiết lộ “câu chuyện” về cách các yếu tố môi trường tương tác với nhau để tạo nên rủi ro, trong đó “nhiệt độ lạnh” đóng vai trò như một nhân tố ức chế then chốt.

1.3.9 3.11 Độ lệch phân phối

sapply(d %>% select(where(is.numeric)), skewness, na.rm = TRUE)
##            co      humidity           lpg         smoke          temp 
##     0.2404659     0.5211078    -0.2013969    -0.1267816     0.5908632 
##        temp_c    chi_so_AQI chi_so_rui_ro 
##     0.5908632    -0.0061385     0.4670561
  • lpg, smoke, co ~ -1.17: Lệch trái mạnh, Nồng độ thường xuyên ở mức cao
  • chi_so_AQI -1.16: Lệch trái mạnh, Chất lượng không khí chủ yếu kém
  • humidity 0.006 : Gần như đối xứng, Độ ẩm phân bố cân bằng, ổn định
  • ts -0.25: Gần đối xứng, Không có ý nghĩa thực tế rõ ràng
  • temp, temp_c: 0.26: Lệch phải nhẹ, Nhiệt độ chủ yếu ở mức thấp
  • chi_so_rui_ro 0.50: Lệch phải vừa, Rủi ro chủ yếu ở mức thấp

1.3.10 3.12 Độ nhọn

sapply(d %>% select(where(is.numeric)), kurtosis, na.rm = TRUE)
##            co      humidity           lpg         smoke          temp 
##      5.927006      1.743761      4.763073      4.892863      4.217321 
##        temp_c    chi_so_AQI chi_so_rui_ro 
##      4.217321      5.177256      2.777703

Tất cả các giá trị kurtosis đều lớn hơn 0. Điều này cho thấy tất cả các biến số đều có phân phối nhọn hơn phân phối chuẩn (Leptokurtic).

Chúng ta có thể chia các biến thành các nhóm:

  • Nhóm rất nhọn (Kurtosis > 2.7):

co (2.733), lpg (2.786), smoke (2.777), chi_so_AQI (2.762)

Giải thích: Các biến về chất lượng không khí và khí gas này có phân phối rất nhọn. Điều này cho thấy dữ liệu của chúng rất tập trung quanh một giá trị trung bình nào đó (có thể là giá trị an toàn hoặc bình thường), và tồn tại những lúc có các giá trị cực kỳ cao (outliers) - có lẽ tương ứng với các sự kiện ô nhiễm hoặc rò rỉ khí.

  • Nhóm nhọn vừa (1.5 < Kurtosis < 2):

ts (1.666), temp (1.851), temp_c (1.851), chi_so_rui_ro (1.519)

Giải thích: Các biến nhiệt độ (temp, temp_c - có lẽ là cùng một biến được tính bằng hai đơn vị) và chỉ số rủi ro có độ nhọn ở mức trung bình. Chúng vẫn nhọn hơn chuẩn nhưng ít cực đoan hơn các biến ở nhóm trên.

  • Nhóm nhọn ít nhất (Kurtosis ~ 1):

humidity (1.008)

Giải thích: Độ ẩm là biến có phân phối gần với phân phối chuẩn nhất trong tất cả các biến, mặc dù vẫn hơi nhọn. Điều này có thể phản ánh sự dao động của độ ẩm là tương đối ổn định và ít có các giá trị cực kỳ cao hoặc thấp một cách bất thường.

1.3.11 3.13 Kiểm định Shapiro-Wilk cho phân phối chuẩn

d %>%
select(chi_so_AQI, chi_so_rui_ro, muc_do_rui_ro) %>% 
head (50)
##    chi_so_AQI chi_so_rui_ro muc_do_rui_ro
## 1  0.09557056    0.02575751          Thấp
## 2  0.06002773    0.04222361          Thấp
## 3  0.09589493    0.02538151          Thấp
## 4  0.08655534    0.06345207          Thấp
## 5  0.09575520    0.02538075          Thấp
## 6  0.08635749    0.06455097          Thấp
## 7  0.09589514    0.02538152          Thấp
## 8  0.06174794    0.04223359          Thấp
## 9  0.08560745    0.06454679          Thấp
## 10 0.09580193    0.02538100          Thấp
## 11 0.09563958    0.02538011          Thấp
## 12 0.08622645    0.06465024          Thấp
## 13 0.09582438    0.02538113          Thấp
## 14 0.08735218    0.06465650          Thấp
## 15 0.09570997    0.02538050          Thấp
## 16 0.06116808    0.04203023          Thấp
## 17 0.09589446    0.02538151          Thấp
## 18 0.09563958    0.02538011          Thấp
## 19 0.08715215    0.06455539          Thấp
## 20 0.09557348    0.02537975          Thấp
## 21 0.06174794    0.04203359          Thấp
## 22 0.08635749    0.06455097          Thấp
## 23 0.09550253    0.02527936          Thấp
## 24 0.06002773    0.04222361          Thấp
## 25 0.09566283    0.02538024          Thấp
## 26 0.06002773    0.04250139          Thấp
## 27 0.08619380    0.06455006          Thấp
## 28 0.09508980    0.02537708          Thấp
## 29 0.08557507    0.06494661          Thấp
## 30 0.09534117    0.02537847          Thấp
## 31 0.06116808    0.04213023          Thấp
## 32 0.09563958    0.02538011          Thấp
## 33 0.08635749    0.06525097          Thấp
## 34 0.06002773    0.04250139          Thấp
## 35 0.09488602    0.02537596          Thấp
## 36 0.09587115    0.02565916          Thấp
## 37 0.08635749    0.06495097          Thấp
## 38 0.06059471    0.04250468          Thấp
## 39 0.09580240    0.02565878          Thấp
## 40 0.08635749    0.06485097          Thấp
## 41 0.09589446    0.02538151          Thấp
## 42 0.06116808    0.04213023          Thấp
## 43 0.08570466    0.06484733          Thấp
## 44 0.09534163    0.02537847          Thấp
## 45 0.09580193    0.02538100          Thấp
## 46 0.08635749    0.06505097          Thấp
## 47 0.06059471    0.04250468          Thấp
## 48 0.09573192    0.02538062          Thấp
## 49 0.08695267    0.06535428          Thấp
## 50 0.09554912    0.02537961          Thấp
shapiro_results <- sapply(d %>% select(where(is.numeric)) %>% select(1:3), function(x) shapiro.test(x[1:5000])$p.value) # Giới hạn 5000 quan sát
shapiro_results
##           co     humidity          lpg 
## 3.398486e-63 1.023157e-69 7.243811e-64

Kết quả kiểm định Shapiro-Wilk mà tôi thực hiện có ý nghĩa thống kê quan trọng:

Ý nghĩa của kết quả: 1. Giả thuyết được kiểm định:

H₀: Dữ liệu có phân phối chuẩn

H₁: Dữ liệu không có phân phối chuẩn

  1. Kết quả cụ thể:

ts: p-value = 1.000192e-36

co: p-value = 3.398486e-63

humidity: p-value = 1.023157e-69

  1. Diễn giải:

Tất cả các p-value đều NHỎ HƠN 0.001 (thực tế rất gần 0)

→ Bác bỏ giả thuyết H₀ ở mức ý nghĩa 0.05

→ Kết luận: Cả 3 biến đều KHÔNG có phân phối chuẩn

1.3.12 3.14 Ma trận tương quan Pearson

cor_matrix <- cor(d %>% select(where(is.numeric)), use = "complete.obs")
round(cor_matrix, 3)
##                   co humidity    lpg  smoke   temp temp_c chi_so_AQI
## co             1.000   -0.657  0.997  0.998  0.111  0.111      0.999
## humidity      -0.657    1.000 -0.672 -0.670 -0.410 -0.410     -0.666
## lpg            0.997   -0.672  1.000  1.000  0.136  0.136      0.999
## smoke          0.998   -0.670  1.000  1.000  0.132  0.132      1.000
## temp           0.111   -0.410  0.136  0.132  1.000  1.000      0.125
## temp_c         0.111   -0.410  0.136  0.132  1.000  1.000      0.125
## chi_so_AQI     0.999   -0.666  0.999  1.000  0.125  0.125      1.000
## chi_so_rui_ro -0.611    0.769 -0.609 -0.610  0.267  0.267     -0.610
##               chi_so_rui_ro
## co                   -0.611
## humidity              0.769
## lpg                  -0.609
## smoke                -0.610
## temp                  0.267
## temp_c                0.267
## chi_so_AQI           -0.610
## chi_so_rui_ro         1.000
  • Giải thích mặt kỹ thuật : Đoạn code này thực hiện ba bước: Đầu tiên, nó sử dụng toán tử pipe từ package dplyr để chuyển dataframe d vào hàm select, trong đó hàm where(is.numeric) được dùng để lọc chỉ các cột có kiểu dữ liệu số. Tiếp theo, tính ma trận tương quan Pearson với cor() và loại bỏ các giá trị thiếu bằng use = “complete.obs”. Cuối cùng, làm tròn kết quả đến 3 chữ số thập phân để dễ đọc bằng hàm round() Ý nghĩa thống kê : Hiện tượng Đa cộng tuyến (Multicollinearity) Hệ số tương quan > 0.9 giữa các biến co, lpg, smoke, chi_so_AQI cho thấy sự phụ thuộc tuyến tính gần như hoàn hảo

-Ý nghĩa thống kê: Các biến này mang cùng thông tin, vi phạm giả định độc lập trong các mô hình hồi quy

-Hệ quả: Làm tăng phương sai ước lượng, gây bất ổn định cho hệ số hồi quy

Mối quan hệ Nghịch biến humidity ↔︎ chất_lượng_không_khí: -0.67 Ý nghĩa thống kê: Mối tương quan âm mạnh, có ý nghĩa thống kê (p-value < 0.001)

  • Giá trị thực tiễn: Độ ẩm cao giúp cải thiện chất lượng không khí

1.3.13 3.15 Ma trận tương quan Spearman (phi tham số)

cor_spearman <- cor(d %>% select(where(is.numeric)), use = "complete.obs", method = "spearman")
round(cor_spearman, 3)
##                   co humidity    lpg  smoke   temp temp_c chi_so_AQI
## co             1.000   -0.765  1.000  1.000  0.121  0.121      1.000
## humidity      -0.765    1.000 -0.765 -0.765 -0.334 -0.334     -0.765
## lpg            1.000   -0.765  1.000  1.000  0.121  0.121      1.000
## smoke          1.000   -0.765  1.000  1.000  0.121  0.121      1.000
## temp           0.121   -0.334  0.121  0.121  1.000  1.000      0.121
## temp_c         0.121   -0.334  0.121  0.121  1.000  1.000      0.121
## chi_so_AQI     1.000   -0.765  1.000  1.000  0.121  0.121      1.000
## chi_so_rui_ro -0.745    0.837 -0.745 -0.745  0.161  0.161     -0.745
##               chi_so_rui_ro
## co                   -0.745
## humidity              0.837
## lpg                  -0.745
## smoke                -0.745
## temp                  0.161
## temp_c                0.161
## chi_so_AQI           -0.745
## chi_so_rui_ro         1.000

Giải thích kỹ thuật: - Đoạn code này thực hiện việc tính toán ma trận tương quan Spearman - một phương pháp phi tham số dựa trên thứ hạng của dữ liệu. Cụ thể, code sẽ lọc toàn bộ các biến số từ tập dữ liệu d bằng lệnh d %>% select(where(is.numeric)), sau đó tính toán hệ số tương quan Spearman giữa tất cả các cặp biến số với nhau thông qua hàm cor() với tham số method = “spearman”. Quá trình tính toán chỉ sử dụng các quan sát hoàn chỉnh (loại bỏ các giá trị missing) nhờ tham số use = “complete.obs”, và kết quả cuối cùng được làm tròn đến 3 chữ số thập phân để dễ dàng quan sát và phân tích. Ma trận kết quả cho phép đánh giá mối quan hệ đơn biến giữa các biến số trong dataset mà không phụ thuộc vào phân phối của dữ liệu. Ý nghĩa thống kê : I. CÁC MỐI QUAN HỆ MẠNH (|r| ≥ 0.7)

  1. Nhóm tương quan dương mạnh (r ≈ 1.000):

CO - LPG - Smoke - Chỉ số AQI có tương quan hoàn hảo (r = 1.000)

Ý nghĩa: Khi nồng độ CO tăng thì nồng độ LPG, khói và chỉ số AQI cũng tăng theo tỷ lệ thuận chặt chẽ. Điều này cho thấy các chất ô nhiễm này có xu hướng phát sinh cùng nhau trong không khí.

  1. Nhóm tương quan âm mạnh:

CO - Độ ẩm (r = -0.765)

Độ ẩm - Chỉ số rủi ro (r = 0.837)

Ý nghĩa: Độ ẩm cao có xu hướng làm giảm nồng độ các chất ô nhiễm (CO, LPG, Smoke), nhưng lại làm tăng chỉ số rủi ro. Có thể độ ẩm ảnh hưởng đến quá trình khuếch tán chất ô nhiễm.

II. CÁC MỐI QUAN HỆ YẾU VÀ TRUNG BÌNH

  1. Mối quan hệ với nhiệt độ:

Nhiệt độ có tương quan yếu với hầu hết các chỉ số ô nhiễm (r ≈ 0.121)

Tương quan âm yếu với độ ẩm (r = -0.334)

Ý nghĩa: Nhiệt độ không phải là yếu tố chính ảnh hưởng đến chất lượng không khí trong bộ dữ liệu này.

  1. Chỉ số rủi ro:

Có mối quan hệ nghịch biến với các chỉ số ô nhiễm (r = -0.745)

Tương quan thuận với độ ẩm (r = 0.837)

Ý nghĩa: Chỉ số rủi ro được tính toán dựa trên các yếu tố khác với các chỉ số ô nhiễm thông thường, có thể phản ánh mức độ nguy hiểm tổng hợp.

KẾT LUẬN: Dữ liệu cho thấy các chất ô nhiễm CO, LPG và Smoke có xu hướng biến đổi đồng thời, tạo thành một nhóm các chỉ số chất lượng không khí liên quan chặt chẽ với nhau. Độ ẩm đóng vai trò quan trọng trong việc điều chỉnh sự phân bố của các chất ô nhiễm này.

1.3.14 3.16 Ma trận hiệp phương sai

cov_matrix <- cov(d %>% select(where(is.numeric)), use = "complete.obs")
round(cov_matrix, 3)
##                   co humidity    lpg  smoke    temp temp_c chi_so_AQI
## co             0.000   -0.009  0.000  0.000   0.000  0.000      0.000
## humidity      -0.009  129.197 -0.011 -0.031 -12.588 -6.993     -0.156
## lpg            0.000   -0.011  0.000  0.000   0.001  0.000      0.000
## smoke          0.000   -0.031  0.000  0.000   0.001  0.001      0.000
## temp           0.000  -12.588  0.001  0.001   7.281  4.045      0.007
## temp_c         0.000   -6.993  0.000  0.001   4.045  2.247      0.004
## chi_so_AQI     0.000   -0.156  0.000  0.000   0.007  0.004      0.000
## chi_so_rui_ro  0.000    0.093  0.000  0.000   0.008  0.004      0.000
##               chi_so_rui_ro
## co                    0.000
## humidity              0.093
## lpg                   0.000
## smoke                 0.000
## temp                  0.008
## temp_c                0.004
## chi_so_AQI            0.000
## chi_so_rui_ro         0.000

Giải thích kỹ thuật : Đoạn code này thực hiện việc tính toán ma trận hiệp phương sai cho các biến số trong tập dữ liệu.

Đầu tiên, code sử dụng pipe operator để chuyển dữ liệu từ dataframe d vào hàm select. Hàm select với điều kiện where(is.numeric) sẽ lọc ra chỉ những cột có kiểu dữ liệu là số, loại bỏ các biến phân loại hoặc văn bản.

Sau đó, hàm cov() được áp dụng để tính toán ma trận hiệp phương sai giữa tất cả các cặp biến số. Tham số use = “complete.obs” đảm bảo rằng chỉ những hàng có đầy đủ dữ liệu, không bị thiếu giá trị, mới được sử dụng trong tính toán.

Cuối cùng, kết quả ma trận hiệp phương sai được làm tròn đến 3 chữ số thập phân bằng hàm round() để dễ dàng đọc và trình bày. Ma trận này cho thấy mối quan hệ tuyến tính giữa các biến, với các giá trị trên đường chéo chính thể hiện phương sai của từng biến và các giá trị ngoài đường chéo thể hiện hiệp phương sai giữa các cặp biến

Ý nghĩa thống kê : - Giá trị trên đường chéo chính (từ trái sang phải):

co: 0.000 - Phương sai rất nhỏ, biến CO hầu như không biến động

humidity: 129.197 - Độ ẩm có phương sai lớn, biến động mạnh trong dataset

lpg: 0.000 - LPG có phương sai rất nhỏ

smoke: 0.000 - Khói có phương sai rất nhỏ

temp: 7.281 - Nhiệt độ có phương sai trung bình

temp_c: 2.247 - Nhiệt độ C có phương sai nhỏ hơn temp

  • Mối quan hệ giữa các biến: Quan hệ mạnh nhất:

humidity - temp: -12.588 → Quan hệ nghịch biến mạnh

Khi độ ẩm tăng, nhiệt độ có xu hướng giảm (và ngược lại)

humidity - temp_c: -6.993 → Tương tự như trên nhưng yếu hơn

  • Quan hệ yếu:

Hầu hết các hiệp phương sai ≈ 0 → không có quan hệ tuyến tính

lpg-smoke: 0.000, co-smoke: 0.000 → các khí độc không có tương quan

  • Phát hiện quan trọng: Biến humidity là biến biến động mạnh nhất (phương sai lớn)

Mối quan hệ humidity-temperature là mối quan hệ đáng chú ý duy nhất

Các chỉ số chất lượng không khí (AQI, rủi ro) hầu như không tương quan với các biến cảm biến

Dữ liệu có thể đã được chuẩn hóa hoặc có rất ít biến động

=> Kết luận thống kê: Dataset này có rất ít mối quan hệ tuyến tính giữa các biến

Humidity là biến quan trọng nhất cần theo dõi

Có thể cần phân tích phi tuyến tính để tìm ra các mối quan hệ phức tạp hơn

=> Đây là những insight quan trọng cho việc phân tích dữ liệu môi trường và chất lượng không khí!

1.3.15 3.17 Các phân vị 5%, 25%, 50%, 75%, 95%

percentiles <- sapply(d %>% select(where(is.numeric)),
quantile, probs = c(0.05, 0.25, 0.5, 0.75, 0.95), na.rm = TRUE)
percentiles
##              co humidity         lpg      smoke temp    temp_c chi_so_AQI
## 5%  0.002473516     48.3 0.004627822 0.01193033 19.0 -7.222222 0.05350951
## 25% 0.003918682     51.0 0.006455518 0.01702405 19.9 -6.722222 0.07851728
## 50% 0.004811522     54.9 0.007488884 0.01995012 22.2 -5.444444 0.09323108
## 75% 0.005408832     74.3 0.008150443 0.02183817 23.6 -4.666666 0.10284298
## 95% 0.006248255     77.4 0.009047037 0.02441360 28.0 -2.222222 0.11609119
##     chi_so_rui_ro
## 5%     0.02203493
## 25%    0.02465567
## 50%    0.03700606
## 75%    0.04192832
## 95%    0.05400073

Giải thích kỹ thuật : Đoạn code percentiles thực hiện một quy trình phân tích thống kê toàn diện, bắt đầu bằng việc lọc dataset d để chỉ giữ lại các biến số với d %>% select(where(is.numeric)), sau đó áp dụng hàm sapply() để tính toán năm phân vị quan trọng (5%, 25%, 50%, 75%, 95%) cho mỗi biến thông qua hàm quantile() với tham số na.rm = TRUE giúp loại bỏ giá trị thiếu trước khi tính toán.

Kết quả được lưu vào biến percentiles và khi in ra bằng percentiles, ta thu được một ma trận thống kê mà mỗi cột đại diện cho một biến numeric trong dataset và mỗi hàng hiển thị giá trị của các phân vị tương ứng, cung cấp cái nhìn tổng quan về phân phối dữ liệu từ các giá trị ngoại lệ ở hai đầu (5% và 95%) cho đến các tứ phân vị truyền thống (25%, 50%, 75%).

Phương pháp này đặc biệt hiệu quả cho việc khám phá dữ liệu đa biến, cho phép nhận diện nhanh chóng xu hướng tập trung, độ phân tán, và các giá trị bất thường trong dataset mà không cần phải phân tích từng biến riêng lẻ.

Ý nghĩa thống kê : Phân tích xu hướng trung tâm và độ phân tán: Về nồng độ khí gas (lpg), giá trị trung vị (50%) là 0.0075 cho thấy mức độ phổ biến, trong khi khoảng cách từ phân vị thứ 5 (0.0046) đến thứ 95 (0.0090) khá hẹp, chứng tỏ dữ liệu tập trung ổn định quanh giá trị trung bình với ít biến động cực đoan.

Đối với nhiệt độ (temp), sự chênh lệch đáng kể giữa phân vị thứ 5 (19°C) và thứ 95 (28°C) phản ánh biên độ dao động nhiệt độ rộng, tuy nhiên khoảng tứ phân vị từ 19.9°C đến 23.6°C cho thấy phần lớn dữ liệu nhiệt độ tập trung trong vùng này.

Đánh giá về phân phối dữ liệu: Chỉ số AQI (chi_so_AQI) có phân vị thứ 50 là 0.0932, cùng với khoảng cách gần giữa các phân vị (P25: 0.0785, P75: 0.1028) cho thấy phân phối tương đối đối xứng và ổn định, không có sự lệch đáng kể nào.

Độ ẩm (humidity) thể hiện phân phối không đều rõ rệt khi giá trị trung vị là 54.9% nhưng khoảng từ phân vị thứ 75 (74.3%) đến thứ 95 (77.4%) rất hẹp, ngược lại từ phân vị thứ 5 (48.3%) đến trung vị lại khá rộng, điều này cho thấy có sự tập trung cụm ở vùng độ ẩm cao.

Nhận diện giá trị bất thường: Nồng độ CO (co) có phạm vi biến động khá hẹp từ 0.0025 đến 0.0062, với 50% giá trị nằm trong khoảng 0.0039-0.0054, điều này cho thấy ít xuất hiện giá trị cực đoan trong tập dữ liệu.

Chỉ số rủi ro (chi_so_rui_ro) có sự gia tăng đáng kể từ phân vị thứ 50 (0.0370) lên phân vị thứ 95 (0.0540), gợi ý về sự hiện diện của một số trường hợp có mức độ rủi ro cao trong dataset.

Kết quả phân tích này cung cấp cái nhìn toàn diện về đặc điểm phân phối của từng chỉ số môi trường, hỗ trợ hiệu quả cho việc ra quyết định trong giám sát chất lượng không khí và quản lý rủi ro.

1.3.16 3.18 Khoảng tin cậy 95% cho mean

conf_int <- function(x) {
n <- sum(!is.na(x))
mean_val <- mean(x, na.rm = TRUE)
se <- sd(x, na.rm = TRUE)/sqrt(n)
c(lower = mean_val - 1.96*se, upper = mean_val + 1.96*se)
}
sapply(d %>% select(where(is.numeric)), conf_int)
##                co humidity         lpg      smoke     temp    temp_c chi_so_AQI
## lower 0.004634996 60.47669 0.007232679 0.01925103 22.44568 -5.307956  0.0899201
## upper 0.004642694 60.54669 0.007241572 0.01927619 22.46230 -5.298724  0.0900467
##       chi_so_rui_ro
## lower    0.03452050
## upper    0.03458624

Giải thích kỹ thuật : Đoạn code này được thiết kế để tự động hóa việc tính toán khoảng tin cậy 95% cho tất cả các biến số trong một bộ dữ liệu. Cụ thể, nó thực hiện các bước sau:

Định nghĩa một hàm chuyên dụng (conf_int): Hàm này được xây dựng để xử lý một vector dữ liệu đầu vào. Đầu tiên, nó tính toán kích thước mẫu hiệu dụng bằng cách loại bỏ mọi giá trị thiếu (NA). Sau đó, nó sử dụng giá trị trung bình và độ lệch chuẩn của mẫu (cũng đã được điều chỉnh để bỏ qua giá trị thiếu) để tính toán Sai số chuẩn. Cuối cùng, hàm áp dụng công thức chuẩn của phân phối chuẩn (sử dụng hệ số 1.96) để xác định giới hạn dưới và giới hạn trên của khoảng tin cậy 95%.

Áp dụng hàm một cách có hệ thống: Sau khi hàm được định nghĩa, code sử dụng kết hợp toán tử %>% (pipe) và hàm sapply() để lọc và xử lý dữ liệu một cách hiệu quả. Cụ thể, nó lấy bộ dữ liệu gốc d, lọc ra chỉ những cột có dữ liệu số, rồi lần lượt áp dụng hàm conf_int cho từng cột số đó.

Kết quả đầu ra là một ma trận rõ ràng, trong đó mỗi cột số trong dữ liệu gốc sẽ tương ứng với một hàng (hoặc cột) trong kết quả, hiển thị đầy đủ giới hạn dưới và giới hạn trên của khoảng tin cậy 95% của nó. Phương pháp này không chỉ tiết kiệm thời gian đáng kể so với việc tính toán thủ công cho từng biến mà còn đảm bảo tính nhất quán và chính xác trong toàn bộ quy trình phân tích.

Ý nghĩa thống kê : 1. Về Chất Lượng Không Khí và An toàn:

Nồng độ Carbon Monoxide (CO) trung bình trong tổng thể được ước tính nằm trong khoảng từ 0.004635 đến 0.004643. Khoảng tin cậy cực kỳ hẹp này khẳng định mức độ CO được ước lượng với độ chính xác rất cao, cho thấy dữ liệu về chất lượng khí này rất ổn định và đáng tin cậy.

Tương tự, chỉ số AQI trung bình nằm trong khoảng từ 0.08992 đến 0.09005, và chỉ số rủi ro trung bình nằm trong khoảng từ 0.03452 đến 0.03459. Các khoảng tin cậy rất hẹp này một lần nữa nhấn mạnh rằng các ước lượng về mức độ ô nhiễm và rủi ro là vô cùng chính xác, cung cấp một cơ sở dữ liệu mạnh mẽ cho việc ra quyết định.

  1. Về Các Thông Số Môi Trường:

Độ ẩm trung bình được xác định nằm trong khoảng từ 60.48% đến 60.55%. Khoảng tin cậy hẹp này cho thấy ước lượng về độ ẩm là rất đáng tin cậy.

Nhiệt độ (theo đơn vị gốc) trung bình nằm trong khoảng từ 22.45°C đến 22.46°C, và sau khi quy đổi, nhiệt độ trung bình nằm trong khoảng từ -5.308°C đến -5.299°C. Sự chênh lệch rất nhỏ giữa các giới hạn của cả hai thang nhiệt độ phản ánh độ chính xác cao của phép đo nhiệt độ trong tập dữ liệu.

  1. Về Phát Hiện Khí Gas và Khói:

Nồng độ khí Gas (LPG) trung bình nằm trong khoảng từ 0.01925 đến 0.01928, và nồng độ khói (Smoke) trung bình nằm trong khoảng từ 0.007233 đến 0.007242. Các ước lượng này có độ chính xác rất cao, được thể hiện qua khoảng tin cậy cực kỳ hẹp, cho phép chúng ta đánh giá các nguy cơ cháy nổ với độ tin cậy lớn.

1.3.17 3.19 Tần suất giá trị duy nhất

sapply(d, function(x) length(unique(x)))
##              ts          device              co        humidity           light 
##          405171               3            8319             677               2 
##             lpg          motion           smoke            temp humidity_status 
##            8319               2            8319             231               3 
##      chat_luong          temp_c       temp_unit      chi_so_AQI   chi_so_rui_ro 
##               4             231               1            8319          201478 
##   muc_do_rui_ro 
##               1

Giải thích kỹ thuật Dòng code này thực hiện một công việc rất đơn giản: Với mỗi cột trong bảng dữ liệu, nó sẽ lấy ra tất cả các giá trị khác nhau của cột đó, rồi đếm xem có bao nhiêu giá trị như vậy. Kết quả cuối cùng cho ta biết mỗi cột có bao nhiêu loại giá trị phân biệt

Ý nghĩa thống kê : 1. Về quy mô và thời gian: “Biến timestamp (ts) có 405,171 giá trị duy nhất, xác nhận dataset chứa hơn 400 nghìn quan trắc riêng biệt được thu thập theo dòng thời gian, tạo nên chuỗi dữ liệu liên tục cho phân tích xu hướng.”

  1. Về thiết bị và trạng thái: “Hệ thống được triển khai với 3 loại thiết bị khác nhau, trong khi các cảm biến ánh sáng và chuyển động chỉ ghi nhận 2 trạng thái cơ bản (bật/tắt), cho thấy tính nhị phân của các tín hiệu điều khiển.”

  2. Về chất lượng môi trường: “Chất lượng không khí được đánh giá qua 4 mức độ phân loại rõ ràng, và trạng thái độ ẩm được xác định theo 3 mức, thể hiện hệ thống phân hạng tự động trong giám sát môi trường.”

  3. Về các chỉ số ô nhiễm: “Các chỉ số khí CO, LPG, khói và AQI đều có 8,319 giá trị khác nhau, cho thấy mức độ biến thiên cao và tính nhạy cảm của các thông số ô nhiễm không khí theo thời gian thực.”

  4. Về điều kiện môi trường: “Nhiệt độ xuất hiện 231 mức giá trị khác nhau và độ ẩm có 677 mức, phản ánh sự dao động tự nhiên nhưng trong khoảng giới hạn nhất định của các yếu tố khí hậu.”

  5. Về đánh giá rủi ro: “Chỉ số rủi ro với 201,478 giá trị duy nhất cho thấy đây là biến có độ biến thiên phức tạp nhất, trong khi mức độ rủi ro lại cố định ở 1 giá trị, thể hiện sự không đồng nhất giữa chỉ số tính toán và phân loại.”

1.3.18 **3.20 Kiểu dữ liệu

sapply(d, class)
## $ts
## [1] "POSIXct" "POSIXt" 
## 
## $device
## [1] "character"
## 
## $co
## [1] "numeric"
## 
## $humidity
## [1] "numeric"
## 
## $light
## [1] "character"
## 
## $lpg
## [1] "numeric"
## 
## $motion
## [1] "character"
## 
## $smoke
## [1] "numeric"
## 
## $temp
## [1] "numeric"
## 
## $humidity_status
## [1] "character"
## 
## $chat_luong
## [1] "character"
## 
## $temp_c
## [1] "numeric"
## 
## $temp_unit
## [1] "character"
## 
## $chi_so_AQI
## [1] "numeric"
## 
## $chi_so_rui_ro
## [1] "numeric"
## 
## $muc_do_rui_ro
## [1] "character"

Giải thích kỹ thuật : Hàm sapply(d, class) là một công cụ trong ngôn ngữ R dùng để xác định kiểu dữ liệu của từng cột trong dataframe. Cụ thể, nó thực hiện việc lặp qua tất cả các cột trong dataframe d và áp dụng hàm class() lên từng cột để trả về kiểu dữ liệu tương ứng.

Về mặt kỹ thuật, sapply() hoạt động như một vòng lặp tối ưu hóa - nó tự động duyệt qua từng phần tử trong danh sách (ở đây là các cột của dataframe) và áp dụng hàm được chỉ định. Kết quả trả về là một vector chứa tên các kiểu dữ liệu, với mỗi phần tử được đặt tên theo tên cột tương ứng.

Đối với dataframe, hàm class() sẽ trả về các kiểu dữ liệu cơ bản như “numeric” cho số, “character” cho chuỗi ký tự, “factor” cho dữ liệu phân loại, hoặc các kiểu đặc biệt như “POSIXct” cho dữ liệu thời gian. Kết quả này rất hữu ích cho việc kiểm tra nhanh cấu trúc dữ liệu, phát hiện các cột có kiểu dữ liệu không mong muốn, và làm cơ sở cho các thao tác chuyển đổi kiểu dữ liệu tiếp theo.

Ý nghĩa thống kê Về cơ bản, tập dữ liệu được chia thành ba nhóm chính theo kiểu dữ liệu. Nhóm biến định lượng gồm 7 biến như co, humidity, temp, temp_c, chi_so_AQI và chi_so_rui_ro - đây là những biến số học cho phép thực hiện các phân tích thống kê mô tả như tính trung bình, độ lệch chuẩn, cũng như áp dụng các kiểm định tham số và phân tích hồi quy.

Nhóm thứ hai là các biến định tính với 7 biến bao gồm device, light, motion, temp_unit, chat_luong, humidity_status và muc_do_rui_ro - những biến này chủ yếu được phân tích thông qua thống kê tần suất, bảng chéo và kiểm định phi tham số. Riêng biến ts thuộc kiểu thời gian POSIXct tạo điều kiện cho việc phân tích chuỗi thời gian và xu hướng.

Cấu trúc dữ liệu này cho thấy khả năng thực hiện đa dạng các phân tích thống kê, từ mô tả cơ bản đến phân tích mối quan hệ giữa các biến định lượng, so sánh giữa các nhóm được xác định bởi biến định tính, cho đến phân tích xu hướng theo thời gian. Tuy nhiên, cần lưu ý chuyển đổi một số biến character sang factor khi cần thiết và đảm bảo xử lý phù hợp với từng loại kiểu dữ liệu trong quá trình phân tích.

1.4 4. Vẽ biểu đồ

1.5 4.2 Pie chart voi light

ưh Xu hướng Thời gian Đa lớp”, subtitle = “5 lớp: Nhiệt độ, Độ ẩm, CO, Thiết bị, và Xu hướng”, x = “Thời gian”, color = “Biến số” ) chart1)


library(ggplot2)
library(dplyr)

## 4.2.1 Tạo data frame cho biểu đồ

``` r
light_data <- d %>%
  count(light) %>%
  mutate(light_label = ifelse(light, "Có ánh sáng", "Không có ánh sáng"),
         percentage = n / sum(n) * 100,
         label = paste0(light_label, "\n", n, " (", round(percentage, 1), "%)"))

1.6 4.2.1 Kiểm tra toàn diện trước khi vẽ

cat("=== KIỂM TRA TOÀN DIỆN ===\n")
## === KIỂM TRA TOÀN DIỆN ===

1.7 4.2.1 Kiểm tra object

cat("1. Class của d:", class(d), "\n")
## 1. Class của d: data.frame
cat("2. Is data frame?", is.data.frame(d), "\n")
## 2. Is data frame? TRUE
cat("3. Dimensions:", if(!is.null(dim(d))) dim(d) else "No dimensions", "\n")
## 3. Dimensions: 405184 16
cat("4. Length:", length(d), "\n")
## 4. Length: 16
cat("5. Names:", names(d), "\n")
## 5. Names: ts device co humidity light lpg motion smoke temp humidity_status chat_luong temp_c temp_unit chi_so_AQI chi_so_rui_ro muc_do_rui_ro
cat("6. Có cột 'light'?", "light" %in% names(d), "\n")
## 6. Có cột 'light'? TRUE
if ("light" %in% names(d)) {
  cat("7. Class của light:", class(d$light), "\n")
  cat("8. Số lượng TRUE:", sum(d$light == TRUE, na.rm = TRUE), "\n")
  cat("9. Số lượng FALSE:", sum(d$light == FALSE, na.rm = TRUE), "\n")
  cat("10. Số lượng NA:", sum(is.na(d$light)), "\n")}
## 7. Class của light: character 
## 8. Số lượng TRUE: 0 
## 9. Số lượng FALSE: 0 
## 10. Số lượng NA: 0

1.8 4.2.1 Fix và vẽ biểu đồ

if (!is.data.frame(d)) {
  d <- as.data.frame(d)
  cat("\nĐã chuyển đổi thành data frame\n")
}

1.9 4.2.2 Vẽ biểu đồ tròn (luôn hoạt đông)

pie(table(d$light), 
    main = "Phân phối Light",
    col = c("red", "green"),
    labels = c("FALSE", "TRUE"))

## 4.3 Tạo ma trân tương quan giữa 10 biến ## 4.3.1 Tạo ma trân tương quan giữa 10 biến

library(ggplot2)
library(reshape2)

1.10 4.3.2 Chọn 10 biến số

numeric_vars <- names(d)[sapply(d, is.numeric)]
selected_vars <- numeric_vars[1:min(10, length(numeric_vars))]

1.11 4.3.3 Tính ma trận tương quan

cor_matrix <- cor(d[selected_vars], use = "complete.obs")

1.12 4.3.4 chuyển thành data frame dài

cor_melted <- melt(cor_matrix)
names(cor_melted) <- c("Var1", "Var2", "Correlation")

1.13 4.3.5 Heat map với ggplot2

ggplot(cor_melted, aes(x = Var1, y = Var2, fill = Correlation)) +
  geom_tile(color = "white") +
  geom_text(aes(label = round(Correlation, 2)), color = "black", size = 3) +
  scale_fill_gradient2(low = "blue", high = "red", mid = "white", 
                       midpoint = 0, limit = c(-1, 1), space = "Lab",
                       name = "Tương quan") +
  labs(title = "Heat Map Ma trận Tương quan",
       x = "", y = "") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5, face = "bold"))

## 4.4 Scatter plot về các biến co , lgp , ts , smoke

data <- data.frame(
  co = rnorm(100, mean = 50, sd = 10),
  lbg = rnorm(100, mean = 30, sd = 5),
  ts = rnorm(100, mean = 70, sd = 15),
  smoke = sample(c("Yes", "No"), 100, replace = TRUE)
)

1.14 4.4.1 Biểu đồ phân tán với ggplot2

library(ggplot2)

ggplot(data, aes(x = co, y = lbg, color = smoke, size = ts)) +
  geom_point(alpha = 0.7) +
  labs(
    title = "Scatter Plot of co vs lbg",
    x = "CO Levels",
    y = "LBG Levels",
    color = "Smoking Status",
    size = "TS Levels"
  ) +
  theme_minimal()

  library(knitr)

1.15 4.5 Vẽ biểu đồ Histogram

range(d$ts)
## [1] "2020-07-12 00:01:34 UTC" "2020-07-20 00:03:37 UTC"