purrr::map 和 dplyr 的冗余变量命名问题
Redundant variable naming issue with purrr::map and dplyr
我猜这是一个基本问题,根本不是 purrr
特有的,但在这种情况下它让我措手不及。如果这不是关于 purrr
和 dplyr
如何一起玩的话,一般的答案会很好。
我试图命名一个变量,我是 "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,取决于迭代。
我猜这是一个基本问题,根本不是 purrr
特有的,但在这种情况下它让我措手不及。如果这不是关于 purrr
和 dplyr
如何一起玩的话,一般的答案会很好。
我试图命名一个变量,我是 "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,取决于迭代。