在数据框中插入多个不相交的行

时间:2014-04-17 15:53:21

标签: r insert dataframe

有效地将多个不相交的行插入数据框或数据表中。我的代码会在每次插入后反复重新评估结果。

我有两个数据框xtmptmpx的补充,需要插入xtmp有一个附加列,第一列,表示tmpx行的正确位置。我在SO上找到了一个解决方案,它涉及在一个位置插入一行,但我无法将其推广到我的需要。

x <- matrix(as.character(seq(100)),20,5)
tmp <- rbind(c(6,letters[1:5]),c(15,LETTERS[1:5]))

此处的链接是SO上提供的解决方案,用于处理将一行插入data.frame stackoverflow.com/questions/11561856/add-new-row-to-dataframe

3 个答案:

答案 0 :(得分:0)

您可以展开x以包含额外的行:

x2 <- x[rep(1:nrow(x), times=ifelse(1:nrow(x) %in% tmp[,1], 2,1)), ]

这会复制原始行号在tmp [,1]中的行。现在您可以插入tmp值

tmp <- tmp[order(tmp[,1]),]
x2[tmp[,1] -1 + 1:nrow(tmp)] <- tmp[,-1]

我们重新命令tmp,以便以正确的顺序插入行。如果需要将第一个元素插入原始的第6行,那么它将进入新的x2。但是第二行需要插入原版的第15行,而第15行已经向下移动了。考虑到之前的插入,这就是为什么我将行偏移j-1,其中j是当前插入计数。

或者你可以这样做:

x2 <- rbind(x, tmp[,-1])[order(c(1:nrow(x), tmp[,1]),]

答案 1 :(得分:0)

以上解决方案非常优雅和简洁。如果您对与原始posting中描述的功能类似的功能感兴趣,以避免对rbind的调用频率较慢,则可以使用此功能:

existingDF <- as.data.frame(matrix(seq(20),nrow=5,ncol=4))
rs <- c(2,4)
newrows <- matrix(seq(-8, -1),nrow=2,ncol=4)
insertRow <- function(existingDF, newrows, rs) {
    rs <- sort(rs) + seq(0, length(rs) - 1)
    old_rs <- seq(nrow(existingDF) + length(rs))[-rs]
    existingDF[old_rs,] <- existingDF
    existingDF[rs,] <- newrows
    existingDF
}

insertRow(existingDF, newrows, rs)

这实质上也会根据要插入的新行数扩展旧数据框,但在重新分配旧数据框时会跳过新行的索引,然后将新行插入适当的位置。

更新:我忘记考虑先前插入引起的行移位,这是rs <- sort(rs) + seq(0, length(rs) - 1)处理的内容(现在行被插入相对于原始数据帧的正确位置,即总是在原始数据框的指定行之前),如果没有它,新行将准确地插入到指定数据框中的位置。

UPDATE2:这是一个修改,直接使用该功能与OP提出的原始数据集

x <- matrix(as.character(seq(100)),20,5)
tmp <- rbind(c(6,letters[1:5]),c(15,LETTERS[1:5]))

insertRow <- function(existingDF, newrows) {
    new_idx <- as.integer(newrows[,1]) # get indices of the new rows
    new_idx <- sort(new_idx) + seq(0, length(new_idx) - 1) # adjust for rows shifting due to other insertions 
    old_idx <- seq(nrow(existingDF) + length(new_idx))[-new_idx] # ge indices for the old rows
    existingDF[old_idx,] <- existingDF # assign old rows
    existingDF[new_idx,] <- newrows[,-1] # assign new rows
    existingDF
}

insertRow(data.frame(x, stringsAsFactors = F), tmp)

答案 2 :(得分:0)

这是我的解决方案,不会构建其他帖子。它适用于rbind,因此它可能更容易理解。

df=matrix(1:40,10,4)
breaks=c(3,5,8)
breaks=append(breaks,nrow(df))
add1=1:4
add2=2:5
add3=3:6
newrows=rbind(add1,add2,add3)
newmat=df[1:breaks[1],]
for(i in 1:(length(breaks)-1)){
newmat=rbind(newmat,newrows[i,],df[(breaks[i]+1):(breaks[i+1]),])}

newmat

当然,您可以随时手动执行所有操作并rbind

newmat=rbind(df[1:breaks[1],],add1,df[(breaks[1]+1):breaks[2],],add2,df[(breaks[2]+1):breaks[3],],add3,df[(breaks[3]+1):nrow(df),])
newmat

<强>替代

提高速度。

insertrows <- function(df,breaks,newrows){#As above we will be adding our new rows in as a matrix. Breaks are a vector and df is the dataframe you want all the rows to go into.
xx=1:length(breaks)
breaks=breaks+xx #To space out the insertion points.
newmat=matrix(NA,length(breaks)+nrow(df),ncol(df)) #Preallocate memory by creating final dataframe.
for(i in 1:length(breaks)){newmat[breaks[i],]=newrows[i,]} #Insert added rows into new dataframe>
x=1:nrow(newmat)
x=x[-(breaks)] #Finding the rows of the new dataframe that will receive old rows
for(i in 1:nrow(df)){newmat[x[i],]=df[i,]} #Notice how we use x to index the new dataframe for placement of old rows.
return(newmat)}

add1=1:4
add2=2:5
add3=3:6
newrows=rbind(add1,add2,add3)
df=matrix(1:40,10,4)
breaks=c(3,5,8)

insertrows(df,breaks,newrows)

这有多快?

非常快。

#Some new data. We're inserting 100 rows into a dataset of 1000 rows. There are 4 columns. 
df=matrix(1:4000,1000,4)
breaks=sample(1:1000,100)
newrows=matrix(1:400,100,4)

library("microbenchmark"
microbenchmark(insertrows(df,breaks,newrows))
Unit: milliseconds
                        expr      min       lq   median       uq      max neval
insertrows(df, breaks, newrows) 3.333208 3.372965 3.408644 3.494566 4.995151   100

让我们破产!

df=matrix(1:400000,100000,4)
breaks=sample(1:100000,10000)
newrows=matrix(1:40000,10000,4)
microbenchmark(insertrows(df,breaks,newrows))
Unit: milliseconds
                        expr     min       lq   median       uq      max neval
insertrows(df, breaks, newrows) 349.581 354.8166 358.2672 409.6821 470.7878   100

请记住这些是毫秒。因此,即使使用这个庞大的数据集,运行时间实际上只有0.36秒。我不担心这里和那里的代码有所改进,但如果你有理由需要比这更快的速度,我会感到惊讶。