添加新行到数据框,在特定的行索引,不附加?
下面的代码将一个向量与一个dataframe结合起来:
newrow = c(1:4) existingDF = rbind(existingDF,newrow)
但是,这段代码总是在数据框的末尾插入新行。
如何在数据框内的指定点插入行? 例如,让我们说数据框有20行,我怎样才能插入10行和11行之间的新行?
这是一个避免(通常很慢) rbind
调用的解决scheme:
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的解决scheme效果很好:
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的解决scheme可以很好地扩展,甚至可以调用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
线性标度绘制:
和一个对数标度:
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
你应该尝试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
与使用rbindfunction相反
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
有一些性能增益。
例如,您想要将variables2的行添加到名为“edges”的数据的variables1中,就像这样做
allEdges <- data.frame(c(edges$V1,edges$V2))