R you ready? - Session 21.06.2012


Ziel: Eine Methode zu erstellen, die summary2 heißt und die Koeffizienten der normalen summary Ausgabe erstellt für Objeket der Klasse lm, aber zusätzlich noch di CIs dazu schreibt.

1. Schritt

Die relevanten Informationen finden.

m <- lm(x1 ~ y1, anscombe)
s <- summary(m)
s
## 
## Call:
## lm(formula = x1 ~ y1, data = anscombe)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -2.652 -1.512 -0.266  1.234  3.895 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)   
## (Intercept)   -0.998      2.434   -0.41   0.6916   
## y1             1.333      0.314    4.24   0.0022 **
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 
## 
## Residual standard error: 2.02 on 9 degrees of freedom
## Multiple R-squared: 0.667,   Adjusted R-squared: 0.629 
## F-statistic:   18 on 1 and 9 DF,  p-value: 0.00217 
## 
str(s)
## List of 11
##  $ call         : language lm(formula = x1 ~ y1, data = anscombe)
##  $ terms        :Classes 'terms', 'formula' length 3 x1 ~ y1
##   .. ..- attr(*, "variables")= language list(x1, y1)
##   .. ..- attr(*, "factors")= int [1:2, 1] 0 1
##   .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. ..$ : chr [1:2] "x1" "y1"
##   .. .. .. ..$ : chr "y1"
##   .. ..- attr(*, "term.labels")= chr "y1"
##   .. ..- attr(*, "order")= int 1
##   .. ..- attr(*, "intercept")= int 1
##   .. ..- attr(*, "response")= int 1
##   .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
##   .. ..- attr(*, "predvars")= language list(x1, y1)
##   .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "numeric"
##   .. .. ..- attr(*, "names")= chr [1:2] "x1" "y1"
##  $ residuals    : Named num [1:11] 0.281 -0.266 3.895 -1.745 0.895 ...
##   ..- attr(*, "names")= chr [1:11] "1" "2" "3" "4" ...
##  $ coefficients : num [1:2, 1:4] -0.998 1.333 2.434 0.314 -0.41 ...
##   ..- attr(*, "dimnames")=List of 2
##   .. ..$ : chr [1:2] "(Intercept)" "y1"
##   .. ..$ : chr [1:4] "Estimate" "Std. Error" "t value" "Pr(>|t|)"
##  $ aliased      : Named logi [1:2] FALSE FALSE
##   ..- attr(*, "names")= chr [1:2] "(Intercept)" "y1"
##  $ sigma        : num 2.02
##  $ df           : int [1:3] 2 9 2
##  $ r.squared    : num 0.667
##  $ adj.r.squared: num 0.629
##  $ fstatistic   : Named num [1:3] 18 1 9
##   ..- attr(*, "names")= chr [1:3] "value" "numdf" "dendf"
##  $ cov.unscaled : num [1:2, 1:2] 1.4541 -0.1817 -0.1817 0.0242
##   ..- attr(*, "dimnames")=List of 2
##   .. ..$ : chr [1:2] "(Intercept)" "y1"
##   .. ..$ : chr [1:2] "(Intercept)" "y1"
##  - attr(*, "class")= chr "summary.lm"
s$coefficients
##             Estimate Std. Error t value Pr(>|t|)
## (Intercept)  -0.9975     2.4344 -0.4098  0.69156
## y1            1.3328     0.3142  4.2415  0.00217
confint(m)
##              2.5 % 97.5 %
## (Intercept) -6.505  4.510
## y1           0.622  2.044

2. Die Ausgaben zusammenfügen

cbind(summary(m)$coef, confint(m))
##             Estimate Std. Error t value Pr(>|t|)  2.5 % 97.5 %
## (Intercept)  -0.9975     2.4344 -0.4098  0.69156 -6.505  4.510
## y1            1.3328     0.3142  4.2415  0.00217  0.622  2.044

3. Als Funktion

# x ist eine Objekt der Klasse lm
summary2 <- function(x) cbind(summary(x)$coef, confint(x))
summary2(m)
##             Estimate Std. Error t value Pr(>|t|)  2.5 % 97.5 %
## (Intercept)  -0.9975     2.4344 -0.4098  0.69156 -6.505  4.510
## y1            1.3328     0.3142  4.2415  0.00217  0.622  2.044

4. summary2 soll Methode der Klasse lm werden.

Wir müssen der Funktion summary2 beibringen, dass sie für die Klasse lm genutzt werden soll. Hierzu

summary2.lm <- function(x) cbind(summary(x)$coef, confint(x))
rm(summary2)

Wir benötigen eine summary2 Funktion, die in Abhängigkeit von der jeweilige Klasse des zu verarbeitenden Objektes entscheidet, welche spezifische summary2.XXX Methode genutzt werden soll. Funktionen, die so etwas entscheiden, nennen sich generisch. Und dieser Vorgang nennt sich method dispatch.

