當前位置: 首頁>>編程示例 >>用法及示例精選 >>正文


R setMethod 創建並保存方法

R語言 setMethod 位於 methods 包(package)。

說明

為泛型函數創建一個方法,對應於參數的類簽名。標準用法將采用以下形式:

setMethod(f, signature, definition)

其中f 是函數的名稱,signature 指定該方法適用的參數類,definition 是該方法的函數定義。

用法

setMethod(f, signature=character(), definition,
          where = topenv(parent.frame()),
          valueClass = NULL, sealed = FALSE)

參數

f

通用函數的字符串名稱。不帶引號的名稱通常也可以使用(評估通用函數),但基礎包中的一些函數除外。

signature

某些參數所需的類。大多數應用程序隻需要一個或兩個與簽名中的第一個參數匹配的字符串。更複雜的情況遵循 R 的參數匹配規則。請參閱下麵的詳細信息;但是,如果簽名不簡單,您應該使用 method.skeleton 生成對 setMethod 的有效調用。

definition

函數定義,當 f 調用中的參數直接或通過繼承與 signature 中的類匹配時,它將成為調用的方法。定義必須是一個與泛型具有相同形式參數的函數;但是,如果 ... 是泛型的形式參數,則 setMethod() 將處理添加參數的方法。請參閱詳細信息部分。

where, valueClass, sealed

這些論點是允許的,但或者過時,或者很少合適。

where :存儲定義的位置;應該是默認的,包的命名空間。

valueClass:已過時。

sealed :防止重新定義方法,但在包的源代碼中定義方法時永遠不需要。

該函數的存在是因為它的副作用。該定義將存儲在特殊的元數據對象中,並在相應的包加載到 R 會話中時合並到通用函數中。

方法選擇:避免歧義

定義方法時,確保正確選擇方法非常重要;特別是,包的設計應避免方法選擇不明確。

為了說明方法選擇,首先考慮主動簽名中隻有一個形式參數的情況;也就是說,隻有一個參數,例如x,已為其定義了方法。通用函數有一個方法表,按 setMethod 調用中參數的類進行索引。如果表中存在調用中的x類的方法,則選擇該方法。

如果不是,下一個最佳方法將對應於 class(x) 的直接超類 - 定義該類時出現在 contains= 參數中的方法。如果其中任何一個都沒有方法,則下一個最佳方法將對應於第一組超類的直接超類,依此類推。

如果該類有多個直接超類並且已為其中多個直接超類定義了方法,則出現第一個可能的歧義來源;R將認為這些同樣有效並報告不明確的選擇。如果你的包有類定義class(x),那麽您需要為泛型函數和類的組合顯式定義一個方法。

當方法簽名中出現多個形式參數時,R要求為每個參數明確選擇“best”方法。當一種方法特定於一個論點而另一種方法特定於不同的論點時,就會出現歧義。滿足這兩個要求的調用是不明確的:這兩個方法看起來同樣有效,應該選擇哪個?在這種情況下,包需要添加第三個方法,要求兩個參數匹配。

最常見的例子是二元運算符。可以為單個運算符、特殊運算符組(例如 Arith 或組 Ops )定義方法。

導出方法

如果一個包定義了泛型函數的方法,那麽當導出任何涉及的類時,這些方法也應該被導出;換句話說,如果使用該包的人可能期望調用這些方法。通過在包的 NAMESPACE 文件中包含 exportMethods() 指令來導出方法,該指令的參數是已為其定義方法的通用函數的名稱。

從聲明你想要發生的事情的意義上來說,導出方法總是可取的,因為你確實希望用戶找到這樣的方法。如果該方法是為某個函數定義的,而該函數原本不是其自己的包中的通用函數(例如,plot()在裏麵graphics包)。在這種情況下,可能是函數中的版本R會話不是通用的,並且您的方法不會被調用。

導出函數的方法也會導出該函數的通用版本。請記住,這確實不是與該函數衝突,因為它最初是在另一個包中定義的;相反,它的目的是確保函數Rsession 為您的類正確分派方法,並在沒有應用特定方法時繼續按預期運行。看Methods_Details對於實際的機製。

細節

setMethod 的調用將提供的方法定義存儲在環境(通常是全局環境或包的命名空間)中此通用函數的元數據表中。對於包,表對象成為包的命名空間或環境的一部分。當包加載到稍後的會話中時,這些方法將合並到相應通用函數對象的方法表中。

泛型函數通過函數名和包名的組合來引用;例如,包 "methods" 中的函數 "show" 。方法的元數據由兩個字符串標識;特別是,通用函數對象本身具有包含其名稱和包名稱的槽。泛型的包名是根據它最初來自的包來設置的;特別是,並且經常是該函數的非通用版本起源的包。例如,包 base 中所有函數的通用函數將以 "base" 作為包名稱,盡管它們都不是該包上的 S4 通用函數。其中包括大多數基元函數,而不是真正的函數;有關詳細信息,請參閱 setGeneric 文檔中有關原始函數的部分。

多個包可以具有相同通用函數的方法;也就是說,對於通用函數名稱和包名稱的相同組合。即使這些方法存儲在不同環境中的單獨表中,加載相應的包也會在會話期間將這些方法添加到通用函數本身的表中。

