【问题标题】:How should a function be applied by row on a dataframe to generate a new or expanded dataframe in r如何在数据帧上按行应用函数以在 r 中生成新的或扩展的数据帧
【发布时间】:2020-06-18 16:05:26
【问题描述】:

我正在尝试扩展现有数据集,目前看起来像这样:

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 中的 apply 函数之一或 purrr 包中的 pmap_df() 似乎很理想,但由于不熟悉这些函数的工作原理,我所有的努力都只产生了错误。

【问题讨论】:

    标签: r function tidyverse rowwise


    【解决方案1】:

    如果我们想应用相同的功能,请使用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)))))
    

    【讨论】:

    • 从来不知道如何使用pmap。看过它,现在很好奇在给定数据帧时它何时会采用向量而不是值。
    • @Onyambu 您可以传递一个命名的 data.framed 作为函数参数,然后应用 f 即这里的 'tr' 和 't' 不同 pmap_dfr(set_names(df, c('site', 'years', 't')), f)
    【解决方案2】:
    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)))
    }))
    

    【讨论】:

    • 虽然此代码可能会为问题提供解决方案,但最好添加有关其工作原理/方式的上下文。这可以帮助未来的用户学习并将这些知识应用到他们自己的代码中。在解释代码时,您也可能会以赞成票的形式从用户那里获得积极的反馈。
    【解决方案3】:

    在基础 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
    

    【讨论】:

      【解决方案4】:

      我们可以使用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
      

      【讨论】:

        【解决方案5】:

        Akrun 的回答对我来说效果很好,所以我对其进行了修改,以使函数更明确地应用于数据帧的每一行:

        
                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))
                  })
        

        【讨论】:

          猜你喜欢
          • 2013-04-19
          • 1970-01-01
          • 1970-01-01
          • 2015-02-13
          • 2020-06-21
          • 1970-01-01
          • 2021-03-09
          • 2020-02-01
          • 1970-01-01
          相关资源
          最近更新 更多