2017-02-10 3 views
2

J'utilise une fonction smean.cl.normal du package Hmisc qui renvoie un vecteur avec 3 valeurs: la moyenne et les CI inférieur et supérieur. Quand je l'utilise sur un data.table avec 2 groupes, j'obtiens 2 colonnes et 6 lignes. Y a-t-il un moyen d'obtenir le résultat avec deux lignes correspondant à 2 groupes et des colonnes séparées pour chacune des sorties de la fonction, c'est-à-dire la moyenne et les CI?data.table: lapply une fonction avec sortie multicolonne

require(Hmisc) 
require(data.table) 

dt = data.table(x = rnorm(100), 
       gr = rep(c('A', 'B'), each = 50)) 

dt[, lapply(.SD, smean.cl.normal), by = gr, .SDcols = "x"] 

La sortie:

gr   x 
1: A -0.07916335 
2: A -0.33656667 
3: A 0.17823998 
4: B -0.02745333 
5: B -0.32950607 
6: B 0.27459941 

La sortie souhaitée:

gr  Mean   Lower   Upper 
1: A -0.07916335 -0.33656667 0.17823998 
2: B -0.02745333 -0.32950607 0.27459941 
+0

Il y a probablement un meilleur moyen, mais les travaux suivants: 'dt2 <- dcast (dt [, lapply (.SD, smean.cl.normal), par = gr], gr ~ rowid (gr)); setnames (dt2, 2: 4, c ('Mean', 'Lower', 'Upper')) ' – Jaap

+0

Merci. Oui, je l'ai fait avec dcast aussi, c'est juste que je pensais qu'il y avait quelque chose dans 'data.table' qui me manquait. – mattek

+1

se référer à http://stackoverflow.com/questions/27494813/data-table-computing-several-column-at-once –

Répondre

5

L'argument j en DT[i,j,by] prévoit une liste, afin d'utiliser as.list:

dt[, 
    Reduce(c, lapply(.SD, function(x) as.list(smean.cl.normal(x)))) 
, by = gr, .SDcols = "x"] 

# gr  Mean  Lower  Upper 
# 1: A 0.1032966 -0.1899466 0.3965398 
# 2: B -0.1437617 -0.4261330 0.1386096 

c(L1, L2, L3) est la façon dont les listes sont combinées, alors Reduce(c, List_o_Lists) fait l'affaire au cas où votre .SDcols contient plus que juste x. Je suppose que do.call(c, List_o_Lists) devrait également fonctionner.


Commentaires

C'est tout à fait inefficace pour deux raisons. Allumez verbose=TRUE de voir que data.table n'aime pas obtenir des listes nommées dans j:

Le résultat de j est une liste nommée. Il est très inefficace de créer les mêmes noms encore et encore pour chaque groupe. Quand j = list (...), tous les noms sont détectés, supprimés et remis après le regroupement, pour plus d'efficacité. Utiliser j = transform(), par exemple, empêche cette accélération (pensez à changer pour: =). Ce message peut être mis à jour à l'avertissement à l'avenir.

En outre, vous manquez des versions optimisées pour groupes de mean et d'autres fonctions qui peuvent probablement être utilisées pour générer votre résultat. Cela peut ne pas être un gros problème pour votre cas d'utilisation, cependant.


Lorsque vous appliquez cela à une seule colonne de valeur, juste:

dt[, as.list(smean.cl.normal(x)), by = gr] 

suffit.

+1

Incroyable, merci un million pour une réponse en profondeur! – mattek