используйте mutate (), чтобы добавить столбец к фрейму данных как функцию произвольного набора других столбцов - PullRequest
2 голосов
/ 21 апреля 2020

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

library(tibble)
tmp <- tribble(
  ~ID,     ~x1,     ~x2,
    1,   "200",     NA,
    2,   "300",   "400")

Я хочу добавить новый столбец new, то есть TRUE тогда и только тогда, когда любое из соответствующих значений в x1 и x2 начинается с "3". То есть я хочу

# A tibble: 2 x 4
     ID x1    x2    new  
  <dbl> <chr> <chr> <lgl>
1     1 200   <NA>  NA   
2     2 300   400   TRUE 

В этом примере new является функцией только x1 и x2. Но таких столбцов «х» может быть много, и я не всегда смогу выписать их имена. Они всегда будут начинаться с «x», так что это одно из решений:

tmp %>%
  mutate(
    new = select(., starts_with("x")) %>%
      apply(., 1, function (x) any(substr(x, 1, 1)=="3"))
  )

Но это решение довольно неуклюже. Есть ли более элегантный способ?

Здесь много связанных вопросов, но они обычно говорят о случаях, в которых (a) имена всех столбцов в исходном наборе данных известны и могут быть записаны, или (b) переменная new является функцией всех других столбцов в кадре данных. ( Здесь является одним примером.)

Ответы [ 2 ]

1 голос
/ 22 апреля 2020

Вот вариант с pivot_longer, где мы преобразуем в «длинный» формат с pivot_longer, выполните группировку по «ID», чтобы проверить, есть ли значение any, в котором 3 является первым di git и выполнить объединение с исходным набором данных

library(dplyr)
library(tidyr)
library(stringr)
tmp %>% 
   pivot_longer(cols = -ID, values_drop_na = TRUE) %>% 
   group_by(ID) %>%
   summarise(new = any(str_detect(value, '^3'))) %>% 
   right_join(tmp)
# A tibble: 2 x 4
#     ID new   x1    x2   
#* <dbl> <lgl> <chr> <chr>
#1     1 FALSE 200   <NA> 
#2     2 TRUE  300   400  

. Или, используя base R, мы можем объединить строку с paste и использовать grepl. Должно быть более эффективным

grepl("(^|,)3", do.call(paste, c(tmp[-1], sep=",")))
#[1] FALSE  TRUE
1 голос
/ 21 апреля 2020

Если вы хотите остаться в tidyverse, мы можем использовать pmap для строчной операции:

library(dplyr)
library(purrr)

tmp %>% 
   mutate(new = pmap_lgl(select(., starts_with('x')), 
                ~any(startsWith(c(...), '3'), na.rm = TRUE)))

#     ID x1    x2    new  
#  <dbl> <chr> <chr> <lgl>
#1     1 200   NA    FALSE
#2     2 300   400   TRUE 

В базе R мы можем использовать построчную apply

tmp$new <- apply(tmp[grep('x', names(tmp))], 1, function(x) 
                 any(startsWith(x, '3'), na.rm = TRUE))
...