Regressionsgerade in einen doppelt-logarithmischen Plot eintragen

Wer Potenzgesetze (PowerLaws) in Daten entdecken möchte, bestimmt die Steigung in einem Graphen mit logarithmischen Achsen (log-log-Plot). In der Regel möchte man diese Steigung dann in der Graphik als Regressionsgerade darstellen. In R ist genau diese Darstellung nicht ganz einfach, da die Funktion abline() hier versagt. Im folgenden Artikel möchte ich zeigen, wie man die Schätzung seines Modells dennoch in den Plot eintragen kann.

Wir haben Daten, die einem Potenzgesetz folgen (mit etwas statistischer Schwankung).

x = c(1:150)
y = x^-.5 * 155 + (runif(length(x), min=-3, max=3))

Diese Daten plotten wir in einer Graphik mit zwei logarithmischen Achsen.

plot(x, y, log="xy", cex=.5)

Da wir ein Potenzgesetz vermuten, berechnen wir die Parameter (Steigung und Y-Achsenabschnitt) des linearen Modells (lm()) der logarithmierten Daten (siehe auch Stackoverflow):

model = lm(log(y) ~ log(x))
model

In einem doppelt-logarithmischen Plot gibt es natürlich keinen Y-Achsenabschnitt (die Null wird nie erreicht). Beim Aufruf der Funktion abline(model) wird die Regressionsgerade (besonders bei verschobenen Funktionen) an der falschen Stelle dargestellt. Daher muss man für sein lineares Modell Werte vorhersagen (mit predict() bzw. predict.lm), die man im Anschluss in den Exponenten nimmt und als Linie (lines()) zum Plot hinzufügt (siehe auch Stackoverflow: Beitrag 1 und Beitrag 2).

# Schätzung für 2 Punkte machen
neuX=c(1e-10,1e10)
lines(neuX, exp(predict(model, newdata=list(x=neuX))) ,col="blue", type="o", pch=2)
 
# Schätzung für Datenpunkte machen
lines(x, exp(predict(model, newdata=list(x=x))), col="red", type="o", pch=4)

nerv_test

Hinweise: Der Variablenname in der Liste von newdata muss genau der selbe sein, wie der Name der Variablen, die beim Aufruf des linearen Modells verwendet wurde.

  1. Hat man seine Daten z.B. in einem data.frame gespeichert, sollte man das lineare Modell mittels with() aufrufen, anstatt die Bereiche mit Hilfe des $-Selektors auszuwählen.
  2. Wenn man das lineare Modell nur für einen Teil seiner Daten verwenden möchte, so sollte man die Option subset= von lm() verwenden, anstatt Teile des Vectors mit Hilfe der eckigen Klammern auszuwählen.

Die folgenden Beispiele zeigen zwei Mögliche Schreibweisen, eine lineare Regression für die die Datensätze 40 bis 80 einzuzeichnen. Die Daten dafür sind:

1
2
3
4
x = c(1:150)
y = x^-.5 * 155 + (runif(length(x), min=-3, max=3))
daten = data.frame(x,y)
range = c(40:80)

Beispiel 1: with() wird nur für den Aufruf des lm() verwendet. die Ergebnisse der Regression werden in model gespeichert.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
plot(daten$x, daten$y, log="xy", cex=.5)
model = with(
  data = daten,
  expr = { model = lm(log(y) ~ log(x), subset=range); model }
)
model
 
lines(
  x[range]
  , exp(predict(model, newdata=list(x=x[range])))
  , col="red"
  , type="o"
  , pch=4
)

Beispiel 2: with() wird für die gesamte Behandlung der Daten verwendet (plot(), lm(), lines()).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
with(
  data = daten,
  expr = {
    plot(x, y, log="xy", cex=.5)
    model = lm(log(y) ~ log(x), subset=range)
    lines(
      x[range]
      , exp(predict(model, newdata=list(x=x[range])))
      , col="red"
      , type="o"
      , pch=4
    )
  }
)

Fehlerbalken in R-Grafik einzeichnen

In wissenschaftlichen Publikationen werden häufig Messwerte in Grafiken dargestellt. Messungen sind allerdings immer fehlerbehaftet. Daher sollte man dem Leser mitteilen, wie verlässlich die gemessenen Werte sind. In der deskriptiven Statistik gibt es dafür diverse Kennzahlen, wie z.B. die Standardabweichung oder den Standardfehler. Diese werden oft als Fehlerbalken in die Grafiken eingefügt.

errorbars
Grafisch dargestellte Messwerte mit Fehlerbalken.

In R gibt es leider keine Standardmethode, die diese Aufgabe übernimmt. Zunächst hatte ich nach Anleitungen im Internet eigene Funktionen für diese Aufgabe erstellt.

  • Eine Lösung fand ich bei Stackoverflow. Allerdings wurden hier die horizontalen Linien bei einer logarithmischen X-Achse nicht korrekt angezeigt (links und rechts waren die Linien unterschiedlich lang).
  • Die Lösung von MonkeysUncle war in der Hinsicht besser. Allerdings wurde keine horizontale Linie angezeigt, wenn der Fehler 0 war. Zudem wurde gar kein Fehlerbalken angezeigt, wenn die untere Grenze des Fehlers (bei logarithmischer Y-Achse) im negativen Bereich lag.

Schließlich habe ich die Funktion errbar() im Paket Hmisc gefunden (siehe auch StackOverflow). Hier werden:

  1. Die horizontalen Linien auch bei logarithmischer X-Achse korrekt gezeichnet.
  2. Bei logarithmischer Y-Achse und negativer unteren Fehlergrenze, wird zumindest die obere Fehlergrenze geplottet.
  3. Eine horizontale Linie wird auch hinzugefügt, wenn der Fehler 0 ist.
  4. Die Y-Ranges werden automatisch gewählt, wenn die Fehlerbalken ausserhalb der Grafik liegen würden.

Das folgende Beispiel zeigt, wie man Datenpunkte mit ihren Fehlerbalken in eine Grafik einträgt.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Datenpunkte (x, y) mit einer Standardabweichung (sd)
daten = data.frame(
  x  = c(1:5)
  , y  = c(1.1, 1.5, 2.9, 3.8, 5.2)
  , sd = c(0.2, 0.3, 0.2, 0.0, 0.4)
)
 
# Paket "Hmisc" installieren und laden 
install.packages("Hmisc", dependencies=T)
library("Hmisc")
 
# Plot mit automatischer Wahl des Y ranges
with (
  data = daten
  , expr = Hmisc::errbar(x, y, y+sd, y-sd, pch=1)
)
 
# Datenpunkte mit Fehlerbalken zu einem
# existierenden Koordinatensystem hinzufügen (add=T)
plot(daten$x, daten$y, type="n", xlab="X-Werte", ylab="Y-Werte")
with (
  data = daten
  , expr = Hmisc::errbar(x, y, y+sd, y-sd, pch=2, add=T)
)

Die Funktion errbar() erweitert die Funktion plot(). Daher können die Grafikparameter von plot() und par() (hier z.B. pch) verwendet werden. Zusätzlich gibt es noch Parameter, mit denen sich z.B. die breite der horizontalen Begrenzung (cap) steuern lässt.