2012-07-27 18 views
88

¿Cuál es la mejor manera de asignar a varias columnas usando data.table? Por ejemplo:Asigne varias columnas usando: = en data.table, por grupo

f <- function(x) {c("hi", "hello")} 
x <- data.table(id = 1:10) 

me gustaría hacer algo como esto (por supuesto, esta sintaxis es incorrecta):

x[ , (col1, col2) := f(), by = "id] 

y ampliar para que pueda tener muchas columnas con nombres en una variable (por ejemplo column_names) y me gustaría hacer:

x[ , col_names := another_f(), by = "id", with = FALSE] 

¿Cuál es la forma correcta de hacer algo como esto?

+1

Esto parece que se ha contestado: http://stackoverflow.com/questions/11308754/add-multiple-columns-to-r-data- table-in-one-function-call – Alex

+0

Alex, esa respuesta está cerca, pero no parece funcionar en combinación con 'by', como es correcto decir @Christoph_J. Enlace a su pregunta agregada a [FR # 2120] (https://r-forge.r-project.org/tracker/index.php?func=detail&aid=2120&group_id=240&atid=978) "Drop need with = FALSE for LHS" de: = ", por lo que no se olvidará volver a visitar. –

Respuesta

106

Esto ahora funciona en v1.8.3 en R-Forge. Gracias por destacarlo!

x <- data.table(a = 1:3, b = 1:6) 
f <- function(x) {list("hi", "hello")} 
x[ , c("col1", "col2") := f(), by = a][] 
# a b col1 col2 
# 1: 1 1 hi hello 
# 2: 2 2 hi hello 
# 3: 3 3 hi hello 
# 4: 1 4 hi hello 
# 5: 2 5 hi hello 
# 6: 3 6 hi hello 

x[ , c("mean", "sum") := list(mean(b), sum(b)), by = a][] 
# a b col1 col2 mean sum 
# 1: 1 1 hi hello 2.5 5 
# 2: 2 2 hi hello 3.5 7 
# 3: 3 3 hi hello 4.5 9 
# 4: 1 4 hi hello 2.5 5 
# 5: 2 5 hi hello 3.5 7 
# 6: 3 6 hi hello 4.5 9 

mynames = c("Name1", "Longer%") 
x[ , (mynames) := list(mean(b) * 4, sum(b) * 3), by = a] 
#  a b col1 col2 mean sum Name1 Longer% 
# 1: 1 1 hi hello 2.5 5 10  15 
# 2: 2 2 hi hello 3.5 7 14  21 
# 3: 3 3 hi hello 4.5 9 18  27 
# 4: 1 4 hi hello 2.5 5 10  15 
# 5: 2 5 hi hello 3.5 7 14  21 
# 6: 3 6 hi hello 4.5 9 18  27 


x[ , mynames := list(mean(b) * 4, sum(b) * 3), by = a, with = FALSE][] # same 
# a b col1 col2 mean sum Name1 Longer% 
# 1: 1 1 hi hello 2.5 5 10  15 
# 2: 2 2 hi hello 3.5 7 14  21 
# 3: 3 3 hi hello 4.5 9 18  27 
# 4: 1 4 hi hello 2.5 5 10  15 
# 5: 2 5 hi hello 3.5 7 14  21 
# 6: 3 6 hi hello 4.5 9 18  27 

x[ , get("mynames") := list(mean(b) * 4, sum(b) * 3), by = a][] # same 
# a b col1 col2 mean sum Name1 Longer% 
# 1: 1 1 hi hello 2.5 5 10  15 
# 2: 2 2 hi hello 3.5 7 14  21 
# 3: 3 3 hi hello 4.5 9 18  27 
# 4: 1 4 hi hello 2.5 5 10  15 
# 5: 2 5 hi hello 3.5 7 14  21 
# 6: 3 6 hi hello 4.5 9 18  27 

x[ , eval(mynames) := list(mean(b) * 4, sum(b) * 3), by = a][] # same 
# a b col1 col2 mean sum Name1 Longer% 
# 1: 1 1 hi hello 2.5 5 10  15 
# 2: 2 2 hi hello 3.5 7 14  21 
# 3: 3 3 hi hello 4.5 9 18  27 
# 4: 1 4 hi hello 2.5 5 10  15 
# 5: 2 5 hi hello 3.5 7 14  21 
# 6: 3 6 hi hello 4.5 9 18  27 
+0

Gracias por esta respuesta y los ejemplos. ¿Cómo debo modificar la siguiente línea para obtener dos columnas para cada objectName de la salida tenue, en lugar de una columna con dos filas? 'data.table (objectName = ls()) [, c (" rows "," cols "): = dim (get (objectName)), by = objectName]' (Estoy usando 'data.table' 1.8. 11) – dnlbrky

+0

@dnlbrky 'dim' devuelve un vector, por lo que convertir eso para escribir' list' debe girarlo; p.ej. '[, c (" rows "," cols "): = as.list (dim (get (objectName))), by = objectNa me]'. El problema es que 'as.list' tiene una sobrecarga de llamada y también copia el pequeño vector. Si la eficiencia es un problema a medida que aumenta el número de grupos, háganoslo saber. –

+0

Gracias @Matt_Dowle. Había intentado 'list' pero no' as.list'. La velocidad no es un problema. Solo quería una forma rápida de encontrar objetos en el entorno que tuvieran una cierta cantidad de columnas o filas. Esto está fuera de tema, pero ... ¿qué piensas acerca de agregar NCOL a 'tables()'? – dnlbrky