Cách đơn giản để báo cáo các giá trị bị thiếu trong data.frame


80

Đây là một đoạn mã nhỏ mà tôi đã viết để báo cáo các biến có giá trị bị thiếu từ khung dữ liệu. Tôi đang cố gắng nghĩ ra một cách thanh lịch hơn để làm điều này, một cách có thể trả về data.frame, nhưng tôi bị mắc kẹt:

for (Var in names(airquality)) {
    missing <- sum(is.na(airquality[,Var]))
    if (missing > 0) {
        print(c(Var,missing))
    }
}

Chỉnh sửa: Tôi đang xử lý data.frame với hàng chục đến hàng trăm biến, vì vậy điều quan trọng là chúng tôi chỉ báo cáo các biến có giá trị bị thiếu.


@kohske: đó là suy nghĩ đầu tiên của tôi, nhưng kết quả là một tableký tự và bạn sẽ phải phân tích số lượng NA.
Joshua Ulrich

Tôi đang hoàn nguyên câu hỏi của bạn, vì bạn đã đăng câu trả lời. Nếu bạn muốn nhận xét về một câu trả lời, hãy làm như một nhận xét cho câu trả lời đó. Nếu câu hỏi cũng chứa câu trả lời, điều này trở nên rất khó hiểu.
Andrie

@Andrie: Tôi không đồng ý với chỉnh sửa của bạn, vì vấn đề chính mà tôi đang gặp phải là chỉ báo cáo các biến có giá trị bị thiếu. Hơn nữa, việc khôi phục của bạn đã xóa một thay đổi mà tôi đã thực hiện đối với mã. Tôi đã chỉnh sửa câu hỏi của mình để bao gồm thông tin này và thêm phiên bản sửa đổi của mã Josh vào một nhận xét.
Zach

@Zach Bản chỉnh sửa mới của bạn có vẻ ổn đối với tôi. Nhân tiện, tôi không ghét việc thêm dữ liệu / yêu cầu bổ sung vào một câu hỏi khi nó đang hoạt động, nếu điều này làm rõ câu hỏi.
Andrie

Có nửa triệu cách để thực hiện việc này, hãy xem CRAN Task View - MissingData
zx8754

Câu trả lời:


156

Chỉ dùng sapply

> sapply(airquality, function(x) sum(is.na(x)))
  Ozone Solar.R    Wind    Temp   Month     Day 
     37       7       0       0       0       0

Bạn cũng có thể sử dụng applyhoặc colSumstrên ma trận được tạo bởiis.na()

> apply(is.na(airquality),2,sum)
  Ozone Solar.R    Wind    Temp   Month     Day 
     37       7       0       0       0       0
> colSums(is.na(airquality))
  Ozone Solar.R    Wind    Temp   Month     Day 
     37       7       0       0       0       0 

12
Tôi đã sửa đổi mã của bạn một chút, để chỉ báo cáo giá trị bị thiếu:M <- sapply(airquality, function(x) sum(is.na(x))); M[M>0]
Zach

Cảm ơn! Đã học hỏi được rất nhiều.
Bombyx mori

Xin chào @Joshua Ulrich, cảm ơn rất nhiều vì mã ngắn gọn của bạn. Tôi muốn thêm một cột trong khung dữ liệu sẽ hiển thị phần trăm giá trị na. Bạn có thể vui lòng cung cấp một số trợ giúp về điều này?
DukeLover

2
@Zach tôi sử dụng một phiên bản đề xuất của bạn để kiểm tra xem trường bắt buộc có giá trị:M <- colSums(is.na(airquality)); M[M <= 0]
Anthony Simon Mielniczuk

@Joshua thêm một tùy chọn cho% s cũng sẽ thành công!
radek

8

Chúng ta có thể sử dụng map_dfvới purrr.

library(mice)
library(purrr)

# map_df with purrr
map_df(airquality, function(x) sum(is.na(x)))
# A tibble: 1 × 6
# Ozone Solar.R  Wind  Temp Month   Day
# <int>   <int> <int> <int> <int> <int>
# 1    37       7     0     0     0     0

