lista - Crear un datagrama R fila por fila
from vector to data frame r (5)
Este es un ejemplo tonto de cómo usar do.call(rbind,)
en la salida de Map()
[que es similar a lapply()
]
> DF <- do.call(rbind,Map(function(x) data.frame(a=x,b=x+1),x=1:3))
> DF
x y
1 1 2
2 2 3
3 3 4
> class(DF)
[1] "data.frame"
Yo uso este constructo con bastante frecuencia.
Me gustaría construir un marco de datos fila por fila en R. He hecho algunas búsquedas, y todo lo que se me ocurre es la sugerencia de crear una lista vacía, mantener un índice de lista escalar, y luego agregar cada vez a la lista un dataframe de una sola fila y avanzar el índice de la lista por uno. Finalmente, do.call(rbind,)
en la lista.
Mientras esto funciona, parece muy engorroso. ¿No hay una manera más fácil de lograr el mismo objetivo?
Obviamente, me refiero a casos en los que no puedo usar alguna función de apply
y explícitamente necesito crear el marco de datos fila por fila. Al menos, ¿hay alguna forma de push
al final de una lista en lugar de seguir de manera explícita el último índice utilizado?
La razón por la que me gusta mucho Rcpp es que no siempre entiendo cómo piensa R Core, y con Rcpp, la mayoría de las veces, no es necesario.
Hablando filosóficamente, estás en un estado de pecado con respecto al paradigma funcional, que trata de asegurar que cada valor aparezca independientemente de cualquier otro valor; cambiar un valor nunca debe causar un cambio visible en otro valor, la forma en que se obtiene con los punteros que comparten la representación en C.
Los problemas surgen cuando la programación funcional señala a la pequeña nave para que se aparte del camino, y la pequeña nave responde "Soy un faro". Mientras tanto, realizar una larga serie de pequeños cambios en un objeto grande en el que desea procesar, lo coloca en el territorio del faro.
En C ++ STL, push_back()
es una forma de vida. No intenta ser funcional, pero intenta acomodar expresiones de programación comunes de manera eficiente .
Con un poco de inteligencia detrás de escena, a veces puedes organizar tener un pie en cada mundo. Los sistemas de archivos basados en instantáneas son un buen ejemplo (que evolucionó a partir de conceptos tales como monturas de unión, que también abarcan ambos lados).
Si R Core quería hacer esto, el almacenamiento vectorial subyacente podría funcionar como un montaje de unión. Una referencia al almacenamiento vectorial podría ser válida para los subíndices 1:N
, mientras que otra referencia al mismo almacenamiento es válida para los subíndices 1:(N+1)
. Puede haber un almacenamiento reservado que aún no tenga una referencia válida por nada más que conveniente para un push_back()
rápido push_back()
. No infringe el concepto funcional cuando se agrega fuera del rango que cualquier referencia existente considera válida.
Eventualmente agregando filas de forma incremental, se queda sin almacenamiento reservado. Tendrá que crear nuevas copias de todo, con el almacenamiento multiplicado por un incremento. Las implementaciones de STL que he usado tienden a multiplicar el almacenamiento por 2 cuando se extiende la asignación. Creí leer en R Internals que hay una estructura de memoria donde el almacenamiento aumenta en un 20%. De cualquier forma, las operaciones de crecimiento ocurren con una frecuencia logarítmica relativa al número total de elementos anexados. Sobre una base amortizada, esto generalmente es aceptable.
A medida que pasan los trucos tras bambalinas, he visto cosas peores. Cada vez que push_back()
una nueva fila en el marco de datos, una estructura de índice de nivel superior tendría que ser copiada. La nueva fila podría agregarse a la representación compartida sin afectar ningún valor funcional anterior. Ni siquiera creo que eso complicaría mucho al recolector de basura; ya que no estoy proponiendo push_front()
todas las referencias son referencias de prefijos al frente del almacenamiento vectorial asignado.
Puede hacer que crezcan fila por fila al rbind()
o usar rbind()
.
Eso no significa que debas. Las estructuras de crecimiento dinámico es una de las formas menos eficientes de codificar en R.
Si puede, simplemente guarde todos sus datos. Marco en primer plano:
N <- 1e4 # some magic number, possibly an overestimate
DF <- data.frame(num=rep(NA, N), txt=rep("", N), # as many cols as you need
stringsAsFactors=FALSE) # you don''t know levels yet
y luego durante tus operaciones inserta fila a la vez
DF[i, ] <- list(1.4, "foo")
Eso debería funcionar para data.frame arbitrario y ser mucho más eficiente. Si sobrepasa N, siempre puede reducir las filas vacías al final.
Si tiene vectores destinados a convertirse en filas, concatenarlos usando c()
, pasarlos a una matriz fila por fila y convertir esa matriz a un marco de datos.
Por ejemplo, filas
dummydata1=c(2002,10,1,12.00,101,426340.0,4411238.0,3598.0,0.92,57.77,4.80,238.29,-9.9)
dummydata2=c(2002,10,2,12.00,101,426340.0,4411238.0,3598.0,-3.02,78.77,-9999.00,-99.0,-9.9)
dummydata3=c(2002,10,8,12.00,101,426340.0,4411238.0,3598.0,-5.02,88.77,-9999.00,-99.0,-9.9)
se puede convertir a un marco de datos así:
dummyset=c(dummydata1,dummydata2,dummydata3)
col.len=length(dummydata1)
dummytable=data.frame(matrix(data=dummyset,ncol=col.len,byrow=TRUE))
Es cierto que veo 2 limitaciones principales: (1) esto solo funciona con datos de modo único, y (2) debes saber tus # columnas finales para que esto funcione (es decir, supongo que no estás trabajando con un matriz irregular cuya mayor longitud de fila es desconocida a priori ).
Esta solución parece simple, pero según mi experiencia con las conversiones de tipo en R, estoy seguro de que crea nuevos desafíos en línea. ¿Alguien puede comentar sobre esto?
Uno puede agregar filas a NULL
:
df<-NULL;
while(...){
#Some code that generates new row
rbind(df,row)->df
}
por ejemplo
df<-NULL
for(e in 1:10) rbind(df,data.frame(x=e,square=e^2,even=factor(e%%2==0)))->df
print(df)