Подсчитайте NA в нескольких столбцах в R

#r

Вопрос:

Я пытаюсь подсчитать количество NA в нескольких столбцах моих данных. Вот воспроизводимый образец.

 structure(list(V2QE38A = c(1, 0, 1, 0, 1, 1, 1, 0, 1, 0), V2QE38B = c(0, 
0, 0, 0, 0, 1, 0, 0, 0, 0), V2QE38C = c(1, 1, 0, 3, 2, 0, 0, 
3, 1, 1), V2QE38D = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)), row.names = c(NA, 
10L), class = "data.frame")
 

Я попробовал два метода:
Первый:

 dt %>% select(starts_with("V2QE38")) %>% colSums(is.na(.))
 

И это дает мне некоторые результаты (короче говоря, у меня есть NAs в некоторых столбцах).
Затем я попробовал еще один:

 colSums(is.na(dt[,c("V2QE38A", "V2QE38B", "V2QE38C", "V2QE38D")]))
 

И я не обнаружил ни в одной из этих колонок NA.

Я думаю, что второй результат верен. Но мне просто интересно, что я сделал не так, чтобы получить первый результат? Спасибо!

Ответ №1:

В первом случае передается несколько функций. Возможно, нам придется либо заблокировать его с помощью {}

 library(dplyr)
dt %>% 
    select(starts_with("V2QE38")) %>%
    {colSums(is.na(.))}
V2QE38A V2QE38B V2QE38C V2QE38D 
      0       0       0       0 
 

или выпейте еще %>%

 dt %>%
    select(starts_with("V2QE38")) %>%
    is.na %>%
    colSums
 

-выход

 V2QE38A V2QE38B V2QE38C V2QE38D 
      0       0       0       0 
 

Проблема в том, что colSums сначала выполняется без оценки is.na

 > dt %>% 
   select(starts_with("V2QE38")) %>% 
   colSums(.)
V2QE38A V2QE38B V2QE38C V2QE38D 
      6       1      12       0 
 

что совпадает с выводом операции с colSums(is.na(.))

Комментарии:

1. Я вижу! Большое вам спасибо за ответ. Очень ясно!

2. @YYM17 По умолчанию первый аргумент берется из lhs of %>% . второй аргумент colSums ис na.rm , который берется в dt %>% select(starts_with("V2QE38")) %>% colSums(na.rm = is.na(.))

3. Да, мне просто нужно подождать еще пару минут, чтобы система разрешила принять ответ, Хахахаха

4. @YYM17 вы можете проверить эти ` ДТ %>% выберите(starts_with(«V2QE38″)) %>% colSums(размеры= это.на(.)) Ошибка в colSums(., размеры = это.на(.)) : недопустимое ‘затемняет» или dt %>% select(starts_with("V2QE38")) %>% colSums(x= is.na(.)) не будет работать, так как ее уже успели оценить x от лхс

5. Спасибо! Кажется, что логика, лежащая в основе colSums, немного странна внутри трубы

Ответ №2:

Базовое решение с использованием sapply и одноименной функции function(x){sum(is.na(x))} :

 data = structure(list(V2QE38A = c(1, 0, 1, 0, 1, 1, 1, 0, 1, 0), V2QE38B = c(0, 
0, 0, 0, 0, 1, 0, 0, 0, 0), V2QE38C = c(1, 1, 0, 3, 2, 0, 0, 
3, 1, 1), V2QE38D = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)), row.names = c(NA, 
10L), class = "data.frame")

sapply(data, function(x){sum(is.na(x))})
# V2QE38A V2QE38B V2QE38C V2QE38D 
#       0       0       0       0 
 

Объяснение:

sapply применяет функцию к a list . data.frame представляет собой список, каждый вектор которого является элементом этого списка. Вход s sapply предназначен для упрощения, поэтому sapply мы попытаемся преобразовать выходной список (из lapply ) в вектор. Если требуемым выводом является список (у него есть некоторые преимущества), используйте lapply вместо этого.

is.na возвращает логический TRUE/FALSE вектор. Это можно преобразовать в числовой вектор со 1/0 значениями.

sum преобразует TRUE/FALSE вектор в 1/0 вектор и суммирует значения.

Альтернативные решения:

В качестве альтернативы, вместо того, чтобы рассматривать data.frame его как список, рассматривайте его как матрицу. Тогда сильно оптимизированный rowSums и colSums может вступить в игру.

 colSums(is.na(data))
# V2QE38A V2QE38B V2QE38C V2QE38D 
#       0       0       0       0 

rowSums(is.na(data))
# 1  2  3  4  5  6  7  8  9 10 
# 0  0  0  0  0  0  0  0  0  0
 

Это здорово, если у вас есть matrix » а «и вы хотите найти, где NA находятся «с».

Комментарии:

1. Спасибо! Хотя до этого я пробовал apply , но есть некоторые проблемы, когда я пытался совместить это с dplyr . Приятно знать, что sapply это можно использовать вместо этого!