Data.table: Mauvais totaux lors de l'agrégation et du regroupement par la même colonne?

Créé le 10 oct. 2018  ·  4Commentaires  ·  Source: Rdatatable/data.table

Bonjour. Je suis confus par le comportement de data.table lors de l'agrégation et du regroupement sur la même colonne. Il semble effectuer l'agrégation (par exemple la somme) sur les données groupées, plutôt que sur les données non groupées. Je ne dis pas nécessairement que c'est faux - mais c'est différent des autres outils et je me demandais quelle est l'explication ou si je fais quelque chose de mal (ou s'il s'agit peut-être d'un bogue). J'ai inclus une comparaison avec dplyr, qui fonctionne plus comme je m'y attendais (et plus comme SQL). NB: j'ai essayé de rechercher les problèmes, stackoverflow, etc., comme demandé, mais la nature de ce scénario (regrouper et agréger la même colonne) est un peu unique et je n'ai trouvé aucune correspondance.

# Minimal reproducible example

Veuillez comparer la colonne Total dans les deux exemples ci-dessous. Par exemple, il y a trois lignes avec la valeur trois, donc je m'attendrais à ce que le total soit 9, pas 3.

data.table

library(data.table)
df <- data.frame(SomeNumber=c(1,2,3,1,2,3,1,2,3))
dt <- data.table(df)
r <- dt[, .(.N, Total=sum(SomeNumber)), by=SomeNumber]

Résultat (r):

   SomeNumber N Total
1:          1 3     1
2:          2 3     2
3:          3 3     3

déplyr

library(dplyr)
df <- data.frame(SomeNumber=c(1,2,3,1,2,3,1,2,3))
r <- df %>% group_by(SomeNumber) %>% 
  summarise(N=n(), Total=sum(SomeNumber)) %>%
  ungroup()

Résultat (r):

   SomeNumber N Total
1:          1 3     3
2:          2 3     6
3:          3 3     9

# Output of sessionInfo()
R version 3.5.1 (02/07/2018)
Plate-forme: x86_64-w64-mingw32 / x64 (64 bits)
Fonctionnement sous: Windows> = 8 x64 (build 9200)

Produits Matrix: par défaut

lieu:
[1] LC_COLLATE = Anglais_Royaume-Uni.1252 LC_CTYPE = Anglais_Royaume-Uni.1252 LC_MONETARY = Anglais_Royaume-Uni.1252
[4] LC_NUMERIC = C LC_TIME = Anglais_Royaume-Uni.1252

paquets de base attachés:
[1] stats graphiques grDevices utils datasets base de méthodes

autres paquets attachés:
[1] dplyr_0.7.6 data.table_1.11.8 openxlsx_4.1.0 bindrcpp_0.2.2 pivottabler_0.4.0.9000

chargé via un espace de noms (et non attaché):
[1] Rcpp_0.12.19 rstudioapi_0.8 bindr_0.1.1 magrittr_1.5 tidyselect_0.2.4 R6_2.3.0 rlang_0.2.2 fansi_0.3.0 tools_3.5.1
[10] utf8_1.1.4 cli_1.0.1 htmltools_0.3.6 yaml_2.2.0 assertthat_0.2.0 digest_0.6.17 tibble_1.4.2 crayon_1.3.4 zip_1.0.0
[19] purrr_0.2.5 htmlwidgets_1.3 glue_1.3.0 compilateur_3.5.1 pillar_1.3.0 jsonlite_1.5 pkgconfig_2.0.2

bug question

Commentaire le plus utile

Merci @ franknarf1 et @jangorecki pour la réponse et le pointeur vers la FAQ.
Après avoir lu la réponse à la FAQ et effectué un peu plus de tests, il semble que vous deviez faire très attention à la façon dont vous utilisez les variables de regroupement, car l'agrégation sur différentes colonnes avec des données identiques peut entraîner des résultats différents, en fonction de ce qui a été utilisé pour le regroupement. Je trouve toujours cela étrange et un peu gênant, mais c'est peut-être quelque chose auquel je dois m'habituer.

Exemples:

library(data.table)
df <- data.frame(SomeNumberA=c(1,1,1),SomeNumberB=c(1,1,1))
dt <- data.table(df)
r <- dt[, .(.N, TotalA=sum(SomeNumberA)), by=SomeNumberA]