簽名中的類名可以是任何正式類,包括 "numeric""character""matrix" 等基本類。可以出現兩個額外的特殊類名: "ANY" ,這意味著該參數可以有任何類;和 "missing" ,這意味著此參數不得出現在調用中才能匹配此簽名。不要混淆這兩者:如果簽名中未提及參數,則它隱式對應於類 "ANY" ,而不是 "missing" 。請參閱下麵的示例。如果您需要與這些類兼容,也可以使用 Old-style (‘S3’) 類,但如果您希望 S3 樣式繼承起作用,則絕對應該通過調用 setOldClass 來聲明這些類。

方法定義可以具有參數的默認表達式,但前提是泛型函數必須具有一些相同參數的默認表達式。 (此限製是通過以下方式施加的R管理形式參數。)如果是這樣,並且在對泛型函數的調用中缺少相應的參數,則使用方法中的默認表達式。如果方法定義沒有參數的默認值,則使用泛型函數本身的定義中提供的表達式,但請注意,將使用方法的封閉環境而不是泛型函數的封閉環境來計算該表達式。方法選擇不會評估默認表達式。當選擇方法時,將評估泛型函數簽名中的所有實際(非缺失)參數 - 當調用standardGeneric(f)發生。注意指定類"missing"簽名中不需要任何默認表達式。

提供給 setMethod 的方法的形式參數與泛型的形式參數之間可能存在一些差異。粗略地說,如果泛型將 ... 作為其參數之一,則該方法可能具有額外的形式參數,這些參數將從調用 f 中匹配 ... 的參數進行匹配。 (實際發生的情況是,在方法內部創建了一個本地函數,並使用修改後的形式參數,並且重新定義了該方法以調用該本地函數。)

方法調度嘗試匹配為 f 收集的可用方法調用中的實際參數的類。如果為與此調用中完全相同的類定義了一個方法,則使用該方法。否則,所有可能的簽名都被視為對應於實際類或實際類的超類(包括 "ANY" )。選擇與實際類別距離最小的方法;如果多個方法具有最小距離,則選擇一個方法(就超類而言,按字典順序排列的第一個),但會發出警告。所有選擇的繼承方法都存儲在另一個表中,以便每個會話每個實際類序列隻需執行一次繼承計算。有關更多詳細信息,請參閱Methods_Details 和參考文獻的第 10.7 節。

例子


## examples for a simple class with two numeric slots.
## (Run example(setMethod) to see the class and function definitions)


## methods for plotting track objects 
##
## First, with only one object as argument, plot the two slots
##  y must be included in the signature, it would default to "ANY"
setMethod("plot", signature(x="track", y="missing"),
  function(x,  y, ...) plot(x@x, x@y, ...)
)

## plot numeric data on either axis against a track object
## (reducing the track object to the cumulative distance along the track)
## Using a short form for the signature, which matches like formal arguments
setMethod("plot", c("track", "numeric"),
 function(x, y, ...) plot(cumdist(x@x, x@y), y,  xlab = "Distance",...)
)

## and similarly for the other axis
setMethod("plot", c("numeric", "track"),
 function(x, y, ...) plot(x, cumdist(y@x, y@y),  ylab = "Distance",...)
)

t1 <- new("track", x=1:20, y=(1:20)^2)
plot(t1)
plot(qnorm(ppoints(20)), t1)

## Now a class that inherits from "track", with a vector for data at
## the points 
  setClass("trackData", contains = c("numeric", "track"))


tc1 <- new("trackData", t1, rnorm(20))


## a method for plotting the object
## This method has an extra argument, allowed because ... is an
## argument to the generic function.
setMethod("plot", c("trackData", "missing"),
function(x, y, maxRadius = max(par("cin")), ...) {
  plot(x@x, x@y, type = "n", ...)
  symbols(x@x, x@y, circles = abs(x), inches = maxRadius)
  }
)
plot(tc1)

## Without other methods for "trackData", methods for "track"
## will be selected by inheritance

plot(qnorm(ppoints(20)), tc1)

## defining methods for primitive function.
## Although "[" and "length" are not ordinary functions
## methods can be defined for them.
setMethod("[", "track",
  function(x, i, j, ..., drop) {
    x@x <- x@x[i]; x@y <- x@y[i]
    x
  })
plot(t1[1:15])

setMethod("length", "track", function(x)length(x@y))
length(t1)

## Methods for binary operators
## A method for the group generic "Ops" will apply to all operators
## unless a method for a more specific operator has been defined.

## For one trackData argument, go on with just the data part
setMethod("Ops", signature(e1 = "trackData"),
    function(e1, e2) callGeneric(e1@.Data, e2))

setMethod("Ops", signature(e2 = "trackData"),
    function(e1, e2) callGeneric(e1, e2@.Data))

## At this point, the choice of a method for a call with BOTH
## arguments from "trackData" is ambiguous.  We must define a method.

setMethod("Ops", signature(e1 = "trackData", e2 = "trackData"),
    function(e1, e2) callGeneric(e1@.Data, e2@.Data))
## (well, really we should only do this if the "track" part
## of the two arguments matched)

tc1 +1

1/tc1

all(tc1 == tc1)


參考

Chambers, John M. (2016) Extending R, Chapman & Hall. (Chapters 9 and 10.)

也可以看看

Methods_for_Nongenerics 討論原始包中非泛型函數的函數的方法定義; Methods_for_S3 討論形式方法與舊 S3 方法的集成。

method.skeleton ,這是生成 setMethod 調用框架的推薦方法,其中包含正確的形式參數和其他詳細信息。

Methods_Details 以及用於一般討論的鏈接,dotsMethods 用於在 “...” 上分派的方法,setGeneric 用於通用函數。

相關用法


注:本文由純淨天空篩選整理自R-devel大神的英文原創作品 Create and Save a Method。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。