удалить строки, имеющие дубликаты, на основе столбца в зависимости от количества NA в другом столбце - PullRequest
0 голосов
/ 28 октября 2018

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

Удаление строк, которые дублируются в одном столбце, на основе условий другого столбца

Вот мой набор данных игрушек:

df1 <- data.frame(a = c("x","y","y","z","x", "z"), b = c(1,2,NA,4,8,3), c = c(NA,2,2,NA,NA,4), d= c(1:4,NA,NA))

, что дает:

  a  b  c  d
1 x  1 NA  1
2 y  2  2  2
3 y NA  2  3
4 z  4 NA  4
5 x  8 NA NA
6 z  3  4 NA

Я хотел бы сохранить только строки с уникальными значениями в столбце a и оставить только строки с наименьшим количеством NA в столбцах b & c (игнорируя NA в столбце d)

Вот код, который я придумал:

df1 %>%
 mutate(NAs= apply(is.na(cbind(b,c)), 1, sum)) %>%     
 group_by(a) %>%
 top_n(n=1, -NAs)

Моя проблема в том, что top_n возвращает более одной строки, если есть связь. В случае галстука, я просто хочу вернуть первый ряд. И, вероятно, есть лучший способ выбрать столбцы в mutate, чем cbind. Мне также не нужна переменная "NA", которую я создал, используя mutate. Мой желаемый вывод такой:

  a  b  c  d
  x  1 NA  1
  y  2  2  2
  z  3  4 NA

Ответы [ 3 ]

0 голосов
/ 29 октября 2018

@ Маркус предположил, что это тоже может быть ответом. Возможно, это правда, поскольку в случае dplyr может быть полезно сохранить код коротким, в противном случае вы часто можете получить довольно подробные сценарии.

Однако, на мой взгляд, основная часть - rowSums, поскольку она уже была выделена.

df1 %>% 
arrange(a, rowSums(is.na(.[, c("b", "c")]))) %>% 
distinct(a, .keep_all = TRUE)

  a b  c  d
1 x 1 NA  1
2 y 2  2  2
3 z 3  4 NA

P.S. Если вам важна скорость, то я действительно стараюсь использовать как можно меньше глаголов dplyr, например, например. подход только с arrange & distinct в 3 раза быстрее, чем с другими подходами с group, slice, top_n, filter и т. д.

0 голосов
/ 29 октября 2018

Немного другой вариант dplyr:

df1 %>%
  mutate(miss = rowSums(is.na(cbind(b,c)))) %>%
  group_by(a) %>%
  filter(miss == min(miss)) %>%
  slice(1) %>%
  select(-miss) %>%
  ungroup()

Или:

df1 %>%
  mutate(miss = rowSums(is.na(cbind(b,c)))) %>%
  group_by(a) %>%
  mutate(dupl = seq_along(a)) %>%
  filter(miss == min(miss)) %>%
  filter(dupl == min(dupl)) %>%
  select(-miss, -dupl) %>%
  ungroup()
0 голосов
/ 28 октября 2018

Вот вариант

library(dplyr)
df1 %>%
  mutate(NAs = rowSums(is.na(.[, c("b", "c")]))) %>%
  group_by(a) %>%
  top_n(n = 1, -NAs) %>% 
  slice(1) %>% 
  select(-NAs)
# A tibble: 3 x 4
# Groups:   a [3]
#  a         b     c     d
#  <fct> <dbl> <dbl> <int>
#1 x         1    NA     1
#2 y         2     2     2
#3 z         3     4    NA

rowSums - более эффективная альтернатива apply(..., 1, sum).


Вы также можете попробовать data.table.Приведенное ниже решение должно быть очень быстрым (но потенциально менее читабельным).

library(data.table)
setDT(df1)
df1[df1[order(a, df1[, rowSums(is.na(.SD)), .SDcols = c("b", "c")]), .I[1], by = "a"]$V1]
#   a b  c  d
#1: x 1 NA  1
#2: y 2  2  2
#3: z 3  4 NA
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...