2016-06-10 18 views
6

Qual è l'approccio data.table idiomatic per produrre un data.table con colonne separate per elementi di un vettore restituito da una funzione, calcolato per gruppo?vettore trasposto per gruppo in data.table

consideri il data.table:

library(data.table) 
data(iris) 
setDT(iris) 

Se la funzione è range(), vorrei l'output simile a:

iris[, .(min_petal_width = min(Petal.Width), 
     max_petal_width = max(Petal.Width) 
     ), keyby = Species] # produces desired output 

ma utilizzando la funzione range().

posso usare dcast, ma è brutto:

dcast(
    iris[, .(petal_width = range(Petal.Width), 
      value = c("min_petal_width", "max_petal_width")), 
     keyby = Species], 
    Species ~ value, value.var = "petal_width") 

Spero ci sia un'espressione più semplice, seguendo le linee di:

iris[, (c("min_petal_width","max_petal_width")) = range(Petal.Width), 
     keyby = Species] # doesn't work 

risposta

5

Il tuo approccio è stato molto vicino. Basta ricordare che è necessario alimentare un elenco per data.table e lo accetterà volentieri. Quindi, è possibile utilizzare:

iris[, c("min_petal_width","max_petal_width") := as.list(range(Petal.Width)), 
    by = Species] 

ho letto male la questione .. Dal momento che si vuole aggregare il risultato invece di aggiungere nuove colonne, si potrebbe usare

cols <- c("min_petal_width", "max_petal_width") 
iris[, setNames(as.list(range(Petal.Width)), cols), keyby = Species] 

Ma sono sicuro che ci sono un pochi altri approcci data.table, anche.

+2

Questo non restituisce un nuovo data.table, ma modifica iride data.table sul posto l'aggiunta di due colonne ad esso – digEmAll

+0

@digEmAll, oh, hai ragione, naturalmente. –

6

È anche possibile fare:

dt[, lapply(list(min=min, max=max), function(f) f(Petal.Width)), by=Species] 
#  Species min max 
# 1:  setosa 0.1 0.6 
# 2: versicolor 1.0 1.8 
# 3: virginica 1.4 2.5 
2

Se la leggibilità e la concisione è veramente importante per voi, vorrei definire una funzione personalizzata o un operatore binario che è quindi possibile utilizzare comodamente in espressione sottoinsieme data.table, per esempio :

# custom function 
.nm <- function(v,vnames){ 
    `names<-`(as.list(v),vnames) 
} 
# custom binary operator 
`%=%` <- function(vnames,v){ 
    `names<-`(as.list(v),vnames) 
} 

# using custom function 
iris[, .nm(range(Petal.Width),c("min_petal_width", "max_petal_width")), keyby = Species] 

# using custom binary operator 
iris[, c("min_petal_width", "max_petal_width") %=% range(Petal.Width), keyby = Species] 
Problemi correlati