purrr::map 和 dplyr 的冗余变量命名问题

Redundant variable naming issue with purrr::map and dplyr

我猜这是一个基本问题,根本不是 purrr 特有的,但在这种情况下它让我措手不及。如果这不是关于 purrrdplyr 如何一起玩的话,一般的答案会很好。

我试图命名一个变量,我是 "mapping" 与 d.f 中的变量相同。想匹配,结果出问题。有人可以解释为什么我第一次尝试生成成对差异失败了吗?

这似乎是变量作用域问题或名称冗余的问题,但我不知道到底出了什么问题。显然,我找到了解决方法。

假设我有如下 mydf 这样的数据,并且有很多变量,我想计算每对站点之间这些变量值的差异:

#four sites
site<-rep(c("j", "k", "l", "m"), 3)
#some measurment
val<-1:12
#some variable
vari<-c(rep(1,4), rep(2, 4), rep(3,4))
mydf<-data.frame(site, val, vari)


#compute pairwise differences between values at each site for each variable 
outp<-map_dfr(1:3, function(vari){
    dists<-as.numeric(dist(mydf %>% filter(vari==vari) %>% select(val), method="manhattan"))
    names(dists)<-c("jk","jl", "jm", "kl", "km", "lm" )
    dists
    return(data.frame(t(dists), vari=vari))

})
# looks like there was an issue with using "vari"
outp

#but use a different name for the same variable and it works fine
outp2<-map_dfr(1:3, function(a){
    dists<-as.numeric(dist(mydf %>% filter(vari==a) %>% select(val), method="manhattan"))
    names(dists)<-c("jk","jl", "jm", "kl", "km", "lm" )
    dists
    return(data.frame(t(dists), vari=vari))

})
outp2

edit 如下面的评论和答案所述,这里的问题是 dplyr::filter 中的变量使用,而不是 purrr

如果您 运行 一些简化的代码可能有意义。例如:

# Remove the vector `vari` to avoid confusion.
rm(vari)

# Run using `map` and a simplified function.
map(1:3, function(vari) filter(mydf, vari==vari))

上面对 map return 的调用是一个包含三个数据帧的列表,每个都与 mydf:

相同
[[1]]
   site val vari
1     j   1    1
2     k   2    1
3     l   3    1
4     m   4    1
5     j   5    2
6     k   6    2
7     l   7    2
8     m   8    2
9     j   9    3
10    k  10    3
11    l  11    3
12    m  12    3

[[2]]
   site val vari
1     j   1    1
2     k   2    1
3     l   3    1
4     m   4    1
5     j   5    2
6     k   6    2
7     l   7    2
8     m   8    2
9     j   9    3
10    k  10    3
11    l  11    3
12    m  12    3

[[3]]
   site val vari
1     j   1    1
2     k   2    1
3     l   3    1
4     m   4    1
5     j   5    2
6     k   6    2
7     l   7    2
8     m   8    2
9     j   9    3
10    k  10    3
11    l  11    3
12    m  12    3

很明显,filter(vari == vari) 正在将 mydf$vari 与自身进行比较,这将只是 return mydf 的精确副本。这是一个很好的行为,因为我们总是知道 filter 会比较什么。用临时变量尝试同样的事情 x:

map(1:3, function(x) filter(mydf, vari==x))

哪些 return 是预期的子集:

[[1]]
  site val vari
1    j   1    1
2    k   2    1
3    l   3    1
4    m   4    1

[[2]]
  site val vari
1    j   5    2
2    k   6    2
3    l   7    2
4    m   8    2

[[3]]
  site val vari
1    j   9    3
2    k  10    3
3    l  11    3
4    m  12    3

这基本上就是您在 "workaround" 中所做的——我将其描述为使用适当约定的有效代码,即根本不是解决方法。

aosmith 已经指出您可以使用 tidy 求值。这非常简洁,它肯定有它的用例,但我认为它会反映出在这种特定情况下的不良做法。使用临时变量会使您的代码不那么含糊不清,从而更具可读性。这也是有道理的,因为我们实际上在处理两个不同的事情:vari 是一个包含(重复)值 1、2 和 3 的向量,而 x 本质上是一个临时循环变量,它是1 2 3,取决于迭代。