Thêm hàng mới vào dataframe, tại chỉ mục hàng cụ thể, không được nối thêm?


160

Đoạn mã sau kết hợp một vectơ với khung dữ liệu:

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

Tuy nhiên, mã này luôn chèn hàng mới vào cuối khung dữ liệu.

Làm cách nào tôi có thể chèn hàng tại một điểm được chỉ định trong khung dữ liệu? Ví dụ: giả sử khung dữ liệu có 20 hàng, làm cách nào tôi có thể chèn hàng mới giữa các hàng 10 và 11?


Sử dụng một chỉ số thuận tiện và sắp xếp?
Roland

22
existingDF = rbind(existingDF[1:10,],newrow,existingDF[-(1:10),])
Pop

Với một vòng lặp đơn giản và một điều kiện nếu cần, các hàng có thể được nối từ một khung dữ liệu này sang một khung dữ liệu khác. Mã mẫu được hiển thị bên dướinewdataframe[nrow(newdataframe)+1,] <- existingdataframe[i,]
kirancodify

Câu trả lời:


156

Đây là một giải pháp tránh rbindcuộc gọi (thường chậm) :

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

Nếu tốc độ không quan trọng bằng sự rõ ràng, thì giải pháp của @ Simon hoạt động tốt:

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

(Lưu ý chúng tôi lập chỉ mục r khác nhau).

Và cuối cùng, điểm chuẩn:

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

Điểm chuẩn

Vì @MatthewDowle luôn chỉ ra cho tôi, điểm chuẩn cần được kiểm tra để nhân rộng khi kích thước của vấn đề tăng lên. Sau đó chúng ta đi:

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()

Giải pháp @ Roland quy mô khá tốt, ngay cả với lời kêu gọi 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

Vẽ trên quy mô tuyến tính:

tuyến tính

Và thang đo log-log:

log-log


3
Chèn một hàng ở cuối cho hành vi kỳ lạ!
Maarten

@Maarten Với chức năng nào?
Ari B. Friedman

Tôi đoán đó là hành vi kỳ lạ tương tự mà tôi mô tả ở đây: stackoverflow.com/questions/19927806/iêu
PatrickT

1
Hành vi kỳ lạ không xảy ra với insertRow2, trong khung và hàng dữ liệu cụ thể của tôi.
PatrickT

Làm thế nào để bạn chỉ cần thêm một hàng số vào một df? Tôi có dfvới các cột a,b,c,dvà tôi muốn thêm hàng 1,2,3,4. Làm thế nào để làm điều đó?
Travis Heeter

44
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

3
Đây là một giải pháp tuyệt vời. Vẫn không thể hiểu tại sao nó lại nhanh hơn nhiều so với cuộc gọi đồng thời rbind, nhưng tôi tò mò.
Ari B. Friedman

Câu trả lời với điểm chuẩn sẽ có thêm một số danh tiếng được áp dụng tự động IMO. Cảm ơn!
Alex

10

Bạn nên thử gói 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)
}

})

Đầu ra

   user  system elapsed 
   0.25    0.00    0.25

Ngược lại với việc sử dụng chức năng rbind

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)
    }

})

Đầu ra

   user  system elapsed 
   0.49    0.00    0.49 

Có một số hiệu suất đạt được.


-4

ví dụ: bạn muốn thêm các hàng của biến 2 vào biến 1 của dữ liệu có tên là "các cạnh" chỉ cần làm như thế này

allEdges <- data.frame(c(edges$V1,edges$V2))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.