Beruflich Dokumente
Kultur Dokumente
Hands on S4 Classes
Yohan Chalabi
R/Rmetrics Workshop
Meielisalp
June 2009
Introduction S3 Classes/Methods S4 Classes/Methods
Outline
1 Introduction
2 S3 Classes/Methods
3 S4 Classes/Methods
Introduction S3 Classes/Methods S4 Classes/Methods
Outline
1 Introduction
2 S3 Classes/Methods
3 S4 Classes/Methods
Introduction S3 Classes/Methods S4 Classes/Methods
S3/S4 History
The appendix in Software for Data Analysis by Chambers [1] is of great
interest to learn more about the history of the S language.
> library(timeDate)
> time <- as.character(timeSequence(length.out=4))
> data <- matrix(round(rnorm(8), 3), ncol = 2)
> colnames(data) <- c("col1", "col2")
> flag <- data.frame(flag = sample(c("M", "F"), 4, replace = TRUE))
Introduction S3 Classes/Methods S4 Classes/Methods
Outline
1 Introduction
2 S3 Classes/Methods
3 S4 Classes/Methods
Introduction S3 Classes/Methods S4 Classes/Methods
S3 classes
1 imagine bulls and cows mooing in the field next to the conference room
Introduction S3 Classes/Methods S4 Classes/Methods
S3 classes
Now we add new attributes for the timestamps and the additional
information flag.
> attr(bull, "time") <- time
> attr(bull, "flag") <- flag
> bull
col1 col2
[1,] -2.123 1.126
[2,] 2.833 -0.721
[3,] 0.921 -1.976
[4,] -0.917 -1.425
attr(,"class")
[1] "Bull"
attr(,"time")
[1] "2009-06-01 06:04:46" "2009-06-02 06:04:46"
[3] "2009-06-03 06:04:46" "2009-06-04 06:04:46"
attr(,"flag")
flag
1 F
2 F
3 M
4 F
Introduction S3 Classes/Methods S4 Classes/Methods
S3 methods
In the world of S3 classes, methods of generic functions can be
defined with a new functions named according to the scheme
<generic name>.<class>.
Here a generic function is a function which dispatches the S3
method with UseMethod().
There are some functions which are S3 generics. For example
print(), plot(), ...
Note S3 methods only dispatch on the type of the first argument.
If no method is found, the default methods is used
(<generic name>.default).
> print
function (x, ...)
UseMethod("print")
<environment: namespace:base>
> head(methods(print)) #-> too many methods
[1] "print.acf" "print.anova" "print.aov"
[4] "print.aovlist" "print.ar" "print.Arima"
Introduction S3 Classes/Methods S4 Classes/Methods
S3 methods
cat("Meielisalp\n")
print(y)
invisible(x)
}
> bull
Meielisalp
col1 col2
2009-06-01 06:04:46 -2.123 1.126
2009-06-02 06:04:46 2.833 -0.721
2009-06-03 06:04:46 0.921 -1.976
2009-06-04 06:04:46 -0.917 -1.425
Introduction S3 Classes/Methods S4 Classes/Methods
S3 generic
S3 group generic
There are group generic methods for a specified group of functions Math,
Ops, Summary and Complex.
> methods("Math")
[1] Math.data.frame Math.Date Math.difftime
[4] Math.factor Math.POSIXt
> getGroupMembers("Math")
[1] "abs" "sign" "sqrt" "ceiling" "floor"
[6] "trunc" "cummax" "cummin" "cumprod" "cumsum"
[11] "exp" "expm1" "log" "log10" "log2"
[16] "log1p" "cos" "cosh" "sin" "sinh"
[21] "tan" "tanh" "acos" "acosh" "asin"
[26] "asinh" "atan" "atanh" "gamma" "lgamma"
[31] "digamma" "trigamma"
Introduction S3 Classes/Methods S4 Classes/Methods
S3 inheritance
> class(Sys.time())
[1] "POSIXt" "POSIXct"
> class(as.POSIXlt(Sys.time()))
[1] "POSIXt" "POSIXlt"
Introduction S3 Classes/Methods S4 Classes/Methods
Drawbacks of S3 Classes
Outline
1 Introduction
2 S3 Classes/Methods
3 S4 Classes/Methods
Introduction S3 Classes/Methods S4 Classes/Methods
S4 Classes
> setClass("Cow",
representation(data = "matrix",
time = "character",
flag = "data.frame"))
[1] "Cow"
> # class metadata
> .__C__Cow
Class "Cow" [in ".GlobalEnv"]
Slots:
S4 Classes
Slot "time":
[1] "2009-06-01 06:04:46" "2009-06-02 06:04:46"
[3] "2009-06-03 06:04:46" "2009-06-04 06:04:46"
Slot "flag":
flag
1 F
2 F
3 M
4 F
Introduction S3 Classes/Methods S4 Classes/Methods
S4 Classes
The structure of the class can be inspected with the str() function.
> str(cow)
Formal class 'Cow' [package ".GlobalEnv"] with 3 slots
..@ data: num [1:4, 1:2] -2.123 2.833 0.921 -0.917 1.126 ...
.. ..- attr(*, "dimnames")=List of 2
.. .. ..$ : NULL
.. .. ..$ : chr [1:2] "col1" "col2"
..@ time: chr [1:4] "2009-06-01 06:04:46" "2009-06-02 06:04:46" "2009-06-03 06
..@ flag:'data.frame': 4 obs. of 1 variable:
.. ..$ flag: Factor w/ 2 levels "F","M": 1 1 2 1
Introduction S3 Classes/Methods S4 Classes/Methods
S4 slots
Inheritance
> cow + 1
Error in cow + 1 : non-numeric argument to binary operator
Introduction S3 Classes/Methods S4 Classes/Methods
Inheritance
But we could have defined the class with the contains argument in
setClass(). Lets redefine our class such that it inherits from the class
matrix.
Slot "flag":
flag
Introduction S3 Classes/Methods S4 Classes/Methods
Inheritance
Note
a class inheriting from another class must have all slots from its
superclass, and may define additional slots.
S4 classes cannot inherits from S3 classes unless they have been
redefined with the setOldClass() function.
> getClass("Cow")
Class "Cow" [in ".GlobalEnv"]
Slots:
Extends:
Class "matrix", from data part
Class "array", by class "matrix", distance 2
Class "structure", by class "matrix", distance 3
Class "vector", by class "matrix", distance 4, with explicit coerce
Introduction S3 Classes/Methods S4 Classes/Methods
S4 Validity Checks
Slots:
Extends:
Class "matrix", from data part
Class "array", by class "matrix", distance 2
Class "structure", by class "matrix", distance 3
Class "vector", by class "matrix", distance 4, with explicit coerce
Introduction S3 Classes/Methods S4 Classes/Methods
S4 Validity Checks
S4 Methods
As you have just seen in the previous chunk, S4 methods are defined
with setMethod().
Lets write a show() method for our class.
> setMethod("show", "Cow", function(object) {
value <- getDataPart(object)
rownames(value) <- as.character(slot(object, "time"))
flag <- as.matrix(slot(object, "flag"))
colnames(flag) <- paste(colnames(flag), "*", sep ="")
cat("Meielisalp\n")
print(cbind(value, flag), right = TRUE, quote = FALSE)
})
[1] "show"
> cow
Meielisalp
col1 col2 flag*
2009-06-01 06:04:46 -2.123 1.126 F
2009-06-02 06:04:46 2.833 -0.721 F
2009-06-03 06:04:46 0.921 -1.976 M
2009-06-04 06:04:46 -0.917 -1.425 F
Introduction S3 Classes/Methods S4 Classes/Methods
S4 Generic
Multiple dispatch
S3 methods are only dispatch on the first argument. You often need
many if ... else ... in your code when you are dealing with
different argument types.
> graphics:::plot.factor
function (x, y, legend.text = NULL, ...)
{
if (missing(y) || is.factor(y)) {
dargs <- list(...)
axisnames <- if (!is.null(dargs$axes))
dargs$axes
else if (!is.null(dargs$xaxt))
dargs$xaxt != "n"
else TRUE
}
if (missing(y)) {
barplot(table(x), axisnames = axisnames, ...)
}
else if (is.factor(y)) {
if (is.null(legend.text))
spineplot(x, y, ...)
else {
args <- c(list(x = x, y = y), list(...))
args$yaxlabels <- legend.text
Introduction S3 Classes/Methods S4 Classes/Methods
Multiple dispatch
With S4 methods you can define the type of all argument and also the
special types ANY and missing.
> setMethod("cowSeries", signature("matrix", "character", "data.frame"),
function(x, time, flag, ...)
new("Cow", x, time = time, flag = flag))
[1] "cowSeries"
> cowSeries(data, time, flag)
Meielisalp
col1 col2 flag*
2009-06-01 06:04:46 -2.123 1.126 F
2009-06-02 06:04:46 2.833 -0.721 F
2009-06-03 06:04:46 0.921 -1.976 M
2009-06-04 06:04:46 -0.917 -1.425 F
Introduction S3 Classes/Methods S4 Classes/Methods
Multiple dispatch
Object Conversion
as() can be used to convert an object to another class
> as(cow, "matrix")
col1 col2
[1,] -2.123 1.126
[2,] 2.833 -0.721
[3,] 0.921 -1.976
[4,] -0.917 -1.425
and one can defined conversion methods with setAs(). Lets define
a more appropriate as() method for our class :
> setAs("Cow", "matrix", function(from)
{
value <- getDataPart(from)
rownames(value) <- as.character(slot(from, "time"))
value
})
[1] "coerce<-"
> as(cow, "matrix")
col1 col2
2009-06-01 06:04:46 -2.123 1.126
2009-06-02 06:04:46 2.833 -0.721
2009-06-03 06:04:46 0.921 -1.976
2009-06-04 06:04:46 -0.917 -1.425
Introduction S3 Classes/Methods S4 Classes/Methods
What is an S4 class in R ?
S4 slots are actually attributes and, in low level, S4 objects has a special
S4 bit
> attrsCow <- attributes(cow)
> madcow <- data
> attributes(madcow) <- attrsCow
> asS4(madcow)
Meielisalp
col1 col2 flag*
2009-06-01 06:04:46 -2.123 1.126 F
2009-06-02 06:04:46 2.833 -0.721 F
2009-06-03 06:04:46 0.921 -1.976 M
2009-06-04 06:04:46 -0.917 -1.425 F
BUT !
You have to promise that you will never use such a trick !
Introduction S3 Classes/Methods S4 Classes/Methods
What is an S4 class in R ?
S4 slots are actually attributes and, in low level, S4 objects has a special
S4 bit
> attrsCow <- attributes(cow)
> madcow <- data
> attributes(madcow) <- attrsCow
> asS4(madcow)
Meielisalp
col1 col2 flag*
2009-06-01 06:04:46 -2.123 1.126 F
2009-06-02 06:04:46 2.833 -0.721 F
2009-06-03 06:04:46 0.921 -1.976 M
2009-06-04 06:04:46 -0.917 -1.425 F
BUT !
You have to promise that you will never use such a trick !
Introduction S3 Classes/Methods S4 Classes/Methods
References I
J.M. Chambers
Software for data analysis: programming with R
Springer, 2008.
R Development Core Team
?Clasees and ?Methods manual pages
2009.
Introduction S3 Classes/Methods S4 Classes/Methods
> toLatex(sessionInfo())
Hands on S4 Classes
Yohan Chalabi
R/Rmetrics Workshop
Meielisalp
June 2009