Tengo una gran tabla de datos , con muchos valores perdidos dispersos en sus ~ 200k filas y 200 columnas. Me gustaría volver a codificar esos valores de NA a ceros de la manera más eficiente posible.
Veo dos opciones:
1: convertir a data.frame y usar algo como esto
2: algún tipo de comando de subconfiguración de data.table genial
Estaré contento con una solución bastante eficiente del tipo 1. La conversión a un data.frame y luego de regreso a data.table no llevará demasiado tiempo.
data.table
a adata.frame
? Adata.table
es adata.frame
. Cualquier operación data.frame simplemente funcionará.data.table
especificando el número de columna. entoncesDT[,3]
no dará la tercera columna. Creo que esto hace que la solución propuesta en el enlace sea inviable aquí. ¡Estoy seguro de que hay un enfoque elegante usando algo dedata.table
magia!DT[, 3, with=FALSE]
devuelve la tercera columna.mydf[is.na(mydf) == TRUE]
hace el trabajo en marcos de datos, mientrasmydt[is.na(mydt) == TRUE]
que me da algo extraño incluso si lo usowith=FALSE
Respuestas:
Aquí hay una solución que utiliza el operador de data.table
:=
, basándose en las respuestas de Andrie y Ramnath.Tenga en cuenta que f_dowle actualizó dt1 por referencia. Si se requiere una copia local, entonces se necesita una llamada explícita a la
copy
función para hacer una copia local de todo el conjunto de datos. data.table'ssetkey
,key<-
y:=
no copiar en escritura.A continuación, veamos dónde f_dowle está gastando su tiempo.
Allí, me enfocaría en
na.replace
yis.na
, donde hay algunas copias vectoriales y escaneos vectoriales. Esos pueden eliminarse fácilmente escribiendo una pequeña función na.replace C que se actualizaNA
por referencia en el vector. Eso al menos reduciría a la mitad los 20 segundos, creo. ¿Existe tal función en algún paquete R?La razón por la que
f_andrie
falla puede deberse a que copia la totalidaddt1
o crea una matriz lógica tan grande como la totalidad dedt1
algunas veces. Los otros 2 métodos funcionan en una columna a la vez (aunque solo lo vi brevementeNAToUnknown
).EDITAR (solución más elegante según lo solicitado por Ramnath en los comentarios):
¡Ojalá lo hiciera así para empezar!
EDIT2 (más de 1 año después, ahora)
También existe
set()
. Esto puede ser más rápido si hay muchas columnas en bucle, ya que evita la sobrecarga (pequeña) de llamar[,:=,]
en un bucle.set
Es un loopable:=
. Ver?set
.fuente
eval(parse)...
cosas? En una nota más amplia, creo que sería útil tener operaciones que funcionen en todos los elementos de ladata.table
.data.table
adecuada de hacer esto. ¡Gracias!DT
tiene columnas de tipological
, a diferencia delcreate_dt()
ejemplo para esta prueba. Cambie el 4to argumento de laset()
llamada (que está0
en su ejemplo y escriba double en R) aFALSE
y debería funcionar sin previo aviso.seq_along(DT)
también prefiero . Pero entonces el lector tiene que saber queseq_along
sería a lo largo de las columnas y no en las filas.seq_len(col(DT))
un poquito más explícito por esa razón.Aquí está el más simple que se me ocurrió:
dt[is.na(dt)] <- 0
Es eficiente y no necesita escribir funciones y otro código de pegamento.
fuente
[.data.table
(dt, is.na (dt)): i es un tipo no válido (matriz). Quizás en el futuro una matriz de 2 columnas pueda devolver una lista de elementos de DT (en el espíritu de A [B] en la pregunta frecuente 2.14). Informe a datatable-help si desea esto o agregue sus comentarios a FR # 657. >set
Las funciones dedicadas (
nafill
ysetnafill
) para ese propósito están disponibles en eldata.table
paquete (versión> = 1.12.4):Procesa columnas en paralelo para abordar de forma correcta los puntos de referencia publicados anteriormente, por debajo de sus tiempos frente al enfoque más rápido hasta ahora, y también se amplió, utilizando una máquina de 40 núcleos.
fuente
Solo como referencia, más lento en comparación con gdata o data.matrix, pero usa solo el paquete data.table y puede manejar entradas no numéricas.
fuente
ifelse
y actualizar por referencia haciendoDT[, names(DT) := lapply(.SD, function(x) {x[is.na(x)] <- "0" ; x})]
. Y dudo que sea más lento que las respuestas que has mencionado.Aquí hay una solución que se usa
NAToUnknown
en elgdata
paquete. He usado la solución de Andrie para crear una gran tabla de datos y también incluí comparaciones de tiempo con la solución de Andrie.fuente
user
tiempo similar pero con una gran diferencia deelapsed
tiempo.rbenchmark
para comparar soluciones usando más réplicas, pero obtuve un error de falta de memoria posiblemente debido al tamaño del marco de datos. si puede ejecutarbenchmark
ambas soluciones con múltiples réplicas, esos resultados serían interesantes ya que no estoy realmente seguro de por qué estoy obteniendo una aceleración 3xncol=5
creo que los tiempos en esta respuesta (deberían tomar mucho más tiempo) debido al errorcreate_dt
.En aras de la integridad, otra forma de reemplazar NAs con 0 es usar
Para comparar resultados y tiempos, he incorporado todos los enfoques mencionados hasta ahora.
Entonces, el nuevo enfoque es un poco más lento
f_dowle3
pero más rápido que todos los otros enfoques. Pero para ser honesto, esto va en contra de mi intuición de la sintaxis data.table y no tengo idea de por qué funciona. ¿Alguien puede iluminarme?fuente
Tengo entendido que el secreto para las operaciones rápidas en R es utilizar vectores (o matrices, que son vectores bajo el capó).
En esta solución, utilizo un
data.matrix
que es unarray
pero se comporta un poco como adata.frame
. Debido a que es una matriz, puede usar una sustitución de vectores muy simple para reemplazar elNA
s:Una pequeña función auxiliar para eliminar el
NA
s. La esencia es una sola línea de código. Solo hago esto para medir el tiempo de ejecución.Una pequeña función auxiliar para crear una
data.table
de un tamaño determinado.Demostración en una pequeña muestra:
fuente
remove_na
. Ese momento de 21.57 incluye elcreate_dt
(incluyendorunif
ysample
) junto con elremove_na
. ¿Alguna posibilidad de que puedas editar para dividir las 2 veces?create_dt
? Parece que siempre crea una tabla de datos de 5 columnas, independientemente de lo que se hayancol
pasado.Para generalizar a muchas columnas, puede usar este enfoque (usando datos de muestra anteriores pero agregando una columna):
Aunque no probé la velocidad
fuente
fuente
Usando la
fifelse
función de lasdata.table
versiones más recientes 1.12.6, es incluso 10 veces más rápido queNAToUnknown
en elgdata
paquete:fuente
f_dowle3
que aún será más rápido: stackoverflow.com/a/7249454/345660