2012-07-19 14 views
149

El siguiente código combina un vector con un trama de datos:¿Agregar una nueva fila al marco de datos, en un índice de fila específico, sin agregar?

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

Sin embargo, este código siempre inserta la nueva fila al final de la trama 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?

+0

¿Utiliza un índice y tipo adecuados? – Roland

+21

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

+0

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

Respuesta

144

he aquí una solución que evite la (a menudo lenta) rbind llamada:

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, a continuación, @ 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 

(índice observamos r de manera diferente).

Y por último, los 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 ser examinados para el escalado como el tamaño del problema aumenta. Aquí vamos a continuación:

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

@ solución de Roland escalas 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 

representa en una escala lineal:

linear

Y una escala de registro-registro:

log-log

+3

¡Insertar una fila al final proporciona un comportamiento extraño! – Maarten

+0

@Maarten ¿Con qué función? –

+0

Supongo que es el mismo comportamiento extraño que describo aquí: http://stackoverflow.com/questions/19927806/efficientlyadd-numeric-columns-and-rows-with-na-and-not-knowing-colnames – PatrickT

36
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 a 'rbind', pero estoy intrigado. –

-4

por ejemplo, desea agregar filas de la variable 2 a la variable 1 de un conjunto de datos llamado "bordes" acaba de hacerlo de esta manera

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

Usted debe tratar dplyr paquete

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 una cierta ganancia de rendimiento.

Cuestiones relacionadas