【问题标题】:Use Dplyr::Bind_Rows and Purrr to Selectively Bind Different Dataframes In a List of Dataframes使用 Dplyr::Bind_Rows 和 Purrr 在数据框列表中选择性地绑定不同的数据框
【发布时间】:2018-01-29 03:47:33
【问题描述】:
library(tidyverse)

我正在尝试使用 tidyverse 工具通过 dplyr::bind_rows() 选择性地绑定数据帧列表。我将拆分 mtcars 数据集以创建我的真实数据的基本复制。

Df<-mtcars%>%
split(.$carb)%>%
head()

我可以将它与 bind_rows() 绑定在一起...

Df<-Df%>%
bind_rows()

但是我如何有选择地绑定列表的元素。我想要做的是创建两个列表 - 第一个绑定列表元素 1、3、6,而第二个绑定 2、4、8。 我在想……

Df<-Df%>%map(~bind_rows(.x,list(.$`1`,.$`3`,.$`6`),list(.$`2`,.$`4`,.$`8`)))

但是这段代码显然是不正确的,所以我很感激一些建议。

【问题讨论】:

    标签: r dplyr tidyverse purrr


    【解决方案1】:

    这可能是另一种方式。我试图在这里反映您的map() 主题。我在base R中使用了Map()。如果你想使用purrr包,我想你可以试试map2()

    foo <- mtcars %>% split(.$carb)
    
    Map(function(x, y) bind_rows(foo[c(x, y)]), c(TRUE, FALSE), c(FALSE, TRUE))
    
    map2(.x = c(TRUE, FALSE), .y = c(FALSE, TRUE), .f = ~ bind_rows(foo[c(.x, .y)]))
    
    [[1]]
        mpg cyl  disp  hp drat    wt  qsec vs am gear carb
    1  22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
    2  21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
    3  18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
    4  32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
    5  33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
    6  21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
    7  27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
    8  16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
    9  17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
    10 15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
    11 19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
    
    [[2]]
        mpg cyl  disp  hp drat    wt  qsec vs am gear carb
    1  18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
    2  24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
    3  22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
    4  30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
    5  15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
    6  15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
    7  19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
    8  26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
    9  30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
    10 21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
    11 21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
    12 21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
    13 14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
    14 19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
    15 17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
    16 10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
    17 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
    18 14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
    19 13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
    20 15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
    21 15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
    

    【讨论】:

    • 我喜欢这个解决方案,但我还不能使用 purrr 的地图让它工作......
    • @Mike 现在我正在玩弄并试图弄清楚map() 选项是如何工作的。我用map2() 尝试了以下想法。 mtcars %&gt;% split(.$carb) %&gt;% map2(.x = c(TRUE, FALSE), .y = c(FALSE, TRUE), .f = ~ bind_rows(.[c(.x, .y)]))。这不起作用,因为. 不表示从前面的代码传递的列表对象。如果我们清楚地指定列表对象,map2() 的想法就会起作用。 foo &lt;- mtcars %&gt;% split(.$carb); map2(.x = c(TRUE, FALSE), .y = c(FALSE, TRUE), .f = ~ bind_rows(foo[c(.x, .y)])).
    • @Mike 再试一次pmap()。这也不起作用。但是,错误消息的内容与map2() 的情况不同。 mtcars %&gt;% split(.$carb) %&gt;% pmap(.l = ., .f = function(x, y) bind_rows(.[c(x, y)]), x = c(TRUE, FALSE), y = c(FALSE, TRUE))。在我看来,这里似乎有必要分解管道。
    • @Mike 我花了一点时间思考了你的问题。我唯一的选择是以下。 map2(.x = c(TRUE, FALSE), .y = c(FALSE, TRUE), .f = ~ bind_rows(split(mtcars, mtcars$carb)[c(.x, .y)]))。如果您放弃使用 %>% 传递数据并将所有内容放入 map2(),那么一切都会对您有利。
    • 感谢您在这方面投入了这么多心思...我喜欢它,只是不确定“c(FALSE, TRUE) 的想法?我猜它是在告诉代码交替加入,但是它不允许以多种不同方式混合列表中各种数据帧的绑定?我的例子太简单了...我希望有一种方法可以让我有选择地绑定任何数据帧...
    【解决方案2】:

    好的,所以我意识到 OP 只是举了一个例子,最初,起点是

    Df<- mtcars%>% split(.$carb)
    

    如果我们这样做,原来的解决方案仍然有效

    lst <- list(x = c(1, 3, 6), y = c(2, 4, 8))
    
    Df %>%
      bind_rows() %>%
      split(.$carb %in% lst[[1]])
    

    但是有没有办法可以直接根据lst绑定呢?

    我不是tidyverse 的专家,但是在通过documentation 之后,我发现了一个函数invoke_map 可以在这里提供我们想要的东西。

    invoke_map(list(
      function(x){x %>% map(. %>% filter(carb %in% lst[[1]])) %>% map_df(c)},
      function(x){x %>% map(. %>% filter(carb %in% lst[[2]])) %>% map_df(c)})
    
    #[[1]]
    # A tibble: 11 x 11
    #     mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
    #   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
    # 1  22.8     4 108.0    93  3.85 2.320 18.61     1     1     4     1
    # 2  21.4     6 258.0   110  3.08 3.215 19.44     1     0     3     1
    # 3  18.1     6 225.0   105  2.76 3.460 20.22     1     0     3     1
    # 4  32.4     4  78.7    66  4.08 2.200 19.47     1     1     4     1
    # 5  33.9     4  71.1    65  4.22 1.835 19.90     1     1     4     1
    # 6  21.5     4 120.1    97  3.70 2.465 20.01     1     0     3     1
    # 7  27.3     4  79.0    66  4.08 1.935 18.90     1     1     4     1
    # 8  16.4     8 275.8   180  3.07 4.070 17.40     0     0     3     3
    # 9  17.3     8 275.8   180  3.07 3.730 17.60     0     0     3     3
    #10  15.2     8 275.8   180  3.07 3.780 18.00     0     0     3     3
    #11  19.7     6 145.0   175  3.62 2.770 15.50     0     1     5     6
    
    #[[2]]
    # A tibble: 21 x 11
    #     mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
    #   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
    # 1  18.7     8 360.0   175  3.15 3.440 17.02     0     0     3     2
    # 2  24.4     4 146.7    62  3.69 3.190 20.00     1     0     4     2
    # 3  22.8     4 140.8    95  3.92 3.150 22.90     1     0     4     2
    # 4  30.4     4  75.7    52  4.93 1.615 18.52     1     1     4     2
    # 5  15.5     8 318.0   150  2.76 3.520 16.87     0     0     3     2
    # 6  15.2     8 304.0   150  3.15 3.435 17.30     0     0     3     2
    # 7  19.2     8 400.0   175  3.08 3.845 17.05     0     0     3     2
    # 8  26.0     4 120.3    91  4.43 2.140 16.70     0     1     5     2
    # 9  30.4     4  95.1   113  3.77 1.513 16.90     1     1     5     2
    #10  21.4     4 121.0   109  4.11 2.780 18.60     1     1     4     2
    # ... with 11 more rows
    

    为我们提供了预期的输出。可能有更好的方法来优化这一点,我不确定。


    原答案:

    为什么不更改您的split 步骤?在不使用bind_rows() 的情况下获取输出。

    lst <- list(x = c(1, 3, 6), y = c(2, 4, 8))
    
    mtcars %>%
      split(.$carb %in% lst[[1]])
    
    
    #$`FALSE`
    #                     mpg cyl  disp  hp drat    wt  qsec vs am gear carb
    #Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
    #Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
    #Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
    #Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
    #Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
    #Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
    #Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
    #Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
    #Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
    #Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
    #Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
    #Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
    #Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
    #AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
    #Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
    #Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
    #Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
    #Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
    #Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
    #Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
    #Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
    
    #$`TRUE`
    #                mpg cyl  disp  hp drat    wt  qsec vs am gear carb
    #Datsun 710     22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
    #Hornet 4 Drive 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
    #Valiant        18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
    #Merc 450SE     16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
    #Merc 450SL     17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
    #Merc 450SLC    15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
    #Fiat 128       32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
    #Toyota Corolla 33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
    #Toyota Corona  21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
    #Fiat X1-9      27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
    #Ferrari Dino   19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
    

    【讨论】:

    • 我只使用“split”来创建假数据,它不适用于我的真实数据。所以对于这个问题,你必须从列表开始。不过我喜欢你的想法……有没有办法将它与 bind_rows 一起使用?
    • @Mike 我刚刚意识到。检查我更新的答案,看看它是否解决了问题。
    【解决方案3】:

    一种简单的方法是在隐式函数中仅使用一个固定参数进行映射。

    picker <- list(c('1', '3', '6'), c('2', '4', '8'))
    my_out <- map(picker, ~'['(Df, .x) %>% bind_rows) 
    
    my_out %>% print 
    

    根据其他答案,我认为您现在想要的是:

    [[1]]
        mpg cyl  disp  hp drat    wt  qsec vs am gear carb
    1  22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
    2  21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
    3  18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
    4  32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
    5  33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
    6  21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
    7  27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
    8  16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
    9  17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
    10 15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
    11 19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
    
    [[2]]
        mpg cyl  disp  hp drat    wt  qsec vs am gear carb
    1  18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
    2  24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
    3  22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
    4  30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
    5  15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
    6  15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
    7  19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
    8  26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
    9  30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
    10 21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
    11 21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
    12 21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
    13 14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
    14 19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
    15 17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
    16 10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
    17 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
    18 14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
    19 13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
    20 15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
    21 15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
    

    注意:我最初很困惑,您是否希望我称之为 picker 的内容成为列表的索引,或者您希望成为列表的名称。这种混淆只是split() 名称列表方式的产物,可能不适用于您的真实数据。

    【讨论】:

    • 我没有太多时间对此进行全面测试,但我不确定它是否符合我的要求。我只是想在列表中堆叠(使用 bind_rows)数据帧 1、3 和 6,以及数据帧 2、4、8,从而生成一个包含两个数据帧的列表。你的方法能做到这一点吗?我不需要混合任何行。
    • 哦,我误会了。在那种情况下,你的工作比我想象的要容易得多(如果我现在理解正确的话。)我会更新我的答案。
    • 答案已编辑。我注意到我的输出与@jazzuro 相同,除了每个数据帧的最后一行。哪个是正确的输出?
    • @jazzuro 是正确的。我喜欢你的解决方案,但不知道为什么它搞砸了最后一部分?快速检查一下,第一部分似乎是 1,3,8,而不是 1,3,6?
    • 哦,我明白了。 split()(用于创建示例数据)创建一个命名列表,其中名称是 carb 的值(即整数)。你想要列表中的第一个、第三个和第六个元素吗? c(1, 3, 6) 是索引],或列表元素 命名 136 [即carb == 1carb == 3carb == 6?]?? 所在的数据帧
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-08
    • 2021-10-26
    • 2012-05-30
    • 1970-01-01
    • 2023-01-27
    • 1970-01-01
    • 2021-09-06
    相关资源
    最近更新 更多