1
Ưu điểm của map_dfhơn là sapplygì?
Zach

1
@Zach Tôi nghĩ rằng không có sự khác biệt lớn, nhưng Hadley nói rằng không sử dụng sapply () bên trong một hàm. Xem Ngoại lệ và gỡ lỗi · Nâng cao R. adv-r.had.co.nz/Exceptions-Debugging.html .
Keiku

đối với những người lười biếng như tôi, bạn có thể viết đoạn mã trên bằng cú pháp purrr ngắn hơn cho các hàm (~) để nó trông như thế này:map_df( air quality, ~sum(is.na(.) )
Agile Bean

1
@Zach lợi thế của map_dfover sapplychỉ là khi kết quả có nhiều hàng vì định dạng đầu ra của map_df luôn là một lỗi nhỏ.
Agile Bean

1
@Zach: tốt hơn nên sử dụng hàm vapplyvs sapplytrong vì vapplycung cấp cho bạn cấu trúc kết quả đã biết (mà bạn chỉ định). sapplycó thể trả về một mảng hoặc một danh sách, tùy thuộc vào kết quả đầu ra của hàm. Một nhược điểm map_dflà bạn cung cấp cho nó một data.frame làm đầu vào và nó trả về một lớp con data.frame, không phải data.frame. Không có gì đảm bảo rằng các tibbles sẽ hoạt động như data.frames trong mọi trường hợp cần thiết trong tương lai.
Joshua Ulrich

8

Yêu thích mới của tôi cho dữ liệu (không quá rộng) là các phương pháp từ gói naniar tuyệt vời . Bạn không chỉ nhận được tần số mà còn cả các dạng mất tích:

library(naniar)
library(UpSetR)

riskfactors %>%
  as_shadow_upset() %>%
  upset()

nhập mô tả hình ảnh ở đây

Thường sẽ hữu ích khi xem vị trí thiếu sót có liên quan đến không thiếu có thể đạt được bằng cách vẽ biểu đồ phân tán với các lần bỏ sót:

ggplot(airquality,
       aes(x = Ozone,
           y = Solar.R)) +
 geom_miss_point()

nhập mô tả hình ảnh ở đây

Hoặc đối với các biến phân loại:

gg_miss_fct(x = riskfactors, fct = marital)

nhập mô tả hình ảnh ở đây

Những ví dụ này là từ gói họa tiết liệt kê các hình ảnh trực quan thú vị khác.


2
Cảm ơn vì đã đăng bài này! Hiện có một gg_miss_upset()chức năng dành riêng trong bản phát hành mới nhất, sẽ được gửi tới CRAN khi họ trở về sau kỳ nghỉ. naniar.njtierney.com/reference/gg_miss_upset.html
Nick Tierney

6
summary(airquality)

đã cung cấp cho bạn thông tin này

Các gói VIM cũng cung cấp một số đồ thị dữ liệu bị thiếu tuyệt vời cho data.frame

library("VIM")
aggr(airquality)

nhập mô tả hình ảnh ở đây


Gói VIM có thể báo cáo những quan sát cụ thể nào bị thiếu dữ liệu không?
Anthony Simon Mielniczuk

đừng nghĩ vậy .. nhưng bạn có thể làm điều này khá dễ dàng (bạn sẽ phải thay thế airquality bằng khung dữ liệu của riêng mình): res <- airquality [rowSums (is.na (airquality))> 0,]
Steffen Moritz

4

Cô đọng hơn-: sum(is.na(x[1]))

Đó là

  1. x[1] Nhìn vào cột đầu tiên

  2. is.na() đúng nếu nó NA

  3. sum() TRUE1, FALSE0


này không trả lời câu hỏi ban đầu, mà là để tìm số của NAs cho tất cả các cột trong dữ liệu
Bến Bolker

4

Một thay thế đồ họa khác - plot_missingchức năng từ DataExplorergói tuyệt vời :

nhập mô tả hình ảnh ở đây

Docs cũng chỉ ra một thực tế là bạn có thể lưu kết quả này để phân tích thêm missing_data <- plot_missing(data).


Các plot_missing()chức năng trong DataExplorergói tại là PlotMissing().
coip

1
@coip PlotMissing()không được dùng nữa. Hãy sử dụng plot_missing()thay thế. Xem # 49 để biết thêm chi tiết.
Boxuan

2

Một hàm khác sẽ giúp bạn xem dữ liệu bị thiếu là df_status từ thư viện funModeling

library(funModeling)

iris.2 là tập dữ liệu mống mắt với một số NA được bổ sung. Bạn có thể thay thế điều này bằng tập dữ liệu của mình.

df_status(iris.2)

Điều này sẽ cung cấp cho bạn số lượng và tỷ lệ NA trong mỗi cột.


1

Để có thêm một giải pháp đồ họa, visdat gói cung cấp vis_miss.

library(visdat)
vis_miss(airquality)

nhập mô tả hình ảnh ở đây

Rất giống với Ameliađầu ra với sự khác biệt nhỏ là cho% s khi bỏ lỡ hộp.


1

Tôi nghĩ rằng thư viện Amelia thực hiện một công việc tốt trong việc xử lý dữ liệu bị thiếu cũng bao gồm một bản đồ để hiển thị các hàng bị thiếu.

install.packages("Amelia")
library(Amelia)
missmap(airquality)

nhập mô tả hình ảnh ở đây

Bạn cũng có thể chạy đoạn mã sau sẽ trả về các giá trị logic của na

row.has.na <- apply(training, 1, function(x){any(is.na(x))})

1

Một cách đồ họa và tương tác khác là sử dụng is.na10hàm từ heatmaplythư viện:

library(heatmaply)

heatmaply(is.na10(airquality), grid_gap = 1, 
          showticklabels = c(T,F),
            k_col =3, k_row = 3,
            margins = c(55, 30), 
            colors = c("grey80", "grey20"))

nhập mô tả hình ảnh ở đây

Có thể sẽ không hoạt động tốt với các tập dữ liệu lớn ..


0

Nếu bạn muốn làm điều đó cho cột cụ thể, thì bạn cũng có thể sử dụng

length(which(is.na(airquality[1])==T))

4
Bạn không cần phải so sánh một vectơ logic với T. Bạn cũng có thể đếm số phần tử ĐÚNG trong một vectơ logic bằng cách tính tổng nó.
Houshalter


0

Một dplyrgiải pháp để có được số lượng có thể là:

summarise_all(df, ~sum(is.na(.)))

Hoặc để nhận phần trăm:

summarise_all(df, ~(sum(is_missing(.) / nrow(df))))

Cũng có thể đáng lưu ý rằng dữ liệu bị thiếu có thể xấu, không nhất quán và không phải lúc nào cũng được mã hóa NAtùy thuộc vào nguồn hoặc cách xử lý khi nhập. Chức năng sau có thể được tinh chỉnh tùy thuộc vào dữ liệu của bạn và những gì bạn muốn xem xét còn thiếu:

is_missing <- function(x){
  missing_strs <- c('', 'null', 'na', 'nan', 'inf', '-inf', '-9', 'unknown', 'missing')
  ifelse((is.na(x) | is.nan(x) | is.infinite(x)), TRUE,
         ifelse(trimws(tolower(x)) %in% missing_strs, TRUE, FALSE))
}

# sample ugly data
df <- data.frame(a = c(NA, '1', '  ', 'missing'),
                 b = c(0, 2, NaN, 4),
                 c = c('NA', 'b', '-9', 'null'),
                 d = 1:4,
                 e = c(1, Inf, -Inf, 0))

# counts:
> summarise_all(df, ~sum(is_missing(.)))
  a b c d e
1 3 1 3 0 2

# percentage:
> summarise_all(df, ~(sum(is_missing(.) / nrow(df))))
     a    b    c d   e
1 0.75 0.25 0.75 0 0.5
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.