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

Я исследовал различные варианты, используя выражения, символы и оценки, но я не могу получить правильный синтаксис.Вот пример кадра данных.

data.frame("A" = letters[1:4], "B" = letters[26:23], "C" = letters[c(1,3,5,7)], "D" = letters[c(2,4,6,8)], "pastecols" = c("B, C","B, D", "B, C, D", NA))
  A B C D pastecols
1 a z a b      B, C
2 b y c d      B, D
3 c x e f   B, C, D
4 d w g h      <NA>

Теперь предположим, что я хочу вставить значения из разных столбцов на основе строки поиска в pastecols, и я всегда хочу включить столбец A. Это мой желаемый результат:

  A B C D pastecols  result
1 a z a b      B, C   a z a
2 b y c d      B, D   b y d
3 c x e f   B, C, D c x e f
4 d w g h      <NA>       d

В идеале это можно сделать в dplyr.Это самое близкое, что я получил:

x %>% mutate(result = lapply(lapply(str_split(pastecols, ", "), c, "A"), na.omit))
  A B C D pastecols     result
1 a z a b      B, C    B, C, A
2 b y c d      B, D    B, D, A
3 c x e f   B, C, D B, C, D, A
4 d w g h      <NA>          A

Ответы [ 3 ]

0 голосов
/ 04 декабря 2018

Вот один из способов, используя pmap, чтобы сделать аналогичную вещь.pmap может использоваться для эффективной работы с кадрами данных по строкам путем захвата каждой строки в качестве именованного вектора;затем вы можете получить нужные имена столбцов для индексации как cols, выбрав их с помощью ["pastecols"].

Большая часть синтаксиса анонимной функции - это не tidyverse материал, а просто элемент R.Чтобы пройти через него:

  1. Передайте фрейм данных в виде списка в аргумент .l pmap_chr.Помните, что кадры данных - это списки столбцов!
  2. Захватите все аргументы ... с помощью c(...).По сути, мы вызываем каждую строку фрейма данных в качестве аргументов функции;теперь row - это именованный вектор, содержащий строку.Обратите внимание, что если у вас есть список-столбцы, это сломается (но так же, как и многое другое, поэтому я предполагаю, что их нет ...)
  3. Мы можем получить значения row, которыемы хотим от row["pastecols"], но нам нужно превратить (скажем) "B, C" в c("A", "B", "C"), чтобы сделать это.Следующая строка просто добавляет "A", заменяет отсутствующие значения на "A", разбивает на части, если они есть, и затем индексирует обратно в список.Часть [[ - это то, как вы делаете list[[1]]" в цепочке труб, это префиксная форма оператора.Вам это нужно, потому что str_split возвращает список, а нам просто нужен вектор.
  4. Используйте этот вектор cols, чтобы получить нужные значения из row и вернуть его, свернутый в символьный вектор длиной 1!
library(tidyverse)
tbl <- tibble("A" = letters[1:4], "B" = letters[26:23], "C" = letters[c(1,3,5,7)], "D" = letters[c(2,4,6,8)], "pastecols" = c("B, C","B, D", "B, C, D", NA))

tbl %>%
  mutate(result = pmap_chr(
    .l = .,
    .f = function(...){
      row <-  c(...)
      cols <- row["pastecols"] %>% str_c("A, ", .) %>% replace_na("A") %>% str_split(", ") %>% `[[`(1)
      vals <- row[cols] %>% str_c(collapse = ", ")
      return(vals)
    }
  ))
#> # A tibble: 4 x 6
#>   A     B     C     D     pastecols result    
#>   <chr> <chr> <chr> <chr> <chr>     <chr>     
#> 1 a     z     a     b     B, C      a, z, a   
#> 2 b     y     c     d     B, D      b, y, d   
#> 3 c     x     e     f     B, C, D   c, x, e, f
#> 4 d     w     g     h     <NA>      d

Создано в 2018-12-03 пакетом Представить (v0.2.0).

0 голосов
/ 04 декабря 2018

Вот другой способ, который не основан на итерации функций в семействах apply или map, если вы предпочитаете их избегать, и пытается использовать сторону tidyr tidyverse.Подход заключается в основном, чтобы расширить фрейм данных с gather и separate_rows на каждую комбинацию pastecols и фактических столбцов, а затем filter, чтобы мы оставляли только те, которые соответствуют для каждого rowid.Получив это, мы можем group_by и summarise вернуть его в один ряд за rowid.Есть куча делопроизводства, чтобы справиться с тем фактом, что у вас всегда есть столбец A, и обратите внимание, что я оставляю A в выводе pastecols, но вы можете удалить это, если хотите.

library(tidyverse)
tbl <- tibble("A" = letters[1:4], "B" = letters[26:23], "C" = letters[c(1,3,5,7)], "D" = letters[c(2,4,6,8)], "pastecols" = c("B, C","B, D", "B, C, D", NA))

tbl %>%
  rowid_to_column() %>%
  mutate(
    pastecols = str_c("A, ", pastecols),
    pastecols = if_else(is.na(pastecols), "A", pastecols)
  ) %>%
  gather(colname, value, -pastecols, -rowid) %>%
  separate_rows(pastecols) %>%
  filter(pastecols == colname) %>%
  group_by(rowid) %>%
  summarise(
    pastecols = str_c(pastecols, collapse = ", "),
    result = str_c(value, collapse = ", ")
  )
#> # A tibble: 4 x 3
#>   rowid pastecols  result    
#>   <int> <chr>      <chr>     
#> 1     1 A, B, C    a, z, a   
#> 2     2 A, B, D    b, y, d   
#> 3     3 A, B, C, D c, x, e, f
#> 4     4 A          d

Создано в 2018-12-03 пакетом Представ (v0.2.0).

0 голосов
/ 03 декабря 2018

Не самое элегантное решение, но выполняет работу только с базовым R. Если столбец A никогда не отображается в pastecols, вы можете удалить unique() из кода.

for(r in seq_len(nrow(df))) {
  df$result[r] <- paste(
                    df[r, na.omit(unique(c("A", unlist(strsplit(df$pastecols[r], ", ")))))],
                    collapse = " "
                  )
}
df

  A B C D pastecols  result
1 a z a b      B, C   a z a
2 b y c d      B, D   b y d
3 c x e f   B, C, D c x e f
4 d w g h      <NA>       d

Данные-

df <- data.frame(
  "A" = letters[1:4], 
  "B" = letters[26:23], 
  "C" = letters[c(1,3,5,7)], 
  "D" = letters[c(2,4,6,8)], 
  "pastecols" = c("B, C","B, D", "B, C, D", NA), stringsAsFactors = F
)
...