使用purrr::pmap捕获.f列表名称

11

以下内容正常工作:

pmap_dbl(iris, ~ ..1 + ..2 + ..3 + ..4)

.l的文档提供了一个列表的列表......如果存在列表名称,则将使用列表名称。这表明您应该能够使用列表名称(即列名称)。 然而:


pmap_dbl(iris, ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width)
Error in .f(Sepal.Length = .l[[c(1L, i)]], Sepal.Width = .l[[c(2L, i)]],  : 
  object 'Sepal.Length' not found

实践中如何应用清单名称?

2个回答

10

公式参数 ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width 被传递给purrr :: as_mapper

purrr::as_mapper(~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width)
# function (..., .x = ..1, .y = ..2, . = ..1) 
# Sepal.Length + Sepal.Width + Petal.Length + Petal.Width

你可以看到这个函数没有直接的方式知道这些变量是什么。

我能想到3种解决办法。我将使用 @zacdav 的例子,因为它比你的更简洁易读:

你可以看到这个函数没有直接的方式知道这些变量是什么。

我能想到3种解决办法。我将使用@zacdav的例子,因为它更加紧凑和易于阅读:

named_list <- list(one = c(1, 1),
                   two = c(2, 2),
                   three = c(3, 3))

明确定义

您可以像@zacdav的答案所示那样明确定义这些变量,它将起作用。


探索dots参数

有一种方法可以通过as_mapper返回的函数的...参数访问命名参数。

当存在名称时,函数的参数会被命名,如文档所述。

这就解释了为什么pmap(named_list, function(x,y,z) x+y+z)会失败并显示错误信息:

unused arguments (one = .l[[c(1, i)]], two = .l[[c(2, i)]], three = .l[[c(3, i)]])

请参见:

pmap(named_list, ~names(list(...)))
# [[1]]
# [1] "one"   "two"   "three"
# 
# [[2]]
# [1] "one"   "two"   "three"

另一方面,pmap(unname(named_list), function(x,y,z) x+y+z) 将能够正常工作。

因此这会起作用:

pmap(named_list, ~ with(list(...), one + two + three))
# [[1]]
# [1] 6
# 
# [[2]]
# [1] 6 

使用 pryr::f

pryr 提供了一个与 pryr::f 一起使用的函数定义的简便方式:

library(pryr)
f(one + two + three)
# function (one, three, two) 
# one + two + three

pmap(named_list, f(one + two + three))
# [[1]]
# [1] 6
# 
# [[2]]
# [1] 6
# 

然而,在使用它时要小心,全局变量仍将显示为参数,而函数是否包括在参数中则取决于它们的调用方式。例如:

x <- 1
test <- mean
f(test(x) + lapply(iris,test2))
# function (iris, test2, x) 
# test(x) + lapply(iris, test2)

因此,它不是一个通用的方法,您应该只在简单情况下使用它。第二种方法虽然有点巧妙,但会是通用的。

此外,f 按字母顺序排列参数,在处理命名列表时不应该成为问题,但在处理部分命名列表时要小心。


1
这显然是一种整洁的方法。我从未遇到过 pryr,所以谢谢。 - geotheory

5
library(purrr)
named_list <- list(one = c(1, 1),
                   two = c(2, 2),
                   three = c(3, 3))

pmap(named_list, function(one, two, three) one + two + three)

甚至在 pmap 文档中:

# Matching arguments by name
l <- list(a = x, b = y, c = z)
pmap(l, function(c, b, a) a / (b + c))

这是有效的,因为它期望显然会看到每个命名元素。
pmap_dbl(iris, function(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width, Species) Sepal.Length + Sepal.Width)

看起来你也可以使用...

pmap_dbl(iris, function(Sepal.Length, Sepal.Width, ...) Sepal.Length + Sepal.Width)

理想情况下,这个例子只需在实践中使用rowSums即可。

1
你必须使用一个函数。根据文档说明。 - zacdav
3
请问列表名应该如何利用?使用~来结合列表名似乎是一种整洁的方式。也许这很快就会推出。 - geotheory
我刚发现这个有效:pmap_dbl(as.list(iris), function(Sepal.Length, Sepal.Width, ...) Sepal.Length + Sepal.Width) - zacdav
你在示例中使用的 as.list 是不必要的。 - moodymudskipper
1
@Moody_Mudskipper 是的,没错 - 我只是复制了他的代码。但是我会将其删除。 - zacdav
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接