creo que algo parecido a lo siguiente (que utiliza la función relativamente nueva set()
) será más rápida:
DT <- data.table(id = c("A","B","C"), x1 = c(10,20,30), x2 = c(20,30,10))
total <- DT[ , x1 + x2]
rr <- seq_len(nrow(DT))
for(j in 2:3) set(DT, rr, j, DT[[j]]/total)
DT
# id x1 x2
# [1,] A 0.3333333 0.6666667
# [2,] B 0.4000000 0.6000000
# [3,] C 0.7500000 0.2500000
Fwiw, llama a set()
tiene la siguiente forma:
# set(x, i, j, value), where:
# x is a data.table
# i contains row indices
# j contains column indices
# value is the value to be assigned into the specified cells
Mi sospecha acerca de la velocidad relativa de este, en comparación con otras soluciones, se basa en este pasaje de data.table's NEWS file, en el apartado de cambios en la versión 1.8.0:
o New function set(DT,i,j,value) allows fast assignment to elements
of DT. Similar to := but avoids the overhead of [.data.table, so is
much faster inside a loop. Less flexible than :=, but as flexible
as matrix subassignment. Similar in spirit to setnames(), setcolorder(),
setkey() and setattr(); i.e., assigns by reference with no copy at all.
M = matrix(1,nrow=100000,ncol=100)
DF = as.data.frame(M)
DT = as.data.table(M)
system.time(for (i in 1:1000) DF[i,1L] <- i) # 591.000s
system.time(for (i in 1:1000) DT[i,V1:=i]) # 1.158s
system.time(for (i in 1:1000) M[i,1L] <- i) # 0.016s
system.time(for (i in 1:1000) set(DT,i,1L,i)) # 0.027s
Gracias por la respuesta. Me actualicé a data.table 1.8.0 y ejecuté con éxito el código de prueba anterior. Obtengo una advertencia elaborada (no encajaré aquí) sobre la coerción para duplicar cuando tanto el numerador como los denominadores son columnas enteras de data.tables. Editaré la pregunta a ese efecto. –
Estoy teniendo un momento difícil con ediciones de hoy: sin alimentación de línea. De todos modos, aquí está el código: para (j en 2: p) { conjunto (dt, allrows, j, dt [[j]]/denom [[2]]) } y para ambos dt y denom, columnas 2 a p son enteros. La advertencia que recibo es –
"Mensaje de advertencia: En conjunto (dt, allrows, j, dt [[j]]/denom [[2]]): Coaccionó 'doble' RHS a 'entero' para que coincida con el tipo de columna ; puede tener precisión truncada. Cambie la columna de destino a "doble" primero (creando una nueva longitud de vector "doble" 16863 (nrows de toda la tabla) y asigne eso, es decir, columna "reemplazar") o fuerce RHS a "entero" '(por ejemplo, 1L, NA_ [real | integer] _, as. *, etc.) para aclarar su intención y para la velocidad. O bien, configure el tipo de columna correctamente al principio cuando cree la tabla y apéguese a ella, por favor. –