1

这不是问题的重复,例如像 apply with purrr 这样的逐行迭代

我了解如何使用pmap()对数据框进行逐行操作:

library(tidyverse)

df1 = tribble(~col_1, ~col_2, ~col_3,
               1,      5,      12,
               9,      3,      3,
               6,     10,     7)

foo = function(col_1, col_2, col_3) {
  mean(c(col_1, col_2, col_3))
}

df1 %>% pmap_dbl(foo)

这给出了foo应用于每一行的函数:

[1] 6.000000 5.000000 7.666667

但是当我有多个列时,这会变得非常笨拙,因为我必须明确地传递它们。如果我说,我的数据框中有 8 列,df2并且我想应用一个bar可能涉及这些列中的每一列的函数怎么办?

set.seed(12345)
df2 = rnorm(n=24) %>% matrix(nrow=3) %>% as_tibble() %>%
  setNames(c("col_1", "col_2", "col_3", "col_4", "col_5", "col_6", "col_7", "col_8"))

bar = function(col_1, col_2, col_3, col_4, col_5, col_6, col_7, col_8) {
  # imagine we do some complicated row-wise operation here
  mean(c(col_1, col_2, col_3, col_4, col_5, col_6, col_7, col_8))
}

df2 %>% pmap_dbl(bar)

给出:

[1]  0.45085420  0.02639697 -0.28121651

这显然是不够的——我必须bar为每一列添加一个新参数。输入很多,它使代码更不可读且更脆弱。似乎应该有一种方法让它接受一个参数x,然后访问我想要的变量x$col_1等。或者无论如何比上面更优雅的东西。有什么方法可以使用 purrr 清理此代码?

4

3 回答 3

4

...一旦list它们在您的函数中,您就可以使用它们。

dot_tester <- function(...) {
  dots <- list(...)
  dots$Sepal.Length + dots$Petal.Width
}

purrr::pmap(head(iris), dot_tester)
[[1]]
[1] 5.3

[[2]]
[1] 5.1

[[3]]
[1] 4.9

[[4]]
[1] 4.8

[[5]]
[1] 5.2

[[6]]
[1] 5.8

但是,这不会改变您的代码“脆弱”,因为您仍然需要明确且准确地将列名匹配为函数中的名称。奖金不必在<- function()电话中列出。

于 2019-08-05T17:50:38.407 回答
1

@Brian 的回答有效,但我还发现了另一种使用方法purrr::transpose,它可以让我使用单个命名变量x而不是...,并且可以按名称访问任何列:

foo = function(x) {
  (x$col_1 + x$col_2 + x$col_3)/3
}

df1 %>% transpose() %>% map_dbl(foo)

这给出了正确的答案:

[1] 6.000000 5.000000 7.666667

至于其他数据框:

set.seed(12345)
df2 = rnorm(n=24) %>% matrix(nrow=3) %>% as_tibble() %>%
  setNames(c("col_1", "col_2", "col_3", "col_4", "col_5", "col_6", "col_7", "col_8"))

bar = function(x) {
  mean(as.double(x))
}

df2 %>% transpose() %>% map_dbl(bar)

给出:

[1]  0.45085420  0.02639697 -0.28121651

但我也可以通过引用各个列来做到这一点:

bar_2 = function(x) {
  x$col_2 + x$col_5 / x$col_3
}

df2 %>% transpose() %>% map_dbl(bar_2)

[1]  0.1347090 -1.2776983  0.8232767

我意识到这些特定的例子可以很容易地完成,mutate但是在需要真正的逐行迭代的时候,我认为这已经足够好了。

于 2019-08-05T18:46:31.240 回答
1

我能想到的最简单(可能不是最安全)的方法是利用...论点,采用任意数量的列

library(tidyverse)

set.seed(12345)
df2  <-  rnorm(n=24) %>% matrix(nrow=3) %>% as_tibble() %>%
  setNames(c("col_1", "col_2", "col_3", "col_4", "col_5", "col_6", "col_7", "col_8"))
#> Warning: `as_tibble.matrix()` requires a matrix with column names or a `.name_repair` argument. Using compatibility `.name_repair`.
#> This warning is displayed once per session.

bar <- function(...){
  mean(c(...))
}
df2 %>% pmap_dbl(bar)
#> [1]  0.45085420  0.02639697 -0.28121651

reprex 包(v0.3.0)于 2019 年 8 月 5 日创建

于 2019-08-05T17:29:38.110 回答