Ceci est très similaire à une question appliquant une fonction commune à plusieurs colonnes d'un data.table
uning .SDcols
réponse complète ici .
La différence est que je voudrais appliquer simultanément une fonction différente sur une autre colonne qui ne fait pas partie du .SD
sous-ensemble. Je poste un exemple simple ci-dessous pour montrer ma tentative de résoudre le problème:
dt = data.table(grp = sample(letters[1:3],100, replace = TRUE),
v1 = rnorm(100),
v2 = rnorm(100),
v3 = rnorm(100))
sd.cols = c("v2", "v3")
dt.out = dt[, list(v1 = sum(v1), lapply(.SD,mean)), by = grp, .SDcols = sd.cols]
Donne l'erreur suivante:
Error in `[.data.table`(dt, , list(v1 = sum(v1), lapply(.SD, mean)), by = grp,
: object 'v1' not found
Maintenant, cela a du sens parce que le v1
La colonne n'est pas incluse dans le sous-ensemble de colonnes qui doit être évalué en premier. J'ai donc exploré davantage en l'incluant dans mon sous-ensemble de colonnes:
sd.cols = c("v1","v2", "v3")
dt.out = dt[, list(sum(v1), lapply(.SD,mean)), by = grp, .SDcols = sd.cols]
Maintenant, cela ne provoque pas d'erreur mais fournit une réponse contenant 9 lignes (pour 3 groupes), la somme étant répétée trois fois dans la colonne V1
et les moyennes des 3 colonnes (comme prévu mais non souhaitées) placées dans V2
comme indiqué ci-dessous:
> dt.out
grp V1 V2
1: c -1.070608 -0.0486639841313638
2: c -1.070608 -0.178154270921521
3: c -1.070608 -0.137625003604012
4: b -2.782252 -0.0794929150464099
5: b -2.782252 -0.149529237116445
6: b -2.782252 0.199925178109264
7: a 6.091355 0.141659419355985
8: a 6.091355 -0.0272192037753071
9: a 6.091355 0.00815760216214876
Solution de contournement en 2 étapes
Il est clairement possible de résoudre le problème en plusieurs étapes en calculant le mean
par groupe pour le sous-ensemble de colonnes et en le joignant au sum
par groupe pour la colonne unique comme suit:
dt.out1 = dt[, sum(v1), by = grp]
dt.out2 = dt[, lapply(.SD,mean), by = grp, .SDcols = sd.cols]
dt.out = merge(dt.out1, dt.out2, by = "grp")
> dt.out
grp V1 v2 v3
1: a 6.091355 -0.0272192 0.008157602
2: b -2.782252 -0.1495292 0.199925178
3: c -1.070608 -0.1781543 -0.137625004
Je suis sûr que c'est une chose assez simple qui me manque, merci d'avance pour tout conseil.
Mise à jour: Problème # 495 est résolu maintenant avec ce récent commit , nous pouvons maintenant le faire ça va:
require(data.table) # v1.9.7+
set.seed(1L)
dt = data.table(grp = sample(letters[1:3],100, replace = TRUE),
v1 = rnorm(100),
v2 = rnorm(100),
v3 = rnorm(100))
sd.cols = c("v2", "v3")
dt.out = dt[, list(v1 = sum(v1), lapply(.SD,mean)), by = grp, .SDcols = sd.cols]
Notez cependant que dans ce cas, v2
Serait renvoyé sous forme de liste. C'est parce que vous faites list(val, list())
efficacement. Ce que vous avez l'intention de faire est peut-être:
dt[, c(list(v1=sum(v1)), lapply(.SD, mean)), by=grp, .SDcols = sd.cols]
# grp v1 v2 v3
# 1: a -6.440273 0.16993940 0.2173324
# 2: b 4.304350 -0.02553813 0.3381612
# 3: c 0.377974 -0.03828672 -0.2489067
Voir l'historique pour une réponse plus ancienne.
Essaye ça:
dt[,list(sum(v1), mean(v2), mean(v3)), by=grp]
Dans data.table
, L'utilisation de list()
dans le deuxième argument vous permet de décrire un ensemble de colonnes qui aboutissent au data.table
Final.
Pour ce que ça vaut, .SD
Peut être assez lent [^ 1], donc vous voudrez peut-être l'éviter à moins que vous n'ayez vraiment besoin de toutes les données fournies dans le sous-ensemble data.table
Comme vous le feriez pour plus fonction sophistiquée.
Une autre option, si vous avez plusieurs colonnes pour .SDcols
Serait de faire la fusion sur une seule ligne en utilisant la syntaxe de fusion data.table
.
Par exemple:
dt[, sum(v1), by=grp][dt[,lapply(.SD,mean), by=grp, .SDcols=sd.cols]]
Pour utiliser le merge
de data.table
, Vous devez d'abord utiliser setkey()
sur votre data.table
Afin qu'il sache comment faire correspondre les choses.
Donc, vraiment, vous avez d'abord besoin:
setkey(dt, grp)
Ensuite, vous pouvez utiliser la ligne ci-dessus pour produire un résultat équivalent.
[^ 1]: Je trouve cela particulièrement vrai lorsque votre nombre de groupes approche le nombre de lignes totales. Par exemple, cela peut se produire lorsque votre clé est un ID individuel et que de nombreux individus n'ont qu'une ou deux observations.