Data.table: Falsche Summen beim Aggregieren und Gruppieren nach derselben Spalte?

Erstellt am 10. Okt. 2018  ·  4Kommentare  ·  Quelle: Rdatatable/data.table

Hallo. Ich bin verwirrt über das Verhalten von data.table beim Aggregieren und Gruppieren in derselben Spalte. Es scheint das Aggregat (z. B. die Summe) für die gruppierten Daten und nicht für die nicht gruppierten Daten durchzuführen. Ich sage nicht unbedingt, dass dies falsch ist - aber es unterscheidet sich von anderen Tools und ich habe mich gefragt, was die Erklärung ist oder ob ich etwas falsch mache (oder ob dies möglicherweise ein Fehler ist). Ich habe einen Vergleich mit dplyr beigefügt, der mehr wie erwartet (und eher wie SQL) funktioniert. NB: Ich habe versucht, die Probleme, den Stapelüberlauf usw. wie gewünscht zu durchsuchen, aber die Art dieses Szenarios (Gruppieren und Aggregieren derselben Spalte) ist etwas eindeutig und ich habe keine Übereinstimmungen gefunden.

# Minimal reproducible example

Bitte vergleichen Sie die Spalte Gesamt in den beiden folgenden Beispielen. ZB gibt es drei Zeilen mit dem Wert drei, also würde ich erwarten, dass die Summe 9 ist, nicht 3.

Datentabelle

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]

Ergebnis (r):

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

dplyr

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()

Ergebnis (r):

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

# Output of sessionInfo()
R Version 3.5.1 (2018-07-02)
Plattform: x86_64-w64-mingw32 / x64 (64-Bit)
Läuft unter: Windows> = 8 x64 (Build 9200)

Matrix-Produkte: Standard

Gebietsschema:
[1] LC_COLLATE = English_United Kingdom.1252 LC_CTYPE = English_United Kingdom.1252 LC_MONETARY = English_United Kingdom.1252
[4] LC_NUMERIC = C LC_TIME = English_United Kingdom.1252

beigefügte Basispakete:
[1] Statistik Grafik GrDevices Utils Datasets Methoden Basis

andere angehängte Pakete:
[1] dplyr_0.7.6 data.table_1.11.8 openxlsx_4.1.0 bindrcpp_0.2.2 pivottabler_0.4.0.9000

über einen Namespace geladen (und nicht angehängt):
[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 compiler_3.5.1 pillar_1.3.0 jsonlite_1.5 pkgconfig_2.0.2

bug question

Hilfreichster Kommentar

Vielen Dank an @ franknarf1 und @jangorecki für die Antwort und den
Nachdem Sie die FAQ-Antwort gelesen und einige weitere Tests durchgeführt haben, müssen Sie anscheinend sehr vorsichtig mit der Verwendung von Gruppierungsvariablen umgehen, da die Aggregation in verschiedenen Spalten mit identischen Daten zu unterschiedlichen Ergebnissen führen kann, je nachdem, was für die Gruppierung verwendet wurde. Ich finde das immer noch seltsam und etwas umständlich, aber vielleicht ist das nur etwas, woran ich mich gewöhnen muss.

Beispiele:

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]

Ergebnis des oben genannten: 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]

Ergebnis des oben genannten: 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]

Kein Ergebnis, kann nicht mit Fehler ausgeführt werden:
Fehler in gsum (SomeNumberA): Objekt 'SomeNumberA' nicht gefunden

Alle 4 Kommentare

Es unterscheidet sich von anderen Tools und ich habe mich gefragt, was die Erklärung ist oder ob ich etwas falsch mache (oder ob dies möglicherweise ein Fehler ist). Ich habe einen Vergleich mit dplyr beigefügt, der mehr wie erwartet (und eher wie SQL) funktioniert.

Innerhalb von j von DT[, j, by] haben die Spalten in by eine Länge von 1. Sie können diese Berechnung jedoch wie .N*SomeNumber :

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

Eine Begründung finden Sie in der Frage "Warum sind die Gruppenvariablen in jeder Gruppe Länge-1?" in den FAQ unter vignette("datatable-faq") oder https://github.com/Rdatatable/data.table/wiki/Getting-started

Vielen Dank an @ franknarf1 und @jangorecki für die Antwort und den
Nachdem Sie die FAQ-Antwort gelesen und einige weitere Tests durchgeführt haben, müssen Sie anscheinend sehr vorsichtig mit der Verwendung von Gruppierungsvariablen umgehen, da die Aggregation in verschiedenen Spalten mit identischen Daten zu unterschiedlichen Ergebnissen führen kann, je nachdem, was für die Gruppierung verwendet wurde. Ich finde das immer noch seltsam und etwas umständlich, aber vielleicht ist das nur etwas, woran ich mich gewöhnen muss.

Beispiele:

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]

Ergebnis des oben genannten: 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]

Ergebnis des oben genannten: 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]

Kein Ergebnis, kann nicht mit Fehler ausgeführt werden:
Fehler in gsum (SomeNumberA): Objekt 'SomeNumberA' nicht gefunden

Der letzte ist ein Fehler ...

Ich bin nicht sicher, ob dies eine Nuance der Gruppierungs- / Aggregationsmethode von data.table ist, aber wenn die Gruppierung und Aggregation nach einer einzelnen Variablen data.table den Gruppierungsaufruf nicht "faktorisiert".

Das heißt, jede Zahl wird nach der Aggregation als eigene Gruppe gezählt. In Ihrem Fall bleiben also nur 3 SomeNumber Variablen zu summieren, anstatt der ursprünglichen 9.

Durch die schnelle und einfache Lösung wird sichergestellt, dass die Faktorisierung innerhalb des ersten Gruppierungsaufrufs erfolgt.

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
War diese Seite hilfreich?
0 / 5 - 0 Bewertungen