¿Por qué data.table actualiza nombres (DT) por referencia, incluso si lo asigno a otra variable?

He almacenado los nombres de un data.table como un vector :

 library(data.table) set.seed(42) DT <- data.table(x = runif(100), y = runif(100)) names1 <- names(DT) 

Por lo que puedo decir, es un vector de carácter vainilla simple:

 str(names1) # chr [1:2] "x" "y" class(names1) # [1] "character" dput(names1) # c("x", "y") 

Sin embargo, este no es un vector de caracteres ordinarios. ¡Es un vector de personaje mágico! ¡Cuando agrego una nueva columna a mi data.table , este vector se actualiza!

 DT[ , z := runif(100)] names1 # [1] "x" "y" "z" 

Sé que esto tiene algo que ver con cómo := actualizaciones por asignación, pero esto todavía me parece mágico, ya que espero <- hacer una copia de los nombres de data.table .

Puedo arreglar esto envolviendo los nombres en c() :

 library(data.table) set.seed(42) DT <- data.table(x = runif(100), y = runif(100)) names1 <- names(DT) names2 <- c(names(DT)) all.equal(names1, names2) # [1] TRUE DT[ , z := runif(100)] names1 # [1] "x" "y" "z" names2 # [1] "x" "y" 

Mi pregunta es doble:

  1. ¿Por qué los names1 <- names(DT) crean una copia de los nombres de data.table ? En otros casos, se nos advierte explícitamente que <- crea copias, tanto de data.table s como de data.frame s.
  2. ¿Cuál es la diferencia entre names1 <- names(DT) y names2 <- c(names(DT)) ?

Actualización: ahora se agrega en la documentación para ?copy en la versión 1.9.3. De NOTICIAS :

  1. Se movió ?copy a su propia página de ayuda y documentó que dt_names <- copy(names(DT)) es necesario para que dt_names no se modifique por referencia como resultado de actualizar DT por referencia (por ejemplo, agregar una nueva columna por referencia) . Cierra # 512 . Gracias a Zach por esta pregunta y al usuario1971988 por esta pregunta .

Parte de tu primera pregunta me deja un poco claro en cuanto a lo que realmente quieres decir con <- operator (al menos en el contexto de data.table ), especialmente la parte: en otras instancias, se nos advierte explícitamente que <- crea copias, tanto de data.tables como de data.frames.

Entonces, antes de responder a su pregunta real, la tocaré brevemente aquí. En el caso de una data.table una <- (asignación) simplemente no es suficiente para copiar una data.table . Por ejemplo:

 DT <- data.table(x = 1:5, y= 6:10) # assign DT2 to DT DT2 <- DT # assign by reference, no copy taken. DT2[, z := 11:15] # DT will also have the z column 

Si desea crear una copy , debe mencionarla explícitamente utilizando el comando de copy .

 DT2 <- copy(DT) # copied content to DT2 DT2[, z := 11:15] # only DT2 is affected 

Desde CauchyDistributedRV, entiendo lo que quieres decir con los names(dt) <- . las asignaciones names(dt) <- . eso dará lugar a la advertencia. Lo dejo como tal.


Ahora, para responder a su primera pregunta: Parece que names1 <- names(DT) también se comporta de manera similar. No había pensado / sabido sobre esto hasta ahora. El .Internal(inspect(.)) Es muy útil aquí:

 .Internal(inspect(names1)) # @7fc86a851480 16 STRSXP g0c7 [MARK,NAM(2)] (len=2, tl=100) # @7fc86a069f68 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "x" # @7fc86a0f96d8 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "y" .Internal(inspect(names(DT))) # @7fc86a851480 16 STRSXP g0c7 [MARK,NAM(2)] (len=2, tl=100) # @7fc86a069f68 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "x" # @7fc86a0f96d8 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "y" 

Aquí puede ver que apuntan a la misma ubicación de memoria @7fc86a851480 . Incluso la truelength de los names1 es 100 (que se asigna por defecto en data.table , verifique ?alloc.col para esto).

 truelength(names1) # [1] 100 

Entonces, básicamente, los names1 <- names(dt) asignación1 names1 <- names(dt) parecen suceder por referencia. Es decir, names1 apunta a la misma ubicación que el puntero de nombres de columna de dt.

Para responder a su segunda pregunta: El comando c(.) Parece crear una copia, ya que no se comprueba si el resultado del contenido debido a la operación de concatenación es diferente . Es decir, debido a que la operación c(.) Puede cambiar el contenido del vector, da como resultado inmediatamente que se realice una "copia" sin verificar si los contenidos están modificados.