Mi pregunta está relacionada con la asignación por referencia versus la copia en data.table
. Quiero saber si uno puede eliminar filas por referencia, similar a
DT[ , someCol := NULL]
Quiero saber sobre
DT[someRow := NULL, ]
Supongo que hay una buena razón por la cual esta función no existe, por lo que tal vez podría señalar una buena alternativa al enfoque de copia habitual, como se muestra a continuación. En particular, yendo con mi favorito de ejemplo (data.table),
DT = data.table(x = rep(c("a", "b", "c"), each = 3), y = c(1, 3, 6), v = 1:9)
# x y v
# [1,] a 1 1
# [2,] a 3 2
# [3,] a 6 3
# [4,] b 1 4
# [5,] b 3 5
# [6,] b 6 6
# [7,] c 1 7
# [8,] c 3 8
# [9,] c 6 9
Digamos que quiero eliminar la primera fila de esta tabla de datos. Sé que puedo hacerlo:
DT <- DT[-1, ]
pero a menudo queremos evitar eso, porque estamos copiando el objeto (y eso requiere aproximadamente 3 * N de memoria, si es N object.size(DT)
, como se señaló aquí . Ahora descubrí set(DT, i, j, value)
. Sé cómo establecer valores específicos (como aquí: establecer todo valores en filas 1 y 2 y columnas 2 y 3 a cero)
set(DT, 1:2, 2:3, 0)
DT
# x y v
# [1,] a 0 0
# [2,] a 0 0
# [3,] a 6 3
# [4,] b 1 4
# [5,] b 3 5
# [6,] b 6 6
# [7,] c 1 7
# [8,] c 3 8
# [9,] c 6 9
Pero, ¿cómo puedo borrar las dos primeras filas, por ejemplo? Haciendo
set(DT, 1:2, 1:3, NULL)
establece todo el DT en NULL.
Mi conocimiento de SQL es muy limitado, así que ustedes me dicen: dado data.table usa tecnología SQL, ¿hay un equivalente al comando SQL?
DELETE FROM table_name
WHERE some_column=some_value
en data.table?
fuente
data.table()
use la tecnología SQL tanto como se pueda establecer un paralelismo entre las diferentes operaciones en SQL y los diversos argumentos de adata.table
. Para mí, la referencia a "tecnología" de alguna manera implica quedata.table
se encuentra en la parte superior de una base de datos SQL en algún lugar, lo que AFAIK no es el caso.DT[ , keep := .I > 1]
, luego, subconjunto para operaciones posteriores:DT[(keep), ...]
quizás inclusosetindex(DT, keep)
la velocidad de este subconjunto. No es una panacea, pero vale la pena considerarla como una opción de diseño en su flujo de trabajo: ¿realmente desea eliminar todas esas filas de la memoria o preferiría excluirlas? La respuesta difiere según el caso de uso.Respuestas:
Buena pregunta.
data.table
No se pueden eliminar filas por referencia todavía.data.table
puede agregar y eliminar columnas por referencia, ya que sobreasigna el vector de punteros de columna, como ya sabe. El plan es hacer algo similar para las filas y permitir rápidoinsert
ydelete
. Una eliminación de fila se usaríamemmove
en C para presupuestar los elementos (en todas y cada una de las columnas) después de las filas eliminadas. Eliminar una fila en el medio de la tabla aún sería bastante ineficiente en comparación con una base de datos de almacén de filas como SQL, que es más adecuada para insertar y eliminar rápidamente filas dondequiera que esas filas estén en la tabla. Pero aún así, sería mucho más rápido que copiar un nuevo objeto grande sin las filas eliminadas.Por otro lado, dado que los vectores de columna se sobreasignarían, las filas podrían insertarse (y eliminarse) al final , al instante; por ejemplo, una serie temporal en crecimiento.
Se presenta como un problema: elimine las filas por referencia .
fuente
fread
primero. Después de eso es bastante alto.DT[b<8 & a>3]
devuelve un nuevo data.table. Nos gustaría agregardelete(DT, b>=8 | a<=3)
yDT[b>=8 | a<=8, .ROW:=NULL]
. La ventaja de este último sería combinar con otras características[]
, como los números de filai
, unirsei
yroll
beneficiarse de la[i,j,by]
optimización.El enfoque que he tomado para hacer que el uso de la memoria sea similar a la eliminación en el lugar es subconjugar una columna a la vez y eliminar. no es tan rápido como una solución C memmove adecuada, pero el uso de memoria es todo lo que me importa aquí. algo como esto:
fuente
memmove
s para reducir las brechas, pero está bien.DT[, col:= NULL, with = F]
enset(DT, NULL, col, NULL)
Aquí hay una función de trabajo basada en la respuesta de @ vc273 y los comentarios de @ Frank.
Y ejemplo de su uso:
Donde "dat" es un data.table. Eliminar 14k filas de 1.4M filas toma 0.25 segundos en mi computadora portátil.
PD. Como soy nuevo en SO, no pude agregar comentarios al hilo de @ vc273 :-(
fuente
En su lugar, o tratando de establecer NULL, intente configurar NA (haciendo coincidir el tipo NA para la primera columna)
fuente
El tema sigue siendo interesante para muchas personas (incluido yo).
¿Qué hay de eso? Solía
assign
reemplazarglovalenv
el código y el descrito anteriormente. Sería mejor capturar el entorno original, pero al menos englobalenv
él es eficiente en memoria y actúa como un cambio por ref.fuente
address(DT); delete(DT, 3); address(DT)
), aunque puede ser eficiente en algún sentido.Aquí hay algunas estrategias que he usado. Creo que puede venir una función .ROW. Ninguno de estos enfoques a continuación son rápidos. Estas son algunas estrategias un poco más allá de los subconjuntos o el filtrado. Traté de pensar como dba solo tratando de limpiar los datos. Como se señaló anteriormente, puede seleccionar o eliminar filas en data.table:
Nota: .SD crea un subconjunto de los datos originales y le permite hacer bastante trabajo en j o data.table posterior. Ver https://stackoverflow.com/a/47406952/305675 . Aquí ordené mis iris por Sepal Length, tome un Sepal.Length especificado como mínimo, seleccione los tres primeros (por Sepal Length) de todas las especies y devuelva todos los datos que lo acompañan:
Los enfoques, sobre todo, reordenan una tabla de datos secuencialmente al eliminar filas. Puede transponer una tabla de datos y eliminar o reemplazar las filas antiguas que ahora son columnas transpuestas. Cuando se usa ': = NULL' para eliminar una fila transpuesta, también se elimina el siguiente nombre de columna:
Cuando transpone el data.frame de nuevo a un data.table, es posible que desee cambiar el nombre del data.table original y restaurar los atributos de la clase en caso de eliminación. La aplicación de ": = NULL" a un data.table ahora transpuesto crea todas las clases de caracteres.
Es posible que solo desee eliminar filas duplicadas que puede hacer con o sin una clave:
También es posible agregar un contador incremental con '.I'. Luego puede buscar claves o campos duplicados y eliminarlos eliminando el registro con el contador. Esto es computacionalmente costoso, pero tiene algunas ventajas ya que puede imprimir las líneas que se eliminarán.
También puede completar una fila con 0 o NA y luego usar una consulta i para eliminarlos:
fuente
t
en un marco data.frame no suele ser una buena idea; verifiquestr(m_iris)
que todos los datos se hayan convertido en una cadena / carácter. Por cierto, también puede obtener números de fila utilizandod_iris[duplicated(Key), which = TRUE]
sin hacer una columna de contador.