向数据框添加新行,在特定的行索引处,而不是追加?

下面的代码将一个向量与一个数据框架结合在一起:

newrow = c(1:4)
existingDF = rbind(existingDF,newrow)

但是这段代码总是在数据框的末尾插入新行。

如何在数据框架中的指定点插入行?例如,假设数据框架有20行,那么如何在第10行和第11行之间插入新行?

434870 次浏览

这里有一个避免 rbind调用(通常比较慢)的解决方案:

existingDF <- as.data.frame(matrix(seq(20),nrow=5,ncol=4))
r <- 3
newrow <- seq(4)
insertRow <- function(existingDF, newrow, r) {
existingDF[seq(r+1,nrow(existingDF)+1),] <- existingDF[seq(r,nrow(existingDF)),]
existingDF[r,] <- newrow
existingDF
}


> insertRow(existingDF, newrow, r)
V1 V2 V3 V4
1  1  6 11 16
2  2  7 12 17
3  1  2  3  4
4  3  8 13 18
5  4  9 14 19
6  5 10 15 20

如果速度比清晰度更重要,那么@Simon 的解决方案就很有效:

existingDF <- rbind(existingDF[1:r,],newrow,existingDF[-(1:r),])
> existingDF
V1 V2 V3 V4
1   1  6 11 16
2   2  7 12 17
3   3  8 13 18
4   1  2  3  4
41  4  9 14 19
5   5 10 15 20

(注意,我们对 r的索引是不同的)。

最后,基准:

library(microbenchmark)
microbenchmark(
rbind(existingDF[1:r,],newrow,existingDF[-(1:r),]),
insertRow(existingDF,newrow,r)
)


Unit: microseconds
expr     min       lq   median       uq       max
1                       insertRow(existingDF, newrow, r) 660.131 678.3675 695.5515 725.2775   928.299
2 rbind(existingDF[1:r, ], newrow, existingDF[-(1:r), ]) 801.161 831.7730 854.6320 881.6560 10641.417

基准

正如@MatthewDowle 经常向我指出的那样,随着问题规模的扩大,需要检查基准的伸缩性。那我们开始吧:

benchmarkInsertionSolutions <- function(nrow=5,ncol=4) {
existingDF <- as.data.frame(matrix(seq(nrow*ncol),nrow=nrow,ncol=ncol))
r <- 3 # Row to insert into
newrow <- seq(ncol)
m <- microbenchmark(
rbind(existingDF[1:r,],newrow,existingDF[-(1:r),]),
insertRow(existingDF,newrow,r),
insertRow2(existingDF,newrow,r)
)
# Now return the median times
mediansBy <- by(m$time,m$expr, FUN=median)
res <- as.numeric(mediansBy)
names(res) <- names(mediansBy)
res
}
nrows <- 5*10^(0:5)
benchmarks <- sapply(nrows,benchmarkInsertionSolutions)
colnames(benchmarks) <- as.character(nrows)
ggplot( melt(benchmarks), aes(x=Var2,y=value,colour=Var1) ) + geom_line() + scale_x_log10() + scale_y_log10()

@ Roland 的解决方案规模相当大,即使是打电话给 rbind:

                                                              5       50     500    5000    50000     5e+05
insertRow2(existingDF, newrow, r)                      549861.5 579579.0  789452 2512926 46994560 414790214
insertRow(existingDF, newrow, r)                       895401.0 905318.5 1168201 2603926 39765358 392904851
rbind(existingDF[1:r, ], newrow, existingDF[-(1:r), ]) 787218.0 814979.0 1263886 5591880 63351247 829650894

按线性比例绘制:

linear

还有一个对数刻度:

log-log

insertRow2 <- function(existingDF, newrow, r) {
existingDF <- rbind(existingDF,newrow)
existingDF <- existingDF[order(c(1:(nrow(existingDF)-1),r-0.5)),]
row.names(existingDF) <- 1:nrow(existingDF)
return(existingDF)
}


insertRow2(existingDF,newrow,r)


V1 V2 V3 V4
1  1  6 11 16
2  2  7 12 17
3  1  2  3  4
4  3  8 13 18
5  4  9 14 19
6  5 10 15 20


microbenchmark(
+   rbind(existingDF[1:r,],newrow,existingDF[-(1:r),]),
+   insertRow(existingDF,newrow,r),
+   insertRow2(existingDF,newrow,r)
+ )
Unit: microseconds
expr     min       lq   median       uq      max
1                       insertRow(existingDF, newrow, r) 513.157 525.6730 531.8715 544.4575 1409.553
2                      insertRow2(existingDF, newrow, r) 430.664 443.9010 450.0570 461.3415  499.988
3 rbind(existingDF[1:r, ], newrow, existingDF[-(1:r), ]) 606.822 625.2485 633.3710 653.1500 1489.216

例如,您希望将变量2的行添加到名为“ edge”的数据的变量1中 就像这样

allEdges <- data.frame(c(edges$V1,edges$V2))

您应该尝试 dplyr 包

library(dplyr)
a <- data.frame(A = c(1, 2, 3, 4),
B = c(11, 12, 13, 14))




system.time({
for (i in 50:1000) {
b <- data.frame(A = i, B = i * i)
a <- bind_rows(a, b)
}


})

输出

   user  system elapsed
0.25    0.00    0.25

与使用绑定函数相比

a <- data.frame(A = c(1, 2, 3, 4),
B = c(11, 12, 13, 14))




system.time({
for (i in 50:1000) {
b <- data.frame(A = i, B = i * i)
a <- rbind(a, b)
}


})

输出

   user  system elapsed
0.49    0.00    0.49

性能有所提高。

dplyr::add_row中的 .before参数可用于指定行。

dplyr::add_row(
cars,
speed = 0,
dist = 0,
.before = 3
)
#>    speed dist
#> 1      4    2
#> 2      4   10
#> 3      0    0
#> 4      7    4
#> 5      7   22
#> 6      8   16
#> ...

在数据框中的五行之后插入空行,并使用此库包。

library(berryFunctions)


df <- insertRows(df, 5 , new = "")