【问题标题】:Row-wise iteration like apply with purrr逐行迭代,例如 apply with purrr
【发布时间】:2018-04-04 14:19:17
【问题描述】:

如何使用 purrr::map 实现逐行迭代?

以下是我如何使用标准的逐行应用来做到这一点。

df <- data.frame(a = 1:10, b = 11:20, c = 21:30)

lst_result <- apply(df, 1, function(x){
            var1 <- (x[['a']] + x[['b']])
            var2 <- x[['c']]/2
            return(data.frame(var1 = var1, var2 = var2))
          })

但是,这不是太优雅,我宁愿用 purrr 来做。也可能(或可能不会)更快。

【问题讨论】:

    标签: r apply purrr


    【解决方案1】:

    您可以使用pmap 进行逐行迭代。这些列用作您正在使用的任何函数的参数。在您的示例中,您将有一个三参数函数。

    例如,这里是pmap 使用匿名函数来完成您正在做的工作。列按照它们在数据集中的顺序传递给函数。

    pmap(df, function(a, b, c) {
         data.frame(var1 = a + b,
                    var2 = c/2) 
         }  ) 
    

    您可以使用 purrr 波浪号“速记”来表示匿名函数,方法是按顺序引用前面带有两个点的数字的列。

    pmap(df, ~data.frame(var1 = ..1 + ..2,
                    var2 = ..3/2)  ) 
    

    如果您想将这些特定结果作为 data.frame 而不是列表,您可以使用pmap_dfr

    【讨论】:

    • 在第一个示例中,如果 df 有 100 列并且我只想操作第 90 列,我该怎么办?我知道我可以通过索引号来引用它,但我想通过名称来引用它。
    • @matsuo_basho 如果您只想使用单个列,其他工具可能更合适(例如,dplyr::mutate)。但是,pmap 的文档指出,您始终可以使用... 来“吸收输入 [the] 列表中未使用的组件”。所以如果感兴趣的列被命名为“c”,像pmap(df, function(c, ...) {data.frame(var1 = c/2) }) 这样的东西就可以了。
    • ... 是做什么用的?
    • @AlvaroMorales 它包含所有其余的列名,因此您无需引用pmap() 中的每个列名。 map 系列函数的文档Examples 部分中有一个示例,您可能会发现它很有用!
    【解决方案2】:

    请注意,您在示例中仅使用矢量化操作,因此您可以很好地做到:

    df %>% dplyr::transmute(var1 = a+b,var2 = c/2)
    

    (或在基础 R 中:transform(df,var1 = a+b,var2 = c/2)[4:5]

    如果您使用非向量化函数,例如中位数,您可以使用@aosmith 的答案中的pmap,或使用dplyr::rowwise

    rowwise 速度较慢,包维护人员建议改用map 系列,但在某些情况下,它可以说比pmap 更容易看。当速度不是问题时,我个人仍然使用它:

    library(dplyr)
    df %>% transmute(var3 = pmap(.,~median(c(..1,..2,..3))))
    df %>% rowwise %>% transmute(var3 = median(c(a,b,c)))
    

    (返回严格的未命名列表输出:res %&gt;% split(seq(nrow(.))) %&gt;% unname

    【讨论】:

      【解决方案3】:

      您可以随时对您“喜欢”的函数进行封装。

      rmap <- function (.x, .f, ...) {
          if(is.null(dim(.x))) stop("dim(X) must have a positive length")
          .x <- t(.x) %>% as.data.frame(.,stringsAsFactors=F)
          purrr::map(.x=.x,.f=.f,...)
      }
      

      应用新功能rmaprowwisema​​p

      rmap(df1,~{
          var1 <- (.x[[1]] + .x[[2]])
          var2 <- .x[[3]]/2
          return(data.frame(var1 = var1, var2 = var2))
          })
      

      附加信息:(从上到下评估)

      df1 <- data.frame(a=1:3,b=1:3,c=1:3)
      m   <- matrix(1:9,ncol=3)
      
      apply(df1,1,sum)
      rmap(df1,sum)
      
      apply(m,1,sum)
      rmap(m,sum)
      
      apply(1:10,1,sum)  # intentionally throws an error
      rmap(1:10,sum)     # intentionally throws an error
      

      【讨论】:

        【解决方案4】:

        您可以结合使用pmap...,这对我来说是最好的解决方案,因为我不需要指定参数。

        df <- data.frame(a = 1:10, b = 11:20, c = 21:30)
        
        lst_result <- df %>%
           pmap(function(...) {
               x <- tibble(...)
              return(tibble(var1 = x$a + x$b, var2 = x$c/2))
           })
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-08-08
          • 2021-05-21
          • 1970-01-01
          • 2010-12-06
          • 1970-01-01
          • 2019-09-06
          • 1970-01-01
          相关资源
          最近更新 更多