Xử lý dữ liệu missing

Tác giả: Nguyễn Hải Trường | 2019-01-15

Trong quá trình xử lý, làm sạch dữ liệu, chúng ta sẽ thường gặp phải vấn đề dữ liệu bị missing. Nguyên nhân có thể do dữ liệu không đầy đủ hoặc có sai sót trong quá trình nhập liệu… Trong bài viết này, Ranalytics sẽ hướng dẫn các bạn một số mẹo để xử lý giá trị missing (missing values) trong R.

Vậy, làm thế nào để xử lý missing values?

Câu trả lời là: Trước tiên cần phải hiểu rõ bản chất của missing values, rồi sau đó sẽ đưa ra giải pháp phù hợp để xử lý missing values.

Thông thường, có 2 cách để xử lý missing values:

  • Cách 1: Loại bỏ missing values (trong trường hợp missing values đó không quan trọng đối với dữ liệu của chúng ta hoặc số lượng missing values quá ít - chỉ chiếm khoảng dưới 3% tổng số quan sát trong 1 biến nhất định).

  • Cách 2: Thay thế missing values bằng một giá trị khác. Việc thay thế bằng giá trị nào sẽ phụ thuộc vào việc bản chất của missing values trong những trường hợp đó là gì.

Câu hỏi đặt ra lúc này là: Vậy thì nếu cần phải thay thế missing values bằng một giá trị khác, thì nên thay thế bằng giá trị nào?

Câu trả lời là:

  • Trường hợp biến có missing values là biến số - numeric: Có thể thay thế missing values bằng những giá trị như: 0, median, mean, v.v. tùy vào từng trường hợp nhất định.

  • Trường hợp biến có missing values là biến categorical: Có thể nhóm những trường hợp missing values vào 1 nhóm, đặt tên là Missing.

Sau đây, Ranalytics sẽ hướng dẫn các bạn xử lý những trường hợp missing values nêu trên bằng R, sử dụng dữ liệu giả lập sau:

data <- data.frame(
  name = c("Viet", "Nam", "Hai", "Phong", "Ha", "Giang", "Bac", "Ninh", "Ha", "Long"),
  age = as.numeric(c(sample(22:25, 7, replace=TRUE),NA,NA,NA)),
  income_mil_VND = c(NA, NA, sample(6:15, 6, replace = FALSE),80, NA),
  province = c("Hai Phong", "Ha Noi", "Hai Duong", NA, "Bac Giang", 
               "Bac Ninh", "Yen Bai", "Ca Mau", "Quang Ninh", "Quang Binh")
)

data
##     name age income_mil_VND   province
## 1   Viet  22             NA  Hai Phong
## 2    Nam  23             NA     Ha Noi
## 3    Hai  25             15  Hai Duong
## 4  Phong  24             12       <NA>
## 5     Ha  23              7  Bac Giang
## 6  Giang  23              9   Bac Ninh
## 7    Bac  24             11    Yen Bai
## 8   Ninh  NA             10     Ca Mau
## 9     Ha  NA             80 Quang Ninh
## 10  Long  NA             NA Quang Binh

Dữ liệu bao gồm thông tin về thu nhập hàng tháng (triệu đồng) và quê quán của 10 người có độ tuổi từ 22-25.

Summary dữ liệu, chúng ta có kết quả sau:

library(dplyr)
data %>% str
## 'data.frame':    10 obs. of  4 variables:
##  $ name          : Factor w/ 9 levels "Bac","Giang",..: 9 6 4 8 3 2 1 7 3 5
##  $ age           : num  22 23 25 24 23 23 24 NA NA NA
##  $ income_mil_VND: num  NA NA 15 12 7 9 11 10 80 NA
##  $ province      : Factor w/ 9 levels "Bac Giang","Bac Ninh",..: 6 4 5 NA 1 2 9 3 8 7
data %>% summary
##       name        age        income_mil_VND       province
##  Ha     :2   Min.   :22.00   Min.   : 7.00   Bac Giang:1  
##  Bac    :1   1st Qu.:23.00   1st Qu.: 9.50   Bac Ninh :1  
##  Giang  :1   Median :23.00   Median :11.00   Ca Mau   :1  
##  Hai    :1   Mean   :23.43   Mean   :20.57   Ha Noi   :1  
##  Long   :1   3rd Qu.:24.00   3rd Qu.:13.50   Hai Duong:1  
##  Nam    :1   Max.   :25.00   Max.   :80.00   (Other)  :4  
##  (Other):3   NA's   :3       NA's   :3       NA's     :1

Biến tuổi (age) và biến thu nhập (income_mil_VND) đều có 3 quan sát bị missing (NA) trên tổng số 10 quan sát -> tỷ lệ quan sát bị missing là 30%, vì vậy chúng ta cần phải thay thế những giá trị bị missing này bằng 1 giá trị nào đó khác.

Đối với biến tuổi, qua 1 số chỉ số thống kê cơ bản ở trên chúng ta có thể thấy không có sự chênh lệnh đáng kể về độ tuổi giữa những quan sát, không có trường hợp “outlier”, do vậy, chúng ta có thể thay thế những giá trị missing của biến tuổi bằng giá trị trung bình (mean).

