¿Agregar nueva fila al marco de datos, en un índice de fila específico, no agregado?


160

El siguiente código combina un vector con un marco de datos:

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

Sin embargo, este código siempre inserta la nueva fila al final del marco de datos.

¿Cómo puedo insertar la fila en un punto específico dentro del marco de datos? Por ejemplo, supongamos que el marco de datos tiene 20 filas, ¿cómo puedo insertar la nueva fila entre las filas 10 y 11?


Utilice un índice conveniente y ordenar?
Roland

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

Con un bucle simple y una condición si es necesario, se pueden agregar filas de un marco de datos a otro. Un código de muestra es el que se muestra a continuaciónnewdataframe[nrow(newdataframe)+1,] <- existingdataframe[i,]
kirancodify

Respuestas:


156

Aquí hay una solución que evita la rbindllamada (a menudo lenta) :

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

Si la velocidad es menos importante que la claridad, entonces la solución de @ Simon funciona bien:

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

(Tenga en cuenta que indexamos de manera rdiferente).

Y finalmente, puntos de referencia:

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

Puntos de referencia

Como @MatthewDowle siempre me señala, los puntos de referencia deben examinarse para determinar la escala a medida que aumenta el tamaño del problema. Aquí vamos entonces:

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

La solución de @ Roland escala bastante bien, incluso con la llamada a 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

Trazado en una escala lineal:

lineal

Y una escala log-log:

log-log


3
¡Insertar una fila al final da un comportamiento extraño!
Maarten

@Maarten ¿Con qué función?
Ari B. Friedman

Supongo que es el mismo comportamiento extraño que estoy describiendo aquí: stackoverflow.com/questions/19927806/…
PatrickT

1
El comportamiento extraño no ocurre con insertRow2, en mi marco de datos particular y fila.
PatrickT

¿Cómo se agrega una fila de números a un df? Tengo dfcon columnas a,b,c,dy quiero agregar la fila 1,2,3,4. ¿Cómo puedo hacer eso?
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
Esta es una solución genial. Todavía no puedo entender por qué es mucho más rápido que la llamada simultánea rbind, pero estoy intrigado.
Ari B. Friedman

Las respuestas con puntos de referencia deberían tener cierta reputación adicional aplicada automáticamente IMO. ¡Gracias!
Alex

10

Deberías probar el paquete 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)
}

})

Salida

   user  system elapsed 
   0.25    0.00    0.25

En contraste con el uso de la función 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)
    }

})

Salida

   user  system elapsed 
   0.49    0.00    0.49 

Hay alguna ganancia de rendimiento.


-4

por ejemplo, desea agregar filas de la variable 2 a la variable 1 de un dato llamado "bordes" simplemente hágalo así

allEdges <- data.frame(c(edges$V1,edges$V2))
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.