Использование значения в одном столбце, чтобы указать, из какой строки получить значение для нового столбца - PullRequest
0 голосов
/ 29 мая 2020

Я ищу автоматический способ преобразования этого:

dat = tribble(
    ~a, ~b, ~c
    , 'x', 1, 'y'
    , 'y', 2, NA
    , 'q', 4, NA
    , 'z', 3, 'q'
)

в:

tribble(
    ~a, ~b, ~d
    , 'x', 1, 2
    , 'z', 3, 4
)

Итак, столбец c в dat кодирует, какая строка в dat, чтобы получить значение для нового столбца d, и если c равно NA, выбросить эту строку из вывода. Есть подсказки?

Ответы [ 2 ]

1 голос
/ 29 мая 2020

Мы можем объединить dat с самим собой, используя столбцы c и a.

library(dplyr)

dat %>%
  inner_join(dat %>% select(-c) %>% rename(d = 'b'), 
             by = c('c' = 'a'))


# A tibble: 2 x 4
#  a         b c         d
#  <chr> <dbl> <chr> <dbl>
#1 x         1 y         2
#2 z         3 q         4

В базовом R мы можем сделать это с помощью merge:

merge(dat, dat[-3], by.x = 'c', by.y = 'a')
1 голос
/ 29 мая 2020

Мы создаем 'd' с lead из 'b' и filter из строк NA с 'c' и удаляем столбец c с select

library(dplyr)
dat %>%
    mutate(d = lead(b)) %>%
    filter(!is.na(c)) %>%
    select(-c)
# A tibble: 2 x 3
# a         b     d
#  <chr> <dbl> <dbl>
#1 x         1     2
#2 z         3     4

Или более компактно

dat %>%
    mutate(d = replace(lead(b), is.na(c), NA), c = NULL) %>% 
    na.omit

Или с fill

library(tidyr)
dat %>%
   mutate(c1 = c) %>%
   fill(c1) %>% 
   group_by(c1) %>%
   mutate(d = lead(b)) %>% 
   ungroup %>% 
   filter(!is.na(c)) %>% 
   select(-c, -c1)

Или в data.table

library(data.table)
setDT(dat)[, d := shift(b, type = 'lead')][!is.na(c)][, c := NULL][]
#   a b d
#1: x 1 2
#2: z 3 4

ПРИМЕЧАНИЕ. Оба решения просты и не требуют соединений. Кроме того, он дает ожидаемый результат в сообщении OP


Или используя match из base R

cbind(na.omit(dat), d = with(dat, b[match(c, a, nomatch = 0)]))[, -3]
#  a b d
#1 x 1 2
#2 z 3 4
...