首页 文章

重复data.frame的行

提问于
浏览
69

我想重复data.frame的行,每次 N 次 . 结果应该是一个新的 data.frame (带有 nrow(new.df) == nrow(old.df) * N )来保持列的数据类型 .

N = 2的示例:

A B   C
  A B   C             1 j i 100
1 j i 100     -->     2 j i 100
2 K P 101             3 K P 101
                      4 K P 101

因此,每行重复2次,字符仍然是字符,因素仍然是因素,数字仍然是数字,...

我使用的第一次尝试适用: apply(old.df, 2, function(co) rep(co, each = N)) ,但是这个将我的值转换为字符,我得到:

A   B   C    
[1,] "j" "i" "100"
[2,] "j" "i" "100"
[3,] "K" "P" "101"
[4,] "K" "P" "101"

10 回答

  • 3

    添加到@dardisco提到的有关 mefa::rep.data.frame() 的内容,它非常灵活 .

    你可以 repeat each row N times

    rep(df, each=N)
    

    或者 repeat the entire dataframe N times (想一想:当你回收矢量化参数时)

    rep(df, times=N)
    

    两个竖起大拇指 mefa !我从来没有听说过它,我不得不写手动代码来做到这一点 .

  • 6
    df <- data.frame(a=1:2, b=letters[1:2]) 
    df[rep(seq_len(nrow(df)), each=2),]
    
  • 1

    一个干净的 dplyr 解决方案,取自here

    library(dplyr)
    df <- data_frame(x = 1:2, y = c("a", "b"))
    df %>% slice(rep(1:n(), each = 2))
    
  • 2

    如果你可以重复整个事情,或者先将它子集,然后再重复一遍,那么this similar question可能会有所帮助 . 再来一次:

    library(mefa)
    rep(mtcars,10)
    

    或者干脆

    mefa:::rep.data.frame(mtcars)
    
  • 4

    rep.row函数似乎有时会为列创建列表,这会导致错误的内存hijink . 我写了以下似乎运作良好的:

    library(plyr)
    rep.row <- function(r, n){
      colwise(function(x) rep(x, n))(r)
    }
    
  • 0

    有关引用并添加到引用mefa的答案,如果您不想包含整个包,可能需要查看 mefa::rep.data.frame() 的实现:

    > data <- data.frame(a=letters[1:3], b=letters[4:6])
    > data
      a b
    1 a d
    2 b e
    3 c f
    > as.data.frame(lapply(data, rep, 2))
      a b
    1 a d
    2 b e
    3 c f
    4 a d
    5 b e
    6 c f
    
  • 2

    我的解决方案与 mefa:::rep.data.frame 类似,但速度更快,关心行名称:

    rep.data.frame <- function(x, times) {
        rnames <- attr(x, "row.names")
        x <- lapply(x, rep.int, times = times)
        class(x) <- "data.frame"
        if (!is.numeric(rnames))
            attr(x, "row.names") <- make.unique(rep.int(rnames, times))
        else
            attr(x, "row.names") <- .set_row_names(length(rnames) * times)
        x
    }
    

    比较方案:

    library(Lahman)
    library(microbenchmark)
    microbenchmark(
        mefa:::rep.data.frame(Batting, 10),
        rep.data.frame(Batting, 10),
        Batting[rep.int(seq_len(nrow(Batting)), 10), ],
        times = 10
    )
    #> Unit: milliseconds
    #>                                            expr       min       lq     mean   median        uq       max neval cld
    #>              mefa:::rep.data.frame(Batting, 10) 127.77786 135.3480 198.0240 148.1749  278.1066  356.3210    10  a 
    #>                     rep.data.frame(Batting, 10)  79.70335  82.8165 134.0974  87.2587  191.1713  307.4567    10  a 
    #>  Batting[rep.int(seq_len(nrow(Batting)), 10), ] 895.73750 922.7059 981.8891 956.3463 1018.2411 1127.3927    10   b
    
  • 4

    有一个可爱的矢量化解决方案,每个行只能重复n次,例如可以在数据框中添加 ntimes 列:

    A B   C ntimes
    1 j i 100      2
    2 K P 101      4
    3 Z Z 102      1
    

    方法:

    df <- data.frame(A=c("j","K","Z"), B=c("i","P","Z"), C=c(100,101,102), ntimes=c(2,4,1))
    df <- as.data.frame(lapply(df, rep, df$ntimes))
    

    结果:

    A B   C ntimes
    1 Z Z 102      1
    2 j i 100      2
    3 j i 100      2
    4 K P 101      4
    5 K P 101      4
    6 K P 101      4
    7 K P 101      4
    

    这与Josh O'Brien和Mark Miller的方法非常相似:

    df[rep(seq_len(nrow(df)), df$ntimes),]
    

    但是,该方法显得相当慢:

    df <- data.frame(A=c("j","K","Z"), B=c("i","P","Z"), C=c(100,101,102), ntimes=c(2000,3000,4000))
    
    microbenchmark::microbenchmark(
      df[rep(seq_len(nrow(df)), df$ntimes),],
      as.data.frame(lapply(df, rep, df$ntimes)),
      times = 10
    )
    

    结果:

    Unit: microseconds
                                          expr      min       lq      mean   median       uq      max neval
       df[rep(seq_len(nrow(df)), df$ntimes), ] 3563.113 3586.873 3683.7790 3613.702 3657.063 4326.757    10
     as.data.frame(lapply(df, rep, df$ntimes))  625.552  654.638  676.4067  668.094  681.929  799.893    10
    
  • 20

    尝试使用例如

    N=2
    rep(1:4, each = N)
    

    作为一个指标

  • 106

    另一种方法是先获取行索引,附加df的额外副本,然后按索引排序:

    df$index = 1:nrow(df)
    df = rbind(df,df)
    df = df[order(df$index),][,-ncol(df)]
    

    虽然其他解决方案可能更短,但该方法在某些情况下可能更有利 .

相关问题