问题
I noticed that defining as.matrix
or as.data.frame
as S3 methods for an S4 class
makes e.g. lm (formula, objS4)
and prcomp (object)
work out of the box. This doesn't work if they are defined as S4 methods.
Why does it matter whether the methods are defined as S3 or S4 method?
Example for as.data.frame
:
setClass ("exampleclass", representation (x = "data.frame"))
object <- new ("exampleclass", x = iris)
setMethod ("as.data.frame", signature="exampleclass", definition= function (x, ...) x@x )
## [1] "as.data.frame"
as.data.frame (object)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## ...snip...
lm (Petal.Length ~ Petal.Width, object)
## error in as.data.frame.default(data) :
## cannot coerce class 'structure("exampleclass", package = ".GlobalEnv")' into a data.frame
as.data.frame.exampleclass <- function (x, ...) x@x
lm (Petal.Length ~ Petal.Width, object)
## Call:
## lm(formula = Petal.Length ~ Petal.Width, data = object)
##
## Coefficients:
## (Intercept) Petal.Width
## 1.084 2.230
As the situation may be a bit complicated with lm
where the coercion will only occur when the formula is evaluated in an environment constructed from the data, here is a more simple case whith the same behaviour:
setMethod ("as.matrix", signature="exampleclass", definition= function (x, ...) as.matrix (x@x[, 1:4]) )
prcomp (object)
## error in as.vector(data) :
## No method to coerce this S4 class into a vector
as.matrix.exampleclass <- function (x, ...) as.matrix (x@x [, 1:4])
prcomp (object)
## Standard deviations:
## [1] 2.0562689 0.4926162 0.2796596 0.1543862
##
## Rotation:
## PC1 PC2 PC3 PC4
## Sepal.Length 0.36138659 -0.65658877 0.58202985 0.3154872
## Sepal.Width -0.08452251 -0.73016143 -0.59791083 -0.3197231
## Petal.Length 0.85667061 0.17337266 -0.07623608 -0.4798390
## Petal.Width 0.35828920 0.07548102 -0.54583143 0.7536574
Here, stats:::prcomp.default
is called, which starts with a plain x <- as.matrix (x)
. This fails with the above S4 definition, but works with the S3 definition.
回答1:
I take it from the comments that lm
simply calls as.data.frame
explicitly. If you look at as.data.frame
:
> as.data.frame
function (x, row.names = NULL, optional = FALSE, ...)
{
if (is.null(x))
return(as.data.frame(list()))
UseMethod("as.data.frame")
}
<bytecode: 0x29140b8>
<environment: namespace:base>
You'll see that it calls the S3 generic, and from the methods documentation
An S4 method alone will not be seen if the S3 generic function is called directly. However, >primitive functions and operators are exceptions: The internal C code will look for S4 >methods if and only if the object is an S4 object. In the examples, the method for
[
for >class "myFrame" will always be called for objects of this class.
来源:https://stackoverflow.com/questions/15593021/as-matrix-and-as-data-frame-s3-methods-vs-s4-methods