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
.