8

S3 オブジェクトのみを受け取るメソッドに渡すことができるように、S4 オブジェクトを作成したいと思います。(これに関連しているようですが、ドキュメントsetOldClass()からはわかりませんか?)

たとえば、最小限の例として、S3 クラスと関数があるとします。

myS3 <- list(a = 1, b = 2)
class(myS3) <- "myS3class"
myS3function.myS3class <- function(x) x$a + x$b

そして私はS4オブジェクトを持っています

setClass("myS4class", representation(a = "numeric", b = "numeric"))
obj <- new("myS4class", a = 1, b = 2)

そのような私にできることはありますか

myS3function.myS3class(obj) 

私に同じことを与える

myS3function.myS3class(myS3) 

S4クラスのみを変更することによって?

編集このアプローチの私の論理的根拠は、S3 クラスのすべての既存のメソッド (通常は他のパッケージなどから取得される可能性があります) を、それらを書き直すことなく利用することです。1 つのアプローチはsetAs()、S4 オブジェクトを S3 オブジェクトに変換する強制メソッド ( ) を単純に記述することですが、その場合、ユーザーは常にこの手順を手動で実行する必要があります。setAs()(動作しますが、S4 クラス間でマッピングするのではなく、S4 クラスを S3 クラスに 使用するのが悪い習慣であるかどうかも少しわかりません)。

のドキュメントを読んだ方法から、setOldClassこれは S3 オブジェクトを S4 オブジェクトのように動作させることができるように思えますか? あれは正しいですか?もしそうなら、私の質問は逆を行うことができるかどうかです(おそらくprototypeS4クラスで設定することによって?)。

これが不可能な場合、これが悪い考えである理由の説明はどうですか?

4

3 に答える 3

3

S4 クラスにメソッドを追加して、S3 クラスに変換します。

setGeneric(
  "as.myS3class", 
  function(object)
  {
    standardGeneric("as.myS3class")
  }  
)

setMethod(
  "as.myS3class",
  signature(object = "myS4class"),
  function(object)
  {
    structure(list(a = object@a, b = object@b), class = "myS3class")
  }
)

次に、次のように S3 メソッドを呼び出すことができます。

myS3function(as.myS3class(obj))
于 2013-09-05T11:07:46.420 に答える
2

成功したソリューションは、実際に次のドキュメントに埋もれていますsetOldClass

 ## Examples of S3 classes with guaranteed attributes
 ## an S3 class "stamped" with a vector and  a "date" attribute
 ## Here is a generator function and an S3 print method.
 ## NOTE:  it's essential that the generator checks the attribute classes
 stamped <- function(x, date = Sys.time()) {
     if(!inherits(date, "POSIXt"))
       stop("bad date argument")
     if(!is.vector(x))
       stop("x must be a vector")
     attr(x, "date") <- date
     class(x) <- "stamped"
     x
 }

 print.stamped <- function(x, ...) {
     print(as.vector(x))
     cat("Date: ",  format(attr(x,"date")), "\n")
 }

 ## Now, an S4 class with the same structure:
 setClass("stamped4", contains = "vector", representation(date = "POSIXt"))

 ## We can use the S4 class to register "stamped", with its attributes:
 setOldClass("stamped", S4Class = "stamped4")
 selectMethod("show", "stamped")
 ## and then remove "stamped4" to clean up
 removeClass("stamped4")

 someLetters <- stamped(sample(letters, 10),
                        ISOdatetime(2008, 10, 15, 12, 0, 0))

 st <- new("stamped", someLetters)
 st
 # show() method prints the object's class, then calls the S3 print method.

 stopifnot(identical(S3Part(st, TRUE), someLetters))

 # creating the S4 object directly from its data part and slots
 new("stamped", 1:10, date = ISOdatetime(1976, 5, 5, 15, 10, 0))

S4 オブジェクトは S3 print メソッドを使用できることに注意してください。私が驚いたのは、これが S3 クラス用に定義されているが S4 クラス用に定義されている他のメソッドでは機能することselectMethodです。ape::phyloここで、オブジェクトを使用したユースケースに関するより詳細な例でこれを説明します: http://carlboettiger.info/2013/10/07/nexml-phylo-class-extension.html

于 2013-10-07T23:00:54.793 に答える
1

S3 クラスと S4 クラスの両方で 1 つの関数を再利用し、変更しない場合は、独自の定義を記述できます$

f <- function(x, name)
slot(x, name)

setMethod("$", signature=c(x="myS4class"), definition=f)

myS3function.myS4class(obj)
# [1] 3

しかし、これは私にはかなり疑わしいようです。[[関数はどちらの方法でもリスト要素を参照できるため、手始めに、おそらく にも同様のメソッドが必要になるでしょう。

setMethod("[[", signature=c(x="myS4class", i="character"),
                definition=function(x, i) slot(x, i))

また、割り当て用のメソッドも必要になります。

setMethod("$<-", signature=c(x="myS4class", value="numeric"),
                 definition=function(x, name, value) `slot<-`(x, name, check=TRUE, value))

setMethod("[[<-", signature=c(x="myS4class", i="character", value="numeric"),
                  definition=function(x, i, value) `slot<-`(x, i, check=TRUE, value))

しかし、番号で参照するという問題があります。

obj[[1]]
# Error in obj[[1]] : this S4 class is not subsettable

したがって、さらに別の方法が必要です。

g <- function(x, i)
{
    slots <- names(getClass("myS4class")@slots)
    slot(x, slots[i])
}

setMethod("[[", signature=c(x="myS4class", i="numeric"), g)

全体として、多くの利益を得るために多くの作業が行われているようです。

于 2013-07-31T18:23:22.643 に答える