дублировать фрейм данных n раз с помощью отличительной переменной

#r #dplyr #purrr

#r #dplyr #purrr

Вопрос:

Я хотел бы расти foo , дублируя его n несколько раз, и различать каждую копию foo с уникальным значением новой переменной. Если n равно 3, я могу сделать это подробно с помощью:

 library(tidyverse)

foo <- mtcars %>%
  filter(row_number() < 3)

# desired result
bind_rows(
  foo %>% mutate(key = "a"),
  foo %>% mutate(key = "b"),
  foo %>% mutate(key = "c")
)
#>   mpg cyl disp  hp drat    wt  qsec vs am gear carb key
#> 1  21   6  160 110  3.9 2.620 16.46  0  1    4    4   a
#> 2  21   6  160 110  3.9 2.875 17.02  0  1    4    4   a
#> 3  21   6  160 110  3.9 2.620 16.46  0  1    4    4   b
#> 4  21   6  160 110  3.9 2.875 17.02  0  1    4    4   b
#> 5  21   6  160 110  3.9 2.620 16.46  0  1    4    4   c
#> 6  21   6  160 110  3.9 2.875 17.02  0  1    4    4   c
  

Я пытаюсь найти более экономный способ сделать это. В идеале я хотел бы поместить решение в одну строку, в которую foo передается with %>% .

Моя (неудачная) purrr попытка:

 foo %>%
  map_dfr(c("a", "b", "c"), ~ mutate(., key = .x))
  

Ответ №1:

В вашей попытке использовать purrr » делание foo %>% » вам не помогает, потому что вам не нужно foo быть первым аргументом против map_dfr . Вместо этого вы можете просто сделать:

 map_dfr(c("a", "b", "c"), ~ mutate(foo, key = .x))
  

Если вы хотите продолжать использовать канал, но перестать foo передаваться в качестве первого аргумента, вы можете окружить map_dfr с {} помощью, которая подавляет автоматическую передачу аргументов:

 foo %>%
    { map_dfr(c("a", "b", "c"), function(x) { mutate(., key = x)}) }
  

(могут быть более элегантные способы сделать это с использованием разных magrittr каналов, я в основном придерживаюсь %>% )

Комментарии:

1. Ах. Как-нибудь я могу подавить первый аргумент, чтобы я мог как-то перейти foo к этому? В идеале я хотел бы иметь возможность перенести это в канал, в котором foo оно модифицируется различными способами до и после выполнения этого.

2. Круто, это работает. Должен существовать вариант канала, который не имеет первого аргумента по умолчанию и требует явного размещения точки.

3. @lost «Должен быть вариант канала, который не имеет первого аргумента по умолчанию и требует явного размещения точки». Зачем в этом случае использовать канал? С таким же успехом вы могли бы использовать функцию с явными аргументами функции напрямую. Вся идея конвейера заключается в передаче объекта в LHS в качестве первого аргумента выражения / функции в RHS.

Ответ №2:

Мы можем использовать

 library(tidyverse)
set_names(replicate(3, foo, simplify = FALSE), letters[1:3])  %>% 
               bind_rows(.id = 'key')
  

Или с помощью uncount

 uncount(foo, 3) %>% 
    mutate(key = rep(letters[1:3], each = 2))
  

Или с unnest

 foo %>% 
   mutate(key = list(letters[1:3])) %>% 
   unnest
#  mpg cyl disp  hp drat    wt  qsec vs am gear carb key
#1  21   6  160 110  3.9 2.620 16.46  0  1    4    4   a
#2  21   6  160 110  3.9 2.620 16.46  0  1    4    4   b
#3  21   6  160 110  3.9 2.620 16.46  0  1    4    4   c
#4  21   6  160 110  3.9 2.875 17.02  0  1    4    4   a
#5  21   6  160 110  3.9 2.875 17.02  0  1    4    4   b
#6  21   6  160 110  3.9 2.875 17.02  0  1    4    4   c