Résultat de ce qui précède: TotalA = 1

library(data.table)
df <- data.frame(SomeNumberA=c(1,1,1),SomeNumberB=c(1,1,1))
dt <- data.table(df)
r <- dt[, .(.N, TotalB=sum(SomeNumberB)), by=SomeNumberA]

Résultat de ce qui précède: TotalB = 3

library(data.table)
df <- data.frame(SomeNumberA=c(1,1,1),SomeNumberB=c(1,1,1))
dt <- data.table(df)
r <- dt[, .(.N, TotalA=sum(SomeNumberA), TotalB=sum(SomeNumberB)), by=SomeNumberA]

Aucun résultat, ne s'exécute pas avec erreur:
Erreur dans gsum (SomeNumberA): objet 'SomeNumberA' introuvable

Tous les 4 commentaires

il est différent des autres outils et je me demandais quelle est l'explication ou si je fais quelque chose de mal (ou si c'est peut-être un bug). J'ai inclus une comparaison avec dplyr, qui fonctionne plus comme prévu (et plus comme SQL)

A l'intérieur de j de DT[, j, by] , les colonnes de by ont une longueur de 1. Vous pouvez faire ce calcul comme .N*SomeNumber , cependant:

dt[, .(.N, Total=.N*SomeNumber), by=SomeNumber]
# or, for efficiency with GForce...
dt[, .(.N), by=SomeNumber][, Total := N*SomeNumber][]

Pour une justification, voir la question «À l'intérieur de chaque groupe, pourquoi les variables de groupe ont-elles une longueur de 1?» dans la FAQ à vignette("datatable-faq") ou https://github.com/Rdatatable/data.table/wiki/Getting-started

Merci @ franknarf1 et @jangorecki pour la réponse et le pointeur vers la FAQ.
Après avoir lu la réponse à la FAQ et effectué un peu plus de tests, il semble que vous deviez faire très attention à la façon dont vous utilisez les variables de regroupement, car l'agrégation sur différentes colonnes avec des données identiques peut entraîner des résultats différents, en fonction de ce qui a été utilisé pour le regroupement. Je trouve toujours cela étrange et un peu gênant, mais c'est peut-être quelque chose auquel je dois m'habituer.

Exemples:

library(data.table)
df <- data.frame(SomeNumberA=c(1,1,1),SomeNumberB=c(1,1,1))
dt <- data.table(df)
r <- dt[, .(.N, TotalA=sum(SomeNumberA)), by=SomeNumberA]

Résultat de ce qui précède: TotalA = 1

library(data.table)
df <- data.frame(SomeNumberA=c(1,1,1),SomeNumberB=c(1,1,1))
dt <- data.table(df)
r <- dt[, .(.N, TotalB=sum(SomeNumberB)), by=SomeNumberA]

Résultat de ce qui précède: TotalB = 3

library(data.table)
df <- data.frame(SomeNumberA=c(1,1,1),SomeNumberB=c(1,1,1))
dt <- data.table(df)
r <- dt[, .(.N, TotalA=sum(SomeNumberA), TotalB=sum(SomeNumberB)), by=SomeNumberA]

Aucun résultat, ne s'exécute pas avec erreur:
Erreur dans gsum (SomeNumberA): objet 'SomeNumberA' introuvable

Le dernier est un bug ...

Je ne sais pas s'il s'agit d'une nuance de la méthode de regroupement / agrégation de data.table, mais lors du regroupement et de l'agrégation par une seule variable, data.table ne «factorise» pas l'appel de regroupement.

c'est-à-dire qu'il compte chaque nombre comme son propre groupe après l'agrégation, donc dans votre cas, il ne vous reste que 3 SomeNumber variables à additionner, au lieu des 9 d'origine.

Une solution simple et rapide consiste à garantir que la factorisation a lieu dans l'appel de groupement initial.

library(data.table)

df <- data.frame(SomeNumber=c(1, 2, 3, 1, 2, 3, 1, 2, 3))

dt <- data.table(df)

r <- dt[, .(.N, Total = sum(SomeNumber)), by = as.factor(SomeNumber)]

   as.factor N Total
1:         1 3     3
2:         2 3     6
3:         3 3     9
Cette page vous a été utile?
0 / 5 - 0 notes