3 votes

Agrégation si chaque observation peut appartenir à plusieurs groupes

Je veux agréger les données par groupe. Cependant, chaque observation peut appartenir à plusieurs groupes (par exemple, l'observation 1 appartient aux groupes A et B). Je n'ai pas pu trouver une manière agréable de réaliser ceci avec data.table . Actuellement, j'ai créé pour chacun des groupes possibles une variable logique qui prend la valeur TRUE si l'observation appartient à ce groupe. Je cherche une meilleure façon de le faire que celle présentée ci-dessous. J'aimerais également savoir comment je pourrais y parvenir avec la fonction tidyverse .

library(data.table)
# Data
set.seed(1)
TF <- c(TRUE, FALSE)
time <- rep(1:4, each = 5)
df <- data.table(time = time, x = rnorm(20), groupA = sample(TF, size = 20, replace = TRUE),
                                             groupB = sample(TF, size = 20, replace = TRUE),
                                             groupC = sample(TF, size = 20, replace = TRUE))

# This should be nicer and less repetitive
df[groupA == TRUE, .(A = sum(x)), by = time][
  df[groupB == TRUE, .(B = sum(x)), by = time], on = "time"][
    df[groupC == TRUE, .(C = sum(x)), by = time], on = "time"]

# desired output
time          A          B         C
1:    1         NA  0.9432955 0.1331984
2:    2  1.2257538  0.2427420 0.1882493
3:    3 -0.1992284 -0.1992284 1.9016244
4:    4  0.5327774  0.9438362 0.9276459

3voto

jogo Points 9208

Voici une solution avec data.table :

df[, lapply(.SD[, .(groupA, groupB, groupC)]*x, sum), time]
# > df[, lapply(.SD[, .(groupA, groupB, groupC)]*x, sum), time]
#    time     groupA     groupB    groupC
# 1:    1  0.0000000  0.9432955 0.1331984
# 2:    2  1.2257538  0.2427420 0.1882493
# 3:    3 -0.1992284 -0.1992284 1.9016244
# 4:    4  0.5327774  0.9438362 0.9276459

ou (merci à @chinsoon12 pour le commentaire) de manière plus programmatique :

df[, lapply(.SD*x, sum), by=.(time), .SDcols=paste0("group", c("A","B","C"))]

Si vous voulez le résultat dans le format long, vous pouvez le faire :

df[, colSums(.SD*x), by=.(time), .SDcols=paste0("group", c("A","B","C"))]
### with indicator for the group:
df[, .(colSums(.SD*x), c("A","B","C")), by=.(time), .SDcols=paste0("group", c("A","B","C"))]

2voto

Jack Brookes Points 2749

Je pense qu'il est plus facile ici de travailler en format long. D'abord je rassemble les observations au format long, puis je ne garde que les valeurs où l'observation appartient au groupe correspondant. Ensuite, je supprime la colonne logique et je renomme les groupes en lettres simples. Ensuite, j'agrège à travers les groupes et le temps (résumer en dplyr ). Finalement, je suis revenu au format large.

library(dplyr)
library(tidyr)

set.seed(1)
TF <- c(TRUE, FALSE)
time <- rep(1:4, each = 5)

df <- data.frame(time = time, x = rnorm(20), groupA = sample(TF, size = 20, replace = TRUE),
                 groupB = sample(TF, size = 20, replace = TRUE),
                 groupC = sample(TF, size = 20, replace = TRUE))

df %>% 
  gather(group, belongs, groupA:groupC) %>% 
  filter(belongs) %>% 
  select(-belongs) %>% 
  mutate(group = gsub("group", "", group)) %>% 
  group_by(time, group) %>% 
  summarise(x = sum(x)) %>% 
  spread(group, x)

Sortie

# A tibble: 4 x 4
# Groups:   time [4]
   time       A      B     C
  <int>   <dbl>  <dbl> <dbl>
1     1  NA      0.943 0.133
2     2   1.23   0.243 0.188
3     3  -0.199 -0.199 1.90 
4     4   0.533  0.944 0.928

1voto

MKR Points 16303

Une option peut être d'utiliser tidyr y dplyr en combinaison avec data.table . Essayez de travailler sur des données au format long, puis passez au format large.

library(dplyr)
library(tidyr)

melt(df, id.vars = c("time", "x")) %>%
  filter(value) %>%
  group_by(time, variable) %>%
  summarise(sum = sum(x)) %>%
  spread(variable, sum)

# # A tibble: 4 x 4
# # Groups: time [4]
# time  groupA groupB groupC
# * <int>   <dbl>  <dbl>  <dbl>
# 1     1  NA      0.943  0.133
# 2     2   1.23   0.243  0.188
# 3     3 - 0.199 -0.199  1.90 
# 4     4   0.533  0.944  0.928

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X