2015-04-27 17 views
9

Quando si applica una funzione con più variabili di uscita (ad esempio una lista) a un sottoinsieme di un data.table, perdo i nomi delle variabili. C'è un modo per trattenerli?mantenendo i nomi delle colonne in lapply (.SD, ...) per data.table R

library(data.table) 

foo <- function(x){ 
    list(mn = mean(x), sd = sd(x)) 
} 

bar <- data.table(x=1:8, y=c("d","e","f","g")) 

# column names "mn" and "sd" are replaced by "V1" and "V2" 
bar[, sapply(.SD, foo), by = y, .SDcols="x"] 

# column names "mn" and "sd" are retained 
bar_split <- split(bar$x, bar$y) 
t(sapply(bar_split, foo)) 
+0

come su 'bar [, c ("mn", "SD"): = sapply (.SD, foo),. (y) ,. SDcols = "x"] ' – MichaelChirico

+1

Bella domanda. Sarei interessato a farlo per funzioni che restituiscono più di una semplice lista di scalari, qualcosa come 'foo2 <- function (x) list (mn = mean (x), tab = table (x))'. – Frank

risposta

8

vorrei andare arguzia seguente, che è un po 'imbarazzante, ma non richiede la scrittura manuale dei nomi, non importa quante funzioni ci sono

bar[, as.list(unlist(lapply(.SD, foo))), by = y, .SDcols = "x"] 
# y x.mn  x.sd 
# 1: d 3 2.828427 
# 2: e 4 2.828427 
# 3: f 5 2.828427 
# 4: g 6 2.828427 

Il più grande vantaggio di questo approccio è che lega le funzioni con i nomi delle colonne. Se, ad esempio, si avrebbe una colonna aggiuntiva, sarà ancora dare un risultato informativo, mentre utilizzando lo stesso codice come sopra

set.seed(1) 
bar[, z := sample(8)] 
bar[, as.list(unlist(lapply(.SD, foo))), by = y, .SDcols = c("x", "z")] 
# y x.mn  x.sd z.mn  z.sd 
# 1: d 3 2.828427 2.0 1.4142136 
# 2: e 4 2.828427 7.5 0.7071068 
# 3: f 5 2.828427 3.0 1.4142136 
# 4: g 6 2.828427 5.5 0.7071068 
+0

'' x' deve essere quotato come '" x "'? - Almeno in 1.9.4. – thelatemail

+0

@thelatemail Buon punto, sto usando '1.9.5'. Fisso. A proposito, in '1.9.5' ora puoi fare cose come' .SDcols = x: y', per esempio. –

+0

Questo funziona per i casi più semplici, ma è possibile usare 'replicate' invece di' lapply' o 'sapply' senza creare' n' nuove colonne? Ad esempio, 'bar [, replicate (n = 3, foo (.SD $ x)),. (Y)]' aggiunge una nuova coppia di colonne per ogni replica e 'as.list (unlist (...)) il trucco non sembra mantenere i nomi delle colonne. – Bryan

0

La funzione setNames consente di aggiungere di nuovo il vettore di carattere mancante .:

bar[, setNames(sapply(.SD, foo), c("mn", "sd")), by = y, .SDcols="x"] 
    y mn  sd 
1: d 3 2.828427 
2: e 4 2.828427 
3: f 5 2.828427 
4: g 6 2.828427 

Gli autori hanno suggerito utilizzando l'altra forma suggerita da Arenburg:

DT[, c('x2', 'y2') := list(x/sum(x), y/sum(y)), by = grp] 
Problemi correlati