在R中不同大小的列表上进行映射/迭代

时间:2019-06-28 17:28:08

标签: r loops tidyverse

我有两个不同的长度列表,并且想生成所有排列以通过R中的函数运行。我可以使用for循环(见下文)来做到这一点,但是我不喜欢使用{{ 1}}和rbind。我无法使其与cbind之类的*applypurrr函数一起使用,因为它们抱怨长度不相等。

最干净的tidyverse友好方法是什么?

下面的简化示例:

map2

这将生成所需的数据帧:

myfun = function(a,b){
    return(a*b)
}
xvalues = c(1,2,3)
yvalues = c(10,20,30,40)

merged = c()
for (x in xvalues){
    z = myfun(x,yvalues)
    merged = rbind(merged,(cbind(x,yvalues,z)))
}

df = data.frame(merged)

2 个答案:

答案 0 :(得分:2)

在要迭代所有组合的情况下,可以使用cross系列功能,例如cross_df来生成列表的产品集。然后,您可以像平常一样使用map函数:

library(tidyverse)
myfun = function(a,b){
  return(a*b)
}
xvalues = c(1,2,3)
yvalues = c(10,20,30,40)

cross_df(list(x = xvalues, y = yvalues)) %>%
  mutate(z = map2_dbl(x, y, myfun))
#> # A tibble: 12 x 3
#>        x     y     z
#>    <dbl> <dbl> <dbl>
#>  1     1    10    10
#>  2     2    10    20
#>  3     3    10    30
#>  4     1    20    20
#>  5     2    20    40
#>  6     3    20    60
#>  7     1    30    30
#>  8     2    30    60
#>  9     3    30    90
#> 10     1    40    40
#> 11     2    40    80
#> 12     3    40   120

当然,在这种情况下,myfun是矢量化的,因此并不需要使用map

cross_df(list(x = xvalues, y = yvalues)) %>%
  mutate(z = myfun(x, y))
#> # A tibble: 12 x 3
#>        x     y     z
#>    <dbl> <dbl> <dbl>
#>  1     1    10    10
#>  2     2    10    20
#>  3     3    10    30
#>  4     1    20    20
#>  5     2    20    40
#>  6     3    20    60
#>  7     1    30    30
#>  8     2    30    60
#>  9     3    30    90
#> 10     1    40    40
#> 11     2    40    80
#> 12     3    40   120

reprex package(v0.3.0)于2019-06-28创建

答案 1 :(得分:1)

有了base R,我们可以使用expand.grid

transform(expand.grid(x= xvalues, yvalues = yvalues), z = myfun(x, yvalues))
#   x yvalues   z
#1  1      10  10
#2  2      10  20
#3  3      10  30
#4  1      20  20
#5  2      20  40
#6  3      20  60
#7  1      30  30
#8  2      30  60
#9  3      30  90
#10 1      40  40
#11 2      40  80
#12 3      40 120

或使用data.table

library(data.table)
CJ(x= xvalues, yvalues)[, z := myfun(x, yvalues)][]