Tambahkan baris baru ke bingkai data, pada indeks baris tertentu, tidak ditambahkan?

160

Kode berikut menggabungkan vektor dengan bingkai data:

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

Namun kode ini selalu menyisipkan baris baru di akhir kerangka data.

Bagaimana saya bisa memasukkan baris pada titik tertentu dalam kerangka data? Misalnya, katakanlah kerangka data memiliki 20 baris, bagaimana saya bisa menyisipkan baris baru antara baris 10 dan 11?

luciano
sumber
Gunakan indeks yang nyaman dan urutkan?
Roland
22
existingDF = rbind(existingDF[1:10,],newrow,existingDF[-(1:10),])
Pop
Dengan loop sederhana dan kondisi jika diperlukan, baris dapat ditambahkan dari satu bingkai data ke yang lain. Contoh kode seperti yang ditunjukkan di bawah ininewdataframe[nrow(newdataframe)+1,] <- existingdataframe[i,]
kirancodify

Jawaban:

156

Inilah solusi yang menghindari rbindpanggilan (sering lambat) :

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

Jika kecepatan kurang penting daripada kejelasan, maka solusi @ Simon bekerja dengan baik:

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

(Perhatikan kami mengindeks secara rberbeda).

Dan akhirnya, tolok ukur:

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

Tolak ukur

Seperti @MatthewDowle selalu menunjukkan kepada saya, tolok ukur perlu diperiksa untuk penskalaan saat ukuran masalah meningkat. Di sini kita pergi:

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

Solusi @ Roland berskala cukup baik, bahkan dengan panggilan ke 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

Diplot pada skala linier:

linier

Dan skala log-log:

log-log

Ari B. Friedman
sumber
3
Memasukkan baris di bagian akhir memberi perilaku aneh!
Maarten
@ Maarten Dengan fungsi apa?
Ari B. Friedman
Saya kira itu perilaku aneh yang sama yang saya jelaskan di sini: stackoverflow.com/questions/19927806/…
PatrickT
1
Perilaku aneh tidak terjadi dengan insertRow2, di frame dan baris data khusus saya.
PatrickT
Bagaimana Anda hanya menambahkan deretan angka ke df? Saya miliki dfdengan kolom a,b,c,ddan saya ingin menambahkan baris 1,2,3,4. Bagaimana aku melakukan itu?
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
Roland
sumber
3
Ini solusi keren. Masih tidak tahu mengapa itu jauh lebih cepat daripada panggilan simultan rbind, tapi saya tertarik.
Ari B. Friedman
Jawaban dengan tolok ukur harus memiliki reputasi ekstra yang diterapkan secara otomatis IMO. Terima kasih!
Alex
10

Anda harus mencoba paket 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)
}

})

Keluaran

   user  system elapsed 
   0.25    0.00    0.25

Berbeda dengan menggunakan fungsi 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)
    }

})

Keluaran

   user  system elapsed 
   0.49    0.00    0.49 

Ada beberapa peningkatan kinerja.

Naimish Agarwal
sumber
-4

misalnya Anda ingin menambahkan baris variabel 2 ke variabel 1 dari data bernama "edge" lakukan saja seperti ini

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