Je recherche une solution efficace pour ajouter des sous-totaux pour chaque colonne dans une nouvelle ligne pour chaque catégorie dans la colonne «id». Je suis en mesure d'obtenir le résultat souhaité en utilisant le code ci-dessous, mais cette approche n'est pas efficace pour les grands ensembles de données. Est-il possible d'accomplir cela en utilisant des tables de données?
Merci!
data <- data.frame(id = c("a","b","a","b","c","c","c","a","a","b"),
total = c(1,2,3,4,2,3,4,2,3,4),
total2 = c(2,3,4,2,3,4,5,6,4,2),
total3 = c(2,3,4,5,6,3,2,3,4,5))
data_new <- data.frame(id = character(), total = numeric(), total2 =
numeric(), total3 = numeric())
for (i in unique(data$id)){
subset <- data[data$id == i,]
subtotals <- data.frame(id = i, total = sum(subset$total), total2 =
sum(subset$total2), total3 = sum(subset$total3))
subset <- rbind(subset,subtotals)
data_new <- rbind(data_new, subset)
}
data_new
3 Réponses :
Voici une approche de style tidyverse:
library(tidyverse)
data_new <- bind_rows(data,
data %>%
group_by(id) %>%
summarise_all(sum)
) %>%
arrange(id) %>%
print()
#> id total total2 total3
#> 1 a 1 2 2
#> 2 a 3 4 4
#> 3 a 2 6 3
#> 4 a 3 4 4
#> 5 a 9 16 13
#> 6 b 2 3 3
#> 7 b 4 2 5
#> 8 b 4 2 5
#> 9 b 10 7 13
#> 10 c 2 3 6
#> 11 c 3 4 3
#> 12 c 4 5 2
#> 13 c 9 12 11
Créé le 10/01/2019 par le paquet reprex (v0.2.1)
Voici une solution de base R utilisant agrégat . Merci à @thelatemail pour avoir rationalisé la version originale.
SubTotals = aggregate(data[,2:4], data["id"], sum) data_new = rbind(data, SubTotals) data_new = data_new[order(data_new$id),] data_new id total total2 total3 1 a 1 2 2 3 a 3 4 4 8 a 2 6 3 9 a 3 4 4 11 a 9 16 13 2 b 2 3 3 4 b 4 2 5 10 b 4 2 5 12 b 10 7 13 5 c 2 3 6 6 c 3 4 3 7 c 4 5 2 13 c 9 12 11
list (data $ id) pourrait également être data ["id"] , ce qui évitera le changement de nom. Ou même agrégat (. ~ Id, données, somme)
@thelatemail C'est une grande amélioration. Je vais l'ajouter à la solution.
Et pour faire bonne mesure, voici une solution data.table :
library(data.table) setDT(data) rbind(data, data[, lapply(.SD,sum), by=id])[order(id)] # id total total2 total3 # 1: a 1 2 2 # 2: a 3 4 4 # 3: a 2 6 3 # 4: a 3 4 4 # 5: a 9 16 13 # 6: b 2 3 3 # 7: b 4 2 5 # 8: b 4 2 5 # 9: b 10 7 13 #10: c 2 3 6 #11: c 3 4 3 #12: c 4 5 2 #13: c 9 12 11
Regrouper par = le id code > variable, puis calculez la somme pour chaque variable autre que id - via lapply (.SD, sum) . Ensuite, rbind cela revient à l'ensemble principal, puis triez les lignes par id.