在dplyr中重复数据框的行

21

我在使用 dplyr 时遇到了重复我的真实数据行的问题。在这里已经有另一篇帖子repeat-rows-of-a-data-frame,但没有 dplyr 的解决方案。

我想知道如何解决 dplyr 的问题,但尝试失败并出现错误:

Error: wrong result size (16), expected 4 or 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
    #*
    #*
    #*

1
我能想到的唯一方法是将其管道传递到一个 do 块中,并从当前数据框生成一个新的数据框,就像这里所需的那样 (df %>% do(data.frame(column = rep(.$column, 4))))。然而,如果数据框有任何其他列,这种方法就会充满风险。 - r2evans
@r2evans非常好用。你可以将其作为答案发送。只需要更改do(data.frame(a = rep(.$a, each=4)))即可。 - Alexander
4个回答

35
使用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  

15

我在寻找一个类似但稍有不同的解决方案。如果对其他人有用的话,就在这里发布一下。

在我的情况下,我需要一个更通用的解决方案,允许每个字母重复任意次数。这是我想出来的:

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

看起来不错,但根据我的经验,速度非常慢。 - ozgeneral
另一种方法是使用“join”操作。您可以在data.frame中指定应将哪些信息附加到哪个字母,然后通过列字母进行连接。 library(dplyr); df <- data.frame(LETTERS = LETTERS[1:4],letters = c(letters[1:2],letters[1:2])); rows_to_repeat <- 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”。 - fabern

10

如果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))

41
根据我的经验,do 很慢。您可以像这样使用 slicedf %>% slice(rep(1:n(), each=4))。这也适用于更多列的情况。 - Frank
2
很不错的选择,而且更加优雅。我一直在尝试想出类似的东西,但我的大脑一直在反抗。谢谢,弗兰克!(而且我同意,“do”往往会拖累事物,是一个已知的瓶颈。) - r2evans
Frank 在这里提供了最好和最简单的解决方案。 - Jamie Tock
@JamieTock 我同意。这篇文章是很多年前写的,我的技能和软件包都已经发生了变化。我不会去修改所有过去的回答。如果你想提出修改建议,请随意。 - r2evans

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)

Benchmark plot


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接