6

新しい S3 クラスのオブジェクトを使用して data.frame を乗算するための独自の動作 (メソッド) を定義したいと考えています。しかし、メソッドディスパッチを取得してメソッドを見つける方法がわかりません。方法はありますか?

まず、S3 オブジェクト 'a' (oldClass "A") と 'df' (oldClass "data.frame") を定義します。

a <- 4
oldClass(a) <- "A"
df <- data.frame(x=1:2,y=3:4)

次に、trace(Ops.data.frame, edit=TRUE) を使用して、最初の行に print("Ops.data.frame") を追加します。このようにして、Ops.data.frame がいつ呼び出されるかがわかります。ここにデモンストレーションがあります:

a*df
# [1] "Ops.data.frame"
# x  y
# 1 4 12
# 2 8 16

クラス「A」の S3 メソッドを定義できます。

Ops.A <- function(e1, e2) {
  print("Ops.A")
  oldClass(e1) <- oldClass(e1)[oldClass(e1) != "A"]
  oldClass(e2) <- oldClass(e2)[oldClass(e2) != "A"]
  callGeneric(e1, e2)
}

これは a に対して呼び出されますが、 dfに対しては呼び出されません:

# This successfully calls Ops.A
a*a
# [1] "Ops.A"
# [1] 16

# But this throws an error
a*df
# Error in a * df : non-numeric argument to binary operator
# In addition: Warning message:
#   Incompatible methods ("Ops.A", "Ops.data.frame") for "*" 

それではうまくいきません。

remove(Ops.A)

代わりに S4 ​​メソッドを使用するのはどうですか? これには S4 クラス "A" を定義する必要がありますが、通常、oldClass "A" を持つ S3 オブジェクトは S4 ディスパッチによって引き続き検出されます。

setClass("A", list("numeric")) # Required to define a method for "A"
setGeneric("ATypicalMethod", function(e1, e2) {print("ATypicalMethod - default")})
setMethod("ATypicalMethod", signature=c("A","A"), function(e1, e2) {print("ATypicalMethod - A,A")})
ATypicalMethod(a,a)
# [1] "ATypicalMethod - A,A"

ただし、それは Ops では機能しません。

setMethod("Ops", signature=c("A","data.frame"), function(e1, e2) {
  print("Ops(A,data.frame)")
  callGeneric(e1@.Data, e2)
})
# Nope - when the scalar is an S3 object, we never find Ops(A,data.frame):
a*df
# [1] "Ops.data.frame"
# x  y
# 1 4 12
# 2 8 16

dfのこの動作は、 Martin Morgan ( https://stackoverflow.com/a/12101238/3203184 ) と ?Methods によって説明されています。S3 ジェネリックが直接呼び出された場合、S4 メソッドは決して見つからないと言っています。a と df の両方が S3 オブジェクトであるため、これは df で発生しているように見えます。

setOldClassまた、 ;を呼び出すことも役に立ちません。問題は、S3 オブジェクトがS4 メソッドのディスパッチによって認識できないことではなく、2 つの S3 オブジェクトが のようなメソッドに渡されたときに検索されないことです*。これらのケースでは、S3 ジェネリックが直接呼び出され、S4 ラベル付けが S4 ディスパッチにつながることはありません。

setOldClass("A", S4Class="A")
a*df
# [1] "Ops.data.frame"
# x  y
# 1 4 12
# 2 8 16

だから今、私は途方に暮れています。S3 オブジェクトの S4 メソッドを発見する方法が見つかりませんでし*た。また、data.frame メソッドに取って代わる S3 メソッドを作成する方法も見つかりませんでした。

スカラーを S4 オブジェクトにしたい場合は、必要なディスパッチを取得できます。

a <- new("A", 4)
a*df
# [1] "Ops(A,data.frame)"
# [1] "Ops.data.frame"
# x  y
# 1 4 12
# 2 8 16

しかし、私は本当に「a」を S3 オブジェクトとして保持したいと考えています。(1) 'a' を S3 にする方法と (2) Ops('A', 'data.frame') の独自のメソッドを定義する方法はありますか?

4

1 に答える 1

0

非常に醜い方法: '*' 関数をオーバーライドする

a <- 4
oldClass(a) <- "A"
df <- data.frame(x=1:2,y=3:4)

my_add_df <- function(e1, e2) {
  print('my_add_df')
  print(e1)
  print(e2)
}

`*` <- function(e1, e2) {
  if (inherits(e1, 'A') && inherits(e2, 'data.frame'))
    my_add_df(e1, e2)
  else 
    .Primitive("*")(e1, e2)
}

a <- 4
oldClass(a) <- "A"
df <- data.frame(x=1:2,y=3:4)

my_add_df <- function(e1, e2) {
  print('my_add_df')
  print(e1)
  print(e2)
}

`*` <- function(e1, e2) {
  if (inherits(e1, 'A') && inherits(e2, 'data.frame'))
    my_add_df(e1, e2)
  else 
    .Primitive("*")(e1, e2)
}
于 2014-04-08T15:24:27.753 に答える