Belirli bir satır dizininde veri çerçevesine yeni satır eklensin mi?


160

Aşağıdaki kod, bir vektörü bir veri çerçevesiyle birleştirir:

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

Ancak bu kod her zaman yeni çerçeveyi veri çerçevesinin sonuna ekler.

Veri çerçevesi içinde belirtilen bir noktaya nasıl satır ekleyebilirim? Örneğin, veri çerçevesinde 20 satır olduğunu varsayalım, yeni satırı 10 ve 11 satırları arasına nasıl ekleyebilirim?


Uygun bir dizin kullanın ve sıralayın?
Roland

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

Basit bir döngü ve gerekirse bir koşulla, satırlar bir veri çerçevesinden diğerine eklenebilir. Örnek kod aşağıda gösterildiği gibidirnewdataframe[nrow(newdataframe)+1,] <- existingdataframe[i,]
12'de kiran

Yanıtlar:


156

İşte (genellikle yavaş) rbindçağrıyı önleyen bir çözü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

Hız netlikten daha az önemliyse, @ Simon'un çözümü iyi çalışır:

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

( rFarklı indekslediğimizi unutmayın ).

Ve son olarak, kriterler:

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

Deneyler

@MatthewDowle her zaman bana işaret ettiğinden, sorunun boyutu arttıkça ölçeklendirme için ölçütlerin incelenmesi gerekir. İşte o zaman:

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'ın çözümü, şu çağrıda bile oldukça iyi ölçeklenir 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

Doğrusal bir ölçekte çizilmiştir:

doğrusal

Ve bir log-log ölçeği:

log-log


3
Sonuna bir satır eklemek garip davranışlar verir!
Maarten

@Maarten Hangi işlevle?
Ari B. Friedman

Sanırım burada açıkladığım garip davranış bu
PatrickT

1
Belirli veri çerçevemde ve satırımda insertRow2 ile garip davranış oluşmuyor.
PatrickT

Bir df'ye nasıl bir sayı satırı eklersiniz? Ben dfsütunları ile var a,b,c,dve satır eklemek istiyorum 1,2,3,4. Bunu nasıl yaparım?
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
Bu harika bir çözüm. Yine de eşzamanlı çağrıdan neden bu kadar hızlı olduğunu anlayamıyorum rbind, ama merak ediyorum.
Ari B. Friedman

Karşılaştırma ölçütlerine sahip yanıtlarda IMO'nun otomatik olarak ek bir itibarı olmalıdır. Teşekkürler!
Alex

10

Dplyr paketini denemelisiniz

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

})

Çıktı

   user  system elapsed 
   0.25    0.00    0.25

Rbind işlevinin aksine

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

})

Çıktı

   user  system elapsed 
   0.49    0.00    0.49 

Bazı performans kazançları var.


-4

örneğin "kenarlar" adlı bir verinin değişken 1'ine değişken 2 satırları eklemek istersiniz.

allEdges <- data.frame(c(edges$V1,edges$V2))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.