Cách thay thế các giá trị bị thiếu (NA) trong R: na.omit & na.rm

Các giá trị bị thiếu trong khoa học dữ liệu phát sinh khi một quan sát bị thiếu trong một cột của khung dữ liệu hoặc chứa giá trị ký tự thay vì giá trị số. Các giá trị bị thiếu phải được loại bỏ hoặc thay thế để rút ra kết luận chính xác từ dữ liệu.

Trong hướng dẫn này, chúng ta sẽ tìm hiểu cách xử lý các giá trị bị thiếu bằng thư viện dplyr. Thư viện dplyr là một phần của hệ sinh thái để thực hiện phân tích dữ liệu.

Thay thế các giá trị bị thiếu trong R

Trong hướng dẫn này, bạn sẽ học

đột biến ()

Động từ thứ tư trong thư viện dplyr rất hữu ích khi tạo biến mới hoặc thay đổi giá trị của biến hiện có.

Chúng ta sẽ tiến hành theo hai phần. Chúng ta sẽ học cách:

  • loại trừ các giá trị bị thiếu khỏi khung dữ liệu
  • gán các giá trị còn thiếu bằng giá trị trung bình và trung vị

Động từ mutate() rất dễ sử dụng. Chúng ta có thể tạo một biến mới theo cú pháp sau:

mutate(df, name_variable_1 = condition, ...)
arguments:
-df: Data frame used to create a new variable
-name_variable_1: Name and the formula to create the new variable
-...: No limit constraint. Possibility to create more than one variable inside mutate()

Loại trừ các giá trị bị thiếu (NA)

Phương thức na.omit() từ thư viện dplyr là một cách đơn giản để loại trừ quan sát bị thiếu. Việc loại bỏ tất cả NA khỏi dữ liệu rất dễ dàng nhưng không có nghĩa là đó là giải pháp thanh lịch nhất. Trong quá trình phân tích, nên sử dụng nhiều phương pháp khác nhau để xử lý các giá trị bị thiếu

Để giải quyết vấn đề thiếu quan sát, chúng tôi sẽ sử dụng bộ dữ liệu titanic. Trong tập dữ liệu này, chúng tôi có quyền truy cập vào thông tin của hành khách trên tàu trong thảm kịch. Tập dữ liệu này có nhiều NA cần được quan tâm.

Chúng ta sẽ tải tệp csv từ internet lên và sau đó kiểm tra xem cột nào có NA. Để trả về các cột có dữ liệu bị thiếu, chúng ta có thể sử dụng mã sau:

Hãy tải lên dữ liệu và xác minh dữ liệu còn thiếu.

PATH <- "https://raw.githubusercontent.com/guru99-edu/R-Programming/master/test.csv"
df_titanic <- read.csv(PATH, sep = ",")
# Return the column names containing missing observations
list_na <- colnames(df_titanic)[ apply(df_titanic, 2, anyNA) ]
list_na

Đầu ra:

## [1] "age"  "fare"

Ở đây,

colnames(df_titanic)[apply(df_titanic, 2, anyNA)]

Cung cấp tên của các cột không có dữ liệu.

Cột tuổi và giá vé bị thiếu giá trị.

Chúng ta có thể loại bỏ chúng bằng na.omit().

library(dplyr)
# Exclude the missing observations
df_titanic_drop <-df_titanic %>%
na.omit()		
dim(df_titanic_drop)

Đầu ra:

## [1] 1045   13

Tập dữ liệu mới chứa 1045 hàng so với 1309 hàng của tập dữ liệu gốc.

Loại trừ các giá trị bị thiếu

Quy kết dữ liệu bị thiếu với giá trị trung bình và trung vị

Chúng ta cũng có thể gán (điền) các giá trị bị thiếu bằng giá trị trung bình hoặc giá trị trung bình. Một cách thực hành tốt là tạo hai biến riêng biệt cho giá trị trung bình và trung vị. Sau khi tạo, chúng ta có thể thay thế các giá trị còn thiếu bằng các biến mới được tạo.

Chúng ta sẽ sử dụng phương thức apply để tính giá trị trung bình của cột với NA. Hãy xem một ví dụ

Bước 1) Trước đó trong hướng dẫn, chúng tôi đã lưu trữ tên cột có giá trị bị thiếu trong danh sách có tên list_na. Chúng tôi sẽ sử dụng danh sách này

Bước 2) Bây giờ chúng ta cần tính giá trị trung bình với đối số na.rm = TRUE. Đối số này là bắt buộc vì các cột bị thiếu dữ liệu và điều này yêu cầu R bỏ qua chúng.

# Create mean
average_missing <- apply(df_titanic[,colnames(df_titanic) %in% list_na],
      2,
      mean,
      na.rm =  TRUE)
average_missing

Giải thích mã:

