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.tablea adata.frame? Adata.tablees adata.frame. Cualquier operación data.frame simplemente funcionará.data.tableespecificando 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.tablemagia!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=FALSERespuestas:
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
copyfunció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.replaceyis.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 actualizaNApor 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_andriefalla puede deberse a que copia la totalidaddt1o crea una matriz lógica tan grande como la totalidad dedt1algunas 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.setEs 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.tableadecuada de hacer esto. ¡Gracias!DTtiene columnas de tipological, a diferencia delcreate_dt()ejemplo para esta prueba. Cambie el 4to argumento de laset()llamada (que está0en su ejemplo y escriba double en R) aFALSEy debería funcionar sin previo aviso.seq_along(DT)también prefiero . Pero entonces el lector tiene que saber queseq_alongserí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)] <- 0Es 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. >setLas funciones dedicadas (
nafillysetnafill) para ese propósito están disponibles en eldata.tablepaquete (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
ifelsey 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
NAToUnknownen elgdatapaquete. 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
usertiempo similar pero con una gran diferencia deelapsedtiempo.rbenchmarkpara 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 ejecutarbenchmarkambas 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=5creo 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_dowle3pero 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.matrixque es unarraypero se comporta un poco como adata.frame. Debido a que es una matriz, puede usar una sustitución de vectores muy simple para reemplazar elNAs:Una pequeña función auxiliar para eliminar el
NAs. 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.tablede un tamaño determinado.Demostración en una pequeña muestra:
fuente
remove_na. Ese momento de 21.57 incluye elcreate_dt(incluyendorunifysample) 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 hayancolpasado.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
fifelsefunción de lasdata.tableversiones más recientes 1.12.6, es incluso 10 veces más rápido queNAToUnknownen elgdatapaquete:fuente
f_dowle3que aún será más rápido: stackoverflow.com/a/7249454/345660