He mirado StackOverflow, pero no puedo encontrar una solución específica para mi problema, que implica agregar filas a un marco de datos R.
Estoy inicializando un marco de datos de 2 columnas vacío, de la siguiente manera.
df = data.frame(x = numeric(), y = character())
Entonces, mi objetivo es recorrer una lista de valores y, en cada iteración, agregar un valor al final de la lista. Empecé con el siguiente código.
for (i in 1:10) {
df$x = rbind(df$x, i)
df$y = rbind(df$y, toString(i))
}
También he tratado las funciones c
, append
y merge
sin éxito. Por favor, avíseme si tiene alguna sugerencia.
Respuestas:
Actualizar
Sin saber lo que está tratando de hacer, compartiré una sugerencia más: preasigne vectores del tipo que desee para cada columna, inserte valores en esos vectores y luego, al final, cree su archivo
data.frame
.Continuando con Julian's
f3
(una preasignadadata.frame
) como la opción más rápida hasta ahora, definida como:Este es un enfoque similar, pero en el que
data.frame
se crea como último paso.microbenchmark
del paquete "microbenchmark" nos brindará información más completa quesystem.time
:f1()
(el enfoque a continuación) es increíblemente ineficiente debido a la frecuencia con la que llamadata.frame
y porque el crecimiento de objetos de esa manera generalmente es lento en R.f3()
se ha mejorado mucho debido a la preasignación, pero ladata.frame
estructura en sí misma podría ser parte del cuello de botella aquí.f4()
intenta evitar ese cuello de botella sin comprometer el enfoque que desea adoptar.Respuesta original
Esto realmente no es una buena idea, pero si quisiera hacerlo de esta manera, creo que puede intentarlo:
Tenga en cuenta que en su código, hay otro problema:
stringsAsFactors
si desea que los caracteres no se conviertan en factores. Utilizar:df = data.frame(x = numeric(), y = character(), stringsAsFactors = FALSE)
fuente
data.frame
del tamaño final que espera y agregar los valores con[
extracción / reemplazo.Comparemos las tres soluciones propuestas:
La mejor solución es preasignar espacio (como se pretende en R). La siguiente mejor solución es usar
list
, y la peor solución (al menos en función de estos resultados de sincronización) parece serlorbind
.fuente
df <- rbind(df, data.frame(x = i, y = toString(i)))
Suponga que simplemente no conoce el tamaño del data.frame de antemano. Bien pueden ser unas pocas filas o unos pocos millones. Necesita tener algún tipo de contenedor, que crezca dinámicamente. Teniendo en cuenta mi experiencia y todas las respuestas relacionadas en SO, vengo con 4 soluciones distintas:
rbindlist
al data.frameUtilice
data.table
laset
operación rápida y combínela con doblar manualmente la mesa cuando sea necesario.Use
RSQLite
y agregue a la tabla que se guarda en la memoria.data.frame
La propia capacidad de crecer y usar un entorno personalizado (que tiene semántica de referencia) para almacenar el data.frame para que no se copie al regresar.Aquí hay una prueba de todos los métodos para un número pequeño y grande de filas agregadas. Cada método tiene 3 funciones asociadas:
create(first_element)
que devuelve el objeto de respaldo apropiado confirst_element
put in.append(object, element)
que agrega elelement
al final de la tabla (representado porobject
).access(object)
obtiene eldata.frame
con todos los elementos insertados.rbindlist
al data.frameEso es bastante fácil y sencillo:
data.table::set
+ doblando manualmente la mesa cuando sea necesario.Almacenaré la longitud real de la tabla en un
rowcount
atributo.SQL debería estar optimizado para una rápida inserción de registros, por lo que inicialmente tenía grandes esperanzas de
RSQLite
soluciónEsto es básicamente copiar y pegar la respuesta de Karsten W. en un hilo similar.
data.frame
propio entorno personalizado de adición de filas.La suite de pruebas:
Por conveniencia, usaré una función de prueba para cubrirlos todos con llamadas indirectas. (Lo comprobé: usar en
do.call
lugar de llamar a las funciones directamente no hace que el código se ejecute durante más tiempo).Veamos el rendimiento para n = 10 inserciones.
También agregué funciones de 'placebo' (con sufijo
0
) que no realizan nada, solo para medir la sobrecarga de la configuración de la prueba.Para 1E5 filas (mediciones realizadas en CPU Intel (R) Core (TM) i7-4710HQ a 2,50 GHz):
Parece que la sulution basada en SQLite, aunque recupera algo de velocidad en datos grandes, no está ni cerca de data.table + crecimiento exponencial manual. ¡La diferencia es de casi dos órdenes de magnitud!
Resumen
Si sabe que agregará un número bastante pequeño de filas (n <= 100), siga adelante y use la solución más simple posible: simplemente asigne las filas al data.frame usando la notación entre corchetes e ignore el hecho de que el data.frame es no poblado previamente.
Para todo lo demás, use
data.table::set
y haga crecer el data.table exponencialmente (por ejemplo, usando mi código).fuente
Actualización con purrr, tidyr y dplyr
Como la pregunta ya está fechada (6 años), a las respuestas les falta una solución con los paquetes más nuevos tidyr y purrr. Entonces, para las personas que trabajan con estos paquetes, quiero agregar una solución a las respuestas anteriores, todo bastante interesante, especialmente.
La mayor ventaja de purrr y tidyr es una mejor legibilidad en mi humilde opinión. purrr reemplaza lapply con la familia map () más flexible, tidyr ofrece el método súper intuitivo add_row - simplemente hace lo que dice :)
Esta solución es breve e intuitiva de leer, y es relativamente rápida:
Escala casi linealmente, por lo que para 1e5 filas, el rendimiento es:
lo que lo ubicaría en segundo lugar justo después de data.table (si ignora el placebo) en el punto de referencia de @Adam Ryczkowski:
fuente
add_row
. Por ejemplo:map_dfr(1:1e5, function(x) { tibble(x = x, y = toString(x)) })
.bind_rows(df, map_dfr(1:1e5, function(x) { tibble(x = x, y = toString(x)) }))
lugar de usaradd_row
.Tomemos un 'punto' vectorial que tenga números del 1 al 5
point = c(1,2,3,4,5)
si queremos agregar un número 6 en cualquier lugar dentro del vector, el siguiente comando puede ser útil
i) Vectores
new_var = append(point, 6 ,after = length(point))
ii) columnas de una tabla
new_var = append(point, 6 ,after = length(mtcars$mpg))
El comando
append
toma tres argumentos:sencillo...!! Disculpas en caso de alguna ...!
fuente
Una solución más genérica para podría ser la siguiente.
La función extendDf () extiende un marco de datos con n filas.
Como ejemplo:
fuente
Mi solución es casi la misma que la respuesta original, pero no me funcionó.
Entonces, di nombres para las columnas y funciona:
fuente