# generische Funktion ruft Methoden auf
summary2 <- function(x) {
    UseMethod("summary2", x)
}
summary2(m)
##             Estimate Std. Error t value Pr(>|t|)  2.5 % 97.5 %
## (Intercept)  -0.9975     2.4344 -0.4098  0.69156 -6.505  4.510
## y1            1.3328     0.3142  4.2415  0.00217  0.622  2.044

Was passiert, wenn keine Methode für das zu verarbeitende Objekt vorhanden ist? ⇒ Ein Fehler tritt auf!

mat <- matrix(1:9, 3)
class(mat)
## [1] "matrix"
summary2(mat)

Wir wollen ein Methide für den Fall, dass für die Klasse keine Methode vorhanden ist. Eine solche Methode nennt sich die default Methode.

summary2.default <- function(x) {
    cat("Keine Methode vorhanden, nutze 'summary' stattdessen\n")
    summary(x)
}
summary2(mat)
## Keine Methode vorhanden, nutze 'summary' stattdessen
##        V1            V2            V3     
##  Min.   :1.0   Min.   :4.0   Min.   :7.0  
##  1st Qu.:1.5   1st Qu.:4.5   1st Qu.:7.5  
##  Median :2.0   Median :5.0   Median :8.0  
##  Mean   :2.0   Mean   :5.0   Mean   :8.0  
##  3rd Qu.:2.5   3rd Qu.:5.5   3rd Qu.:8.5  
##  Max.   :3.0   Max.   :6.0   Max.   :9.0  

Objektstruktur:

Ausgabe in der Konsole:
“Die Summe von Wert 1 und Wert 2 ist Ergebnis

addi <- function(x, y) {
    res <- x + y
    class(res) <- "cl_addi"
    res
}
addi(2, 3)
## [1] 5
## attr(,"class")
## [1] "cl_addi"

Unschöne Lösung.

addi <- function(x, y) {
    res <- x + y
    cat("Die Summe von", x, "und", y, "ist", res, "\n")
    class(res) <- "cl_addi"
    invisible(res)
}
g <- addi(2, 3)
## Die Summe von 2 und 3 ist 5 
g
## [1] 5
## attr(,"class")
## [1] "cl_addi"

Was wir wollen, ist dass das eine Objekt der Klasse cl_addi immer auf eine gewissen Weise ausgegeben wird.

Was machen wir:
1. Wir müssen die Summanden mit in dem Objekt speichern.
2. Wir müssen sicherstellen, dass jedes Objekt der Klasse cl_addi immer mit einer bestimmten Methode dargestellt wird.

addi <- function(x, y) {
    ans <- list()
    ans$x <- x
    ans$y <- y
    ans$res <- x + y
    class(ans) <- "cl_addi"
    ans
}
addi(3, 5)
## $x
## [1] 3
## 
## $y
## [1] 5
## 
## $res
## [1] 8
## 
## attr(,"class")
## [1] "cl_addi"

Die Ausgabe in der Konsole wird stets durch die print Funktion generiert.

m <- matrix(1:9, 3)
m
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9
print(m)
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9

Bei jeder print Anweisung wird implizit mach einer print Methode für die Klasse des Objektes gesucht. Ist diese nicht vorhanden wird die print.default Methode genutzt. Folgende Zeilen sind identisch bzw. stellen den Ablauf im Hintergrund dar.

a <- addi(1, 2)
a
## $x
## [1] 1
## 
## $y
## [1] 2
## 
## $res
## [1] 3
## 
## attr(,"class")
## [1] "cl_addi"
print(a)
## $x
## [1] 1
## 
## $y
## [1] 2
## 
## $res
## [1] 3
## 
## attr(,"class")
## [1] "cl_addi"
print.default(a)
## $x
## [1] 1
## 
## $y
## [1] 2
## 
## $res
## [1] 3
## 
## attr(,"class")
## [1] "cl_addi"

D.h., es gibt schon eine generische Funktion print. Wir benötigen nun nur noch eine Methode für unsere Klasse cl_addi.

print.cl_addi <- function(a) {
    cat("Die Summe von", a$x, "und", a$y, "ist", a$res, "\n")
}
b <- addi(7, 12)
b
## Die Summe von 7 und 12 ist 19 
print(b)
## Die Summe von 7 und 12 ist 19 

Die Funktion print betrifft nur die Darstellung in der Konsole.
das Objekt behält sein Struktur, die man jetzt nicht mehr direkt sehe kann. str zeigt die Strukutr an.

str(b)
## List of 3
##  $ x  : num 7
##  $ y  : num 12
##  $ res: num 19
##  - attr(*, "class")= chr "cl_addi"



Vorschlag für ein Paket, das wir bauen wollen: Split-Half Reliabilitäten