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

Я пытаюсь расширить существующий набор данных, который в настоящее время выглядит следующим образом:

df <- tibble(
        site = letters[1:3],
        years = rep(4, 3),
        tr = c(3, 6, 4)
)

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

        f <- function(site=NULL, years=NULL, t=NULL){
                df <- tibble(
                        site = rep(site, each = t, times= years),
                        tr = rep(1:t, times = years),
                        year = rep(1:years, each = t)
                        )
                df 
        }

# For one site:
f(site='a',  years=4, t=3)

# Producing this:
# # A tibble: 12 x 3
# site     tr  year
# <chr> <int> <int>
# 1 a         1     1
# 2 a         2     1
# 3 a         3     1
# 4 a         1     2
# 5 a         2     2
# 6 a         3     2
# 7 a         1     3
# 8 a         2     3
# 9 a         3     3
# 10 a         1     4
# 11 a         2     4
# 12 a         3     4

Как эту функцию можно применить к каждой строке входного кадра данных для получения окончательного кадра данных? Одна из функций применения в base r или pmap_df () в пакете purrr могла бы показаться идеальной, но, поскольку я не знал, как работают эти функции, все мои усилия приводили только к ошибкам.

Ответы [ 5 ]

1 голос
/ 06 марта 2020

в базе R вы можете сделать:

do.call(rbind,do.call(Vectorize(f,SIMPLIFY = FALSE),unname(df)))
# A tibble: 52 x 3
   site     tr  year
 * <chr> <int> <int>
 1 a         1     1
 2 a         2     1
 3 a         3     1
 4 a         1     2
 5 a         2     2
 6 a         3     2
 7 a         1     3
 8 a         2     3
 9 a         3     3
10 a         1     4
# ... with 42 more rows
1 голос
/ 06 марта 2020

Если мы хотим применить ту же функцию, используйте pmap

library(purrr)
pmap_dfr(df, ~ f(..1, ..2, ..3))
# A tibble: 52 x 3
#   site     tr  year
# * <chr> <int> <int>
# 1 a         1     1
# 2 a         2     1
# 3 a         3     1
# 4 a         1     2
# 5 a         2     2
# 6 a         3     2
# 7 a         1     3
# 8 a         2     3
# 9 a         3     3
#10 a         1     4
# … with 42 more rows

, другой вариант - condense из версии уровня dplyr

library(tidyr)
df %>%
      group_by(rn = row_number()) %>% 
      condense(out = f(site, years, tr)) %>% 
      unnest(c(out))

Или в base R, мы также можем использовать do.call с Map

do.call(rbind, do.call(Map, c(f, unname(as.data.frame(df)))))
0 голосов
/ 07 марта 2020

Ответ Акруна хорошо сработал для меня, поэтому я изменил его, чтобы сделать функцию, применяемую к каждой строке фрейма данных, немного более явной:


        df1 <- pmap_df(df, function(site, years, tr){
            site = rep(site, each = tr, times=years)
            year = rep(1:years, each = tr)
            tr = rep(1:tr, times=years)
          return(tibble(site, year, tr))
          })
0 голосов
/ 06 марта 2020

Мы можем использовать Map, чтобы применить f к каждому значению site, years и tr.

do.call(rbind, Map(f, df$site, df$years, df$tr))

# A tibble: 52 x 3
#   site     tr  year
# * <chr> <int> <int>
# 1 a         1     1
# 2 a         2     1
# 3 a         3     1
# 4 a         1     2
# 5 a         2     2
# 6 a         3     2
# 7 a         1     3
# 8 a         2     3
# 9 a         3     3
#10 a         1     4
# … with 42 more rows
0 голосов
/ 06 марта 2020
do.call(rbind, lapply(split(df, df$site), function(x){
    with(x, data.frame(site,
               years = rep(sequence(years), each = tr),
               tr = rep(sequence(tr), years)))
}))
...