2016-06-17 13 views
2

Ich verwende ggplot 2.1.0, um Histogramme zu plotten, und ich habe ein unerwartetes Verhalten bezüglich der Histogramm-Bins. Ich gebe hier ein Beispiel mit linksgeschlossenen Behältern (d. H. [0, 0,1 [) mit einer Behälterbreite von 0,1.geom_histogram: falsche Behälter?

mydf <- data.frame(myvar=c(-1,-0.5,-0.4,-0.1,-0.1,0.05,0.1,0.1,0.25,0.5,1)) 
myplot <- ggplot(mydf, aes(myvar)) + geom_histogram(aes(y=..count..),binwidth = 0.1, boundary=0.1,closed="left") 
myplot 
ggplot_build(myplot)$data[[1]] 

enter image description here

An diesem Beispiel kann man den Wert -0,4 innerhalb des Behälters [-0,4, -0,3 [, aber es fällt statt (geheimnisvoll) in der Tonne [-0,5, erwarten -0,4 [. Das Gleiche gilt für den Wert -0.1, der in [-0,2, -0,1 [statt [-0,1,0 [... usw.] Fällt.

Gibt es hier etwas, das ich nicht vollständig verstehe (besonders mit den neuen "Mitte" und "Grenze" -Parametern)? Oder macht ggplot2 da seltsame Dinge?

Vielen Dank im Voraus, Mit freundlichen Grüßen, Arnaud

PS: Auch hier gefragt: https://github.com/hadley/ggplot2/issues/1651

+2

Wahrscheinlich eine Konsequenz von [Fließkommagenauigkeit] (http://stackoverflow.com/q/9508518/1412059). Die Intervallgrenzen sind immerhin Gleitkommazahlen. – Roland

+0

Das ist ... bedauerlich. Allerdings habe ich nicht das gleiche Ergebnis mit ggplot 2.1.0 (http://i66.tinypic.com/1sy2w4.jpg) und ggplot0.9.3 (http://i65.tinypic.com/4rsvev.jpg), was ist sehr beunruhigend. – user1410760

+0

Bitte beachten Sie, dass ggplot 0.9.3 sich wie erwartet verhält. – user1410760

Antwort

4

Ihr Problem ist reproduzierbar und erscheint durch Rundungsfehler verursacht werden, wie es in den Kommentaren von Roland vorgeschlagen. An dieser Stelle sieht das für mich wie ein Fehler aus, der in der Version ggplot2_2.0.0 eingeführt wurde. Ich spekuliere unten über seinen Ursprung, aber zuerst möchte ich einen Workaround basierend auf der boundary Option vorstellen.

PROBLEM:

df <- data.frame(var = seq(-100,100,10)/100) 
as.list(df) # check the data 
$var 
[1] -1.0 -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 
[10] -0.1 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 
[19] 0.8 0.9 1.0 
library("ggplot2") 
p <- ggplot(data = df, aes(x = var)) + 
    geom_histogram(aes(y = ..count..), 
     binwidth = 0.1, 
     boundary = 0.1, 
     closed = "left") 
p 

enter image description here

SOLUTION

Zwicken der boundary Parameter. In diesem Beispiel funktioniert die Einstellung knapp unter 1, z. B. 0,99. Ihr Anwendungsfall sollte auch angepasst werden können.

ggplot(data = df, aes(x = var)) + 
    geom_histogram(aes(y = ..count..), 
     binwidth = 0.05, 
     boundary = 0.99, 
     closed = "left") 

enter image description here

(Ich habe die binwidth schmale für eine bessere visuellen gemacht)

Eine andere Lösung ist Ihre eigenen Unschärfen einzuführen, z.B. multiplizieren Sie die Daten mit 1 plus etwas weniger als der Maschinennullpunkt (siehe unten eps). In ggplot2 multipliziert sich die Unschärfe um 1e-7 (frühere Versionen) oder 1e-8 (spätere Versionen).

Ursache:

Das Problem scheint eindeutig in ncount:

str(ggplot_build(p)$data[[1]]) 
## 'data.frame': 20 obs. of 17 variables: 
## $ y  : num 1 1 1 1 1 2 1 1 1 0 ... 
## $ count : num 1 1 1 1 1 2 1 1 1 0 ... 
## $ x  : num -0.95 -0.85 -0.75 -0.65 -0.55 -0.45 -0.35 -0.25 -0.15 -0.05 ... 
## $ xmin : num -1 -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1 ... 
## $ xmax : num -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1 0 ... 
## $ density : num 0.476 0.476 0.476 0.476 0.476 ... 
## $ ncount : num 0.5 0.5 0.5 0.5 0.5 1 0.5 0.5 0.5 0 ... 
## $ ndensity: num 1.05 1.05 1.05 1.05 1.05 2.1 1.05 1.05 1.05 0 ... 
## $ PANEL : int 1 1 1 1 1 1 1 1 1 1 ... 
## $ group : int -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ... 
## $ ymin : num 0 0 0 0 0 0 0 0 0 0 ... 
## $ ymax : num 1 1 1 1 1 2 1 1 1 0 ... 
## $ colour : logi NA NA NA NA NA NA ... 
## $ fill : chr "grey35" "grey35" "grey35" "grey35" ... 
## $ size : num 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 ... 
## $ linetype: num 1 1 1 1 1 1 1 1 1 1 ... 
## $ alpha : logi NA NA NA NA NA NA ... 

ggplot_build(p)$data[[1]]$ncount 
## [1] 0.5 0.5 0.5 0.5 0.5 1.0 0.5 0.5 0.5 0.0 1.0 0.5 
## [13] 0.5 0.5 0.0 1.0 0.5 0.0 1.0 0.5 

Rundungsfehler?

Sieht aus wie:

df <- data.frame(var = as.integer(seq(-100,100,10))) 
# eps <- 1.000000000000001 # on my system 
eps <- 1+10*.Machine$double.eps 
p <- ggplot(data = df, aes(x = eps*var/100)) + 
    geom_histogram(aes(y = ..count..), 
        binwidth = 0.05, 
        closed = "left") 
p 

(ich die boundary Option vollständig entfernt haben)

enter image description here

Dieses Verhalten erscheint einige Zeit nach ggplot2_1.0.1. Betrachten des Quellcodes, z.B. bin.R und stat-bin.r in https://github.com/hadley/ggplot2/blob/master/R, und die Berechnungen von count führt Tracing bin_vector() zu funktionieren, die die folgenden Zeilen enthält:

bin_vector <- function(x, bins, weight = NULL, pad = FALSE) { 
... STUFF HERE I HAVE DELETED FOR CLARITY ... 
cut(x, bins$breaks, right = bins$right_closed, 
include.lowest = TRUE) 
... STUFF HERE I HAVE DELETED FOR CLARITY ... 
} 

Durch die aktuellen Versionen dieser Funktionen mit älteren zu vergleichen, sollten Sie in der Lage sein, den Grund zu finden, für das unterschiedliche Verhalten ... Fortsetzung folgt ...

Aufsummieren DEBUGGEN

von "patching" die bin_vector-Funktion und das Drucken der Ausgabe auf dem Bildschirm erscheint es, dass:

  1. bins$fuzzy korrekt die Fuzzy-Parameter speichert

  2. Die nicht-fuzzy bins$breaks werden in den Berechnungen verwendet, aber so weit wie ich sehen kann (und korrigieren Sie mich, wenn ich falsch liege) die bins$fuzzy sind nicht.

  3. Wenn ich einfach bins$breaks durch bins$fuzzy an der Spitze bin_vector ersetzen, wird die richtige Darstellung zurückgegeben. Kein Beweis eines Fehlers, sondern ein Vorschlag, dass vielleicht mehr getan werden könnte, um das Verhalten früherer Versionen von ggplot2 zu emulieren.

  4. Oben auf bin_vector erwartete ich, eine Bedingung zu finden, auf der entweder bins$breaks oder bins$fuzzy zurückgeben. Ich denke, das fehlt jetzt.

Patchen

Um "patch" die bin_vector Funktion, die Funktionsdefinition aus der Github Quelle kopieren oder bequemer, von dem Endgerät, mit:

ggplot2:::bin_vector 

es ändern (Patch it) und weisen Sie es dem Namensraum zu:

library("ggplot2") 
bin_vector <- function (x, bins, weight = NULL, pad = FALSE) 
{ 
... STUFF HERE I HAVE DELETED FOR CLARITY ... 
## MY PATCH: Replace bins$breaks with bins$fuzzy 
bin_idx <- cut(x, bins$fuzzy, right = bins$right_closed, 
include.lowest = TRUE) 
... STUFF HERE I HAVE DELETED FOR CLARITY ... 
ggplot2:::bin_out(bin_count, bin_x, bin_widths) 
## THIS IS THE PATCHED FUNCTION 
} 
assignInNamespace("bin_vector", bin_vector, ns = "ggplot2") 
df <- data.frame(var = seq(-100,100,10)/100) 
ggplot(data = df, aes(x = var)) + geom_histogram(aes(y = ..count..), binwidth = 0.05, boundary = 1, closed = "left") 

Nur um klar zu sein, ist der obige Code zur besseren Übersichtlichkeit bearbeitet: Die Funktion hat viele Typprüfungen und andere Berechnungen, die ich entfernt habe, die aber die Funktion patchten müssten. Bevor Sie den Patch ausführen, starten Sie Ihre R-Sitzung oder detach Ihre derzeit geladene ggplot2.

ALTE VERSIONEN

Das unerwartete Verhalten ist NICHT in Versionen beobachtet 2.0.9.3 oder 2.1.0.1 und erscheint in der aktuellen Version 2.2.0.1 (oder vielleicht die frühere 2.2.0.0, stammen, die mir einen Fehler gab, als ich versuchte, nennen).

eine alte Version zu installieren und zu laden, sagen ggplot2_0.9.3, erstellen Sie ein separates Verzeichnis (kein Punkt in der aktuellen Version überschreiben), sagen ggplot2093:

URL <- "http://cran.r-project.org/src/contrib/Archive/ggplot2/ggplot2_0.9.3.tar.gz" 
install.packages(URL, repos = NULL, type = "source", 
    lib = "~/R/testing/ggplot2093") 

die alte Version zu laden, rufen Sie es von Ihrem lokalen directory:

library("ggplot2", lib.loc = "~/R/testing/ggplot2093") 
+0

Vielen Dank für die Verfolgung des Problems. Sie sagten, dass die Diddle-Funktion entfernt wurde, aber wenn Sie sich die bin.R-Datei in der neuesten Version von ggplot (https://github.com/hadley/ggplot2/blob/master/R/bin.R) ansehen, I hab den eindruck, dass der param "fuzz" "diddle" ersetzt. Ist das korrekt? – user1410760

+0

Die Diskussion wurde zu '' https: // github.com/hadley/ggplot2/issues/1651'' verschoben. Meldet sich hier zurück, wenn die Quelle des Bugs/Features gefunden wurde. – PatrickT

+1

In der Tat, 'bin $ fuzzy' scheint nirgendwo verwendet zu werden ... Ich hoffe, Hadley (oder irgendjemand kompetent) wird uns zu diesem Thema aufklären. Wie auch immer, danke für den Patch! – user1410760