【问题标题】:Repeating rows of data.frame in dplyr [duplicate]在dplyr中重复data.frame的行[重复]
【发布时间】:2016-11-09 07:01:33
【问题描述】:

我无法使用dplyr 重复我的真实数据行。这里已经有另一个帖子repeat-rows-of-a-data-frame,但dplyr 没有解决方案。

在这里我只是想知道dplyr 的解决方案如何 但失败并出现错误:

错误:错误的结果大小 (16),预期为 4 或 1

library(dplyr)
    df <- data.frame(column = letters[1:4])

    df_rep <- df%>%
      mutate(column=rep(column,each=4))

预期输出

>df_rep 
    column
    #a
    #a
    #a
    #a
    #b
    #b
    #b
    #b
    #*
    #*
    #*

【问题讨论】:

  • 我能想到的唯一方法是通过管道进入do 块,并从当前的data.frame 生成一个你想要的新块(df %&gt;% do(data.frame(column = rep(.$column, 4))))。但是,如果 data.frame 有任何其他列,这将充满危险。
  • @r2evans 效果很好。您可以将其作为答案发送。只需要更改do(data.frame(a = rep(.$a, each=4)))

标签: r dplyr


【解决方案1】:

使用uncount 函数也可以解决这个问题。 count 列表示一行应该重复的频率。

library(tidyverse)

df <- tibble(letters = letters[1:4])

df 
# A tibble: 4 x 1
  letters
  <chr>  
1 a      
2 b      
3 c      
4 d 

df %>%
  mutate(count = c(2, 3, 2, 4)) %>%
  uncount(count)

# A tibble: 11 x 1
   letters
   <chr> 
 1 a      
 2 a      
 3 b      
 4 b      
 5 b      
 6 c      
 7 c      
 8 d      
 9 d      
10 d      
11 d  

【讨论】:

    【解决方案2】:

    我一直在寻找类似(但略有不同)的解决方案。在这里发帖以防对其他人有用。

    就我而言,我需要一个更通用的解决方案,允许每个字母重复任意次数。这是我想出的:

    library(tidyverse)
    
    df <- data.frame(letters = letters[1:4])
    df
    
    > df
      letters
    1       a
    2       b
    3       c
    4       d
    

    假设我想要 2 个 A、3 个 B、2 个 C 和 4 个 D:

    df %>% 
      mutate(count = c(2, 3, 2, 4)) %>% 
      group_by(letters) %>% 
      expand(count = seq(1:count))
    
    # A tibble: 11 x 2
    # Groups:   letters [4]
       letters count
        <fctr> <int>
     1       a     1
     2       a     2
     3       b     1
     4       b     2
     5       b     3
     6       c     1
     7       c     2
     8       d     1
     9       d     2
    10       d     3
    11       d     4
    

    如果不想保留计数栏:

    df %>% 
      mutate(count = c(2, 3, 2, 4)) %>% 
      group_by(letters) %>% 
      expand(count = seq(1:count)) %>% 
      select(letters)
    
    # A tibble: 11 x 1
    # Groups:   letters [4]
       letters
        <fctr>
     1       a
     2       a
     3       b
     4       b
     5       b
     6       c
     7       c
     8       d
     9       d
    10       d
    11       d
    

    如果您希望计数反映每个字母重复的次数:

    df %>% 
      mutate(count = c(2, 3, 2, 4)) %>% 
      group_by(letters) %>% 
      expand(count = seq(1:count)) %>% 
      mutate(count = max(count))
    
    # A tibble: 11 x 2
    # Groups:   letters [4]
       letters count
        <fctr> <dbl>
     1       a     2
     2       a     2
     3       b     3
     4       b     3
     5       b     3
     6       c     2
     7       c     2
     8       d     4
     9       d     4
    10       d     4
    11       d     4
    

    【讨论】:

    • 看起来不错,但在我的经验中这很慢
    • 另一种方法是使用join 操作。您在data.frame 中指定应该为哪个字母附加什么信息,然后将它加入by 列字母。 library(dplyr); df &lt;- data.frame(LETTERS = LETTERS[1:4],letters = c(letters[1:2],letters[1:2])); rows_to_repeat &lt;- bind_rows(data.frame(letters="a", counter=1:2),data.frame(letters="b", counter=1:3)); left_join(df, rows_to_repeat)。请注意,它根据为“a”和“b”指定的规则重复了“C”和“D”行。
    【解决方案3】:

    如果 data.frame 有其他列(我说过!),这很危险,但是 do 块将允许您在 dplyr 管道内生成派生的 data.frame(虽然, ceci n'est pas un pipe):

    library(dplyr)
    df <- data.frame(column = letters[1:4], stringsAsFactors = FALSE)
    df %>%
      do( data.frame(column = rep(.$column, each = 4), stringsAsFactors = FALSE) )
    #    column
    # 1       a
    # 2       a
    # 3       a
    # 4       a
    # 5       b
    # 6       b
    # 7       b
    # 8       b
    # 9       c
    # 10      c
    # 11      c
    # 12      c
    # 13      d
    # 14      d
    # 15      d
    # 16      d
    

    正如@Frank 所建议的,一个更好的选择可能是

    df %>% slice(rep(1:n(), each=4))
    

    【讨论】:

    • 根据我的经验,do 非常慢。你可以slice 喜欢df %&gt;% slice(rep(1:n(), each=4))。这也处理了更多列的情况。
    • 不错的选择,当然更优雅。我试图想出类似的东西,但我的大脑一直在反抗。谢谢,弗兰克! (我同意,do 往往会使事情陷入困境,这是一个已知的瓶颈。)
    【解决方案4】:

    我做了一个快速基准测试,表明uncount()expand() 快​​很多

    # for the pipe
    library(magrittr)
    
    # create some test data
    df_test <- 
      tibble::tibble(
        letter = letters,
        row_count = sample(1:10, size = 26, replace = TRUE)
      )
    
    # benchmark
    bench <- microbenchmark::microbenchmark(
      expand = df_test %>%
        dplyr::group_by(letter) %>%
        tidyr::expand(row_count = seq(1:row_count)),
      uncount = df_test %>%
        tidyr::uncount(row_count)
    )
    
    # plot the benchmark
    ggplot2::autoplot(bench)
    

    【讨论】:

      猜你喜欢
      • 2012-06-22
      • 2018-07-04
      • 2016-05-18
      • 2016-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多