Chúng ta truyền 4 đối số trong phương thức apply.

  • df: df_titanic[,colnames(df_titanic) %in% list_na]. Mã này sẽ trả về tên cột từ đối tượng list_na (tức là “tuổi” và “giá vé”)
  • 2: Tính hàm trên các cột
  • ý nghĩa: Tính giá trị trung bình
  • na.rm = TRUE: Bỏ qua các giá trị còn thiếu

Đầu ra:

##      age     fare 
## 29.88113 33.29548

Chúng tôi đã tạo thành công giá trị trung bình của các cột chứa các quan sát bị thiếu. Hai giá trị này sẽ được sử dụng để thay thế các quan sát còn thiếu.

Bước 3) Thay thế các giá trị NA

Động từ mutate từ thư viện dplyr rất hữu ích trong việc tạo một biến mới. Chúng tôi không nhất thiết muốn thay đổi cột ban đầu để có thể tạo một biến mới mà không cần NA. mutate rất dễ sử dụng, chúng ta chỉ cần chọn tên biến và xác định cách tạo biến này. Đây là mã hoàn chỉnh

# Create a new variable with the mean and median
df_titanic_replace <- df_titanic %>%
   mutate(replace_mean_age  = ifelse(is.na(age), average_missing[1], age),
   replace_mean_fare = ifelse(is.na(fare), average_missing[2], fare))

Giải thích mã:

Chúng tôi tạo hai biến, thay thế_mean_age và thay thế_mean_fare như sau:

  • thay thế_mean_age = ifelse(is.na(age), Average_missing[1], age)
  • thay thế_mean_fare = ifelse(is.na(giá vé), Average_missing[2], giá vé)

Nếu cột tuổi thiếu giá trị thì thay thế bằng phần tử đầu tiên của Average_missing (tuổi trung bình), nếu không thì giữ nguyên giá trị ban đầu. Logic tương tự cho giá vé

sum(is.na(df_titanic_replace$age))

Đầu ra:

## [1] 263

Thực hiện thay thế

sum(is.na(df_titanic_replace$replace_mean_age))

Đầu ra:

## [1] 0

Cột age ban đầu có 263 giá trị bị thiếu trong khi biến mới được tạo đã thay thế chúng bằng giá trị trung bình của biến age.

Bước 4) Chúng ta cũng có thể thay thế các quan sát còn thiếu bằng giá trị trung vị.

median_missing <- apply(df_titanic[,colnames(df_titanic) %in% list_na],
      2,
      median,
      na.rm =  TRUE)
df_titanic_replace <- df_titanic %>%
            mutate(replace_median_age  = ifelse(is.na(age), median_missing[1], age), 
            replace_median_fare = ifelse(is.na(fare), median_missing[2], fare))
head(df_titanic_replace)

Đầu ra:

Quy kết dữ liệu bị thiếu với giá trị trung bình và trung vị

Bước 5) Một tập dữ liệu lớn có thể thiếu nhiều giá trị và phương pháp trên có thể cồng kềnh. Chúng ta có thể thực hiện tất cả các bước trên trong một dòng mã bằng phương thức sapply(). Mặc dù chúng ta không biết giá trị trung bình và trung vị.

sapply không tạo ra một khung dữ liệu, vì vậy chúng ta có thể gói hàm sapply() bên trong data.frame() để tạo đối tượng khung dữ liệu.

# Quick code to replace missing values with the mean
df_titanic_impute_mean < -data.frame(
    sapply(
        df_titanic,
        function(x) ifelse(is.na(x),
            mean(x, na.rm = TRUE),
            x)))

Tổng kết

Chúng tôi có ba phương pháp để xử lý các giá trị bị thiếu:

  • Loại trừ tất cả các quan sát còn thiếu
  • Đổ tội với ý nghĩa
  • Tranh chấp với số trung vị

Bảng sau đây tóm tắt cách loại bỏ tất cả các quan sát bị thiếu

Thư viện Mục tiêu
cơ sở Liệt kê các quan sát còn thiếu
colnames(df)[apply(df, 2, anyNA)]
dplyr Xóa tất cả các giá trị bị thiếu
na.omit(df)

Việc tính toán bằng giá trị trung bình hoặc trung vị có thể được thực hiện theo hai cách

  • Sử dụng áp dụng
  • Sử dụng sapply
Phương pháp Chi Tiết Ưu điểm Nhược điểm
Từng bước áp dụng Kiểm tra các cột bị thiếu, tính giá trị trung bình/trung vị, lưu trữ giá trị, thay thế bằng mutate() Bạn biết giá trị của phương tiện/trung vị Thêm thời gian thực hiện. Có thể chậm với tập dữ liệu lớn
Cách nhanh chóng với sapply Sử dụng sapply() và data.frame() để tự động tìm kiếm và thay thế các giá trị bị thiếu bằng giá trị trung bình/trung vị Mã ngắn và nhanh Không biết các giá trị quy định