Удалить строки, содержащие NA, из столбца с наименьшим количеством NA - PullRequest
0 голосов
/ 24 апреля 2019

У меня есть фрейм данных, который в итоге будет преобразован в объект xts.Первый столбец содержит данные о дате, а все остальные столбцы содержат числовые данные.Однако не все числовые столбцы имеют одинаковое количество значений / одинаковую длину.В некоторых столбцах содержится больше строк, содержащих NA, чем в других.

Я хочу отфильтровать мой фрейм данных, удалив строки, содержащие NA, в столбце, который имеет наименьшее количество NA, но при этом сохранит строки, содержащие NA для всех других столбцов, которыеЯ выбрал.Например, столбец grpA ниже имеет наименьшее количество NA.Я хотел бы удалить первые 2 строки кадра данных, которые содержат NA, но сохраняют значения в grpB независимо от того, что они есть.

Что у меня есть:

Date        grpA    grpB
2007-11-06  NA      NA
2007-11-07  NA      NA
2007-11-09  1.66    NA
2007-11-12  1.64    NA
2007-11-13  1.61    1.28
2007-11-14  1.60    1.30
2007-11-15  1.57    1.27
2007-11-16  1.56    1.25
2007-11-19  1.55    1.25
2007-11-20  1.55    1.25
2007-11-21  1.52    1.22
2007-11-22  1.50    1.21
2007-11-23  1.51    1.21
2007-11-26  1.52    1.25
2007-11-27  1.50    1.25
2007-11-28  1.50    1.23
2007-11-29  1.52    1.24
2007-11-30  1.56    1.25
2007-12-03  1.56    1.22
2007-12-04  1.56    1.23

Что я хочу:

Date        grpA    grpB
2007-11-09  1.66    NA
2007-11-12  1.64    NA
2007-11-13  1.61    1.28
2007-11-14  1.60    1.30
2007-11-15  1.57    1.27
2007-11-16  1.56    1.25
2007-11-19  1.55    1.25
2007-11-20  1.55    1.25
2007-11-21  1.52    1.22
2007-11-22  1.50    1.21
2007-11-23  1.51    1.21
2007-11-26  1.52    1.25
2007-11-27  1.50    1.25
2007-11-28  1.50    1.23
2007-11-29  1.52    1.24
2007-11-30  1.56    1.25
2007-12-03  1.56    1.22
2007-12-04  1.56    1.23

Воспроизводимая выборка кадра данных выглядит следующим образом:

df <- data.frame(Date = structure(c(1194307200, 1194393600, 1194566400, 
                                    1194825600, 1194912000, 1194998400, 1195084800, 1195171200, 1195430400, 
                                    1195516800, 1195603200, 1195689600, 1195776000, 1196035200, 1196121600, 
                                    1196208000, 1196294400, 1196380800, 1196640000, 1196726400), class = c("POSIXct", 
                                                                                                           "POSIXt"), tzone = "UTC"), 
                 grpA = c(NA, NA, 1.66, 1.64, 1.61, 1.6, 1.57, 1.56, 1.55, 1.55, 1.52, 1.5, 1.51, 1.52, 1.5, 1.5, 1.52, 1.56, 1.56, 1.56), 
                 grpB = c(NA, NA, NA, NA, 1.28, 1.3, 1.27, 1.25, 1.25, 1.25, 1.22, 1.21, 1.21, 1.25, 1.25, 1.23, 1.24, 1.25, 1.22, 1.23))

Я пробовал функцию drop_na из пакета tidyr, и она работает:

df2 <- drop_na(df, grpA)

Однако я собираюсь использовать вышеупомянутую фильтрацию в блестящем приложении, и я не знаю заранее, какие столбцы выберут пользователи с наименьшим числом строк, содержащих в себе NA.

IЯ попробовал следующее, чтобы идентифицировать столбец с наименьшим количеством строк, содержащих в себе NA, но он предоставил мне количество не-NA строк вместо имени столбца:

max(colSums(!is.na(df[-1])))

Я пыталсяИзвлеките имя столбца, используя следующее, но обнаружили ошибку:

colnames(df)[which(colSums(!is.na(df[-1]))) == max(colSums(!is.na(df[-1])))]

Я предполагал, что это простая задача, но она стала довольно сложной.Мне нужен был бы ответ, чтобы можно было использовать его в блестящем реактивном выражении.

Спасибо и высоко ценю!

1 Ответ

4 голосов
/ 24 апреля 2019

Сначала можно найти имя столбца с минимальным числом NA с, а затем удалить из этого столбца NA строк.

col <- names(which.min(colSums(is.na(df[-1]))))
df[!is.na(df[col]), ]


#         Date grpA grpB
#3  2007-11-09 1.66   NA
#4  2007-11-12 1.64   NA
#5  2007-11-13 1.61 1.28
#6  2007-11-14 1.60 1.30
#7  2007-11-15 1.57 1.27
#8  2007-11-16 1.56 1.25
#9  2007-11-19 1.55 1.25
#10 2007-11-20 1.55 1.25
#11 2007-11-21 1.52 1.22
#12 2007-11-22 1.50 1.21
#13 2007-11-23 1.51 1.21
#14 2007-11-26 1.52 1.25
#15 2007-11-27 1.50 1.25
#16 2007-11-28 1.50 1.23
#17 2007-11-29 1.52 1.24
#18 2007-11-30 1.56 1.25
#19 2007-12-03 1.56 1.22
#20 2007-12-04 1.56 1.23

, что также может быть выполнено в одну строку без создания дополнительной переменной

df[!is.na(df[names(which.min(colSums(is.na(df[-1]))))]), ]

Используя ту же логику, dplyr подход мог бы использовать filter_at

library(dplyr)

df %>%
   filter_at(df %>%
   summarise_at(-1, ~sum(is.na(.))) %>%
   which.min %>% names, ~!is.na(.))

Или используя его с tidyr::drop_na

tidyr::drop_na(df, df %>%
                  summarise_at(-1, ~sum(is.na(.))) %>%
                  which.min %>% names)
...