data <- data %>% 
  # Tạo thêm biến mới (age_new) để có thể so sánh với biến cũ (age)
  mutate(age_new = case_when(
    is.na(age) ~ ceiling(mean(age, na.rm = T)),
    TRUE ~ age
  ))

data
##     name age income_mil_VND   province age_new
## 1   Viet  22             NA  Hai Phong      22
## 2    Nam  23             NA     Ha Noi      23
## 3    Hai  25             15  Hai Duong      25
## 4  Phong  24             12       <NA>      24
## 5     Ha  23              7  Bac Giang      23
## 6  Giang  23              9   Bac Ninh      23
## 7    Bac  24             11    Yen Bai      24
## 8   Ninh  NA             10     Ca Mau      24
## 9     Ha  NA             80 Quang Ninh      24
## 10  Long  NA             NA Quang Binh      24

Như vậy, missing values của biến tuổi đã được thay thế bằng giá trị trung bình của biến tuổi (mean = 23.4285714 làm tròn thành 24).

Còn đối với biến thu nhập, chúng ta thấy rằng 3/4 số người có mức thu nhập hàng tháng dưới 13.5 triệu đồng, trong khi đó có 1 người thu nhập lên đến 80 triệu đồng/tháng (outlier). Do đó, chúng ta không nên thay thế missing values của biến thu nhập bằng giá trị trung bình như trường hợp biến tuổi, vì điều đó sẽ không phản ánh đúng bản chất của dữ liệu. Thay vào đó, chúng ta nên thay thế missing values trong trường hợp này bằng giá trị trung vị (median).

data <- data %>% 
  # Thêm biến mới (income_new)
  mutate(income_new = case_when(
    is.na(income_mil_VND) ~ median(income_mil_VND, na.rm=T),
    TRUE ~ income_mil_VND
  ))

data
##     name age income_mil_VND   province age_new income_new
## 1   Viet  22             NA  Hai Phong      22         11
## 2    Nam  23             NA     Ha Noi      23         11
## 3    Hai  25             15  Hai Duong      25         15
## 4  Phong  24             12       <NA>      24         12
## 5     Ha  23              7  Bac Giang      23          7
## 6  Giang  23              9   Bac Ninh      23          9
## 7    Bac  24             11    Yen Bai      24         11
## 8   Ninh  NA             10     Ca Mau      24         10
## 9     Ha  NA             80 Quang Ninh      24         80
## 10  Long  NA             NA Quang Binh      24         11

Như vậy, missing values của biến thu nhập đã được thay thế bằng giá trị trung vị của biến thu nhập (median = 11).

Trường hợp cuối cùng, đối với biến quê quán (province), chỉ có 1 missing values. Nếu như chúng ta thấy rằng quan sát này không quan trọng thì có thể loại bỏ quan sát này, bằng câu lệnh sau đây:

data2 <- data %>% 
  # Chỉ lấy những quan sát mà province không bị missing
  filter(!is.na(province))

data2
##    name age income_mil_VND   province age_new income_new
## 1  Viet  22             NA  Hai Phong      22         11
## 2   Nam  23             NA     Ha Noi      23         11
## 3   Hai  25             15  Hai Duong      25         15
## 4    Ha  23              7  Bac Giang      23          7
## 5 Giang  23              9   Bac Ninh      23          9
## 6   Bac  24             11    Yen Bai      24         11
## 7  Ninh  NA             10     Ca Mau      24         10
## 8    Ha  NA             80 Quang Ninh      24         80
## 9  Long  NA             NA Quang Binh      24         11

Như vậy, chúng ta đã vừa bỏ đi 1 quan sát của tập dữ liệu (từ 10 quan sát còn 9).

Có 1 cách khác để xử lý missing values trong trường hợp này mà các bạn có thể sử dụng trong trường hợp các bạn vẫn muốn giữ lại quan sát nói trên. Đó là nhóm quan sát bị missing vào 1 nhóm tên là Missing như sau:

data <- data %>% 
  # Do biến province là biến factor, nên chúng ta cần transform biến này về dạng character trước
  mutate(province = province %>% as.character) %>% 
  # Tạo thêm biến mới (province_new)
  mutate(province_new = case_when(
    is.na(province) ~ "Missing",
    TRUE ~ province
  ) %>% as.factor)

Như vậy, chúng ta đã vừa thay thế giá trị missing của biến quê quán (province) thành Missing.

Sau khi làm sạch dữ liệu, chúng ta có thể loại bỏ những biến cũ age, income_mil_VNDprovince đi để dữ liệu được clean.

data <- data %>% 
  select(-c(age,income_mil_VND,province))

data
##     name age_new income_new province_new
## 1   Viet      22         11    Hai Phong
## 2    Nam      23         11       Ha Noi
## 3    Hai      25         15    Hai Duong
## 4  Phong      24         12      Missing
## 5     Ha      23          7    Bac Giang
## 6  Giang      23          9     Bac Ninh
## 7    Bac      24         11      Yen Bai
## 8   Ninh      24         10       Ca Mau
## 9     Ha      24         80   Quang Ninh
## 10  Long      24         11   Quang Binh

Như vậy, chúng ta đã được làm quen với một số tricks để xử lý missing values. Chúc các bạn học tập và làm việc hiệu quả với Ranalytics.vn!

comments powered by Disqus