tak0kadaの何でもノート

発声練習、生存確認用。

医学関連は 医学ノート

Rでのダックタイピング

先日参加した1細胞RNAseq解析勉強会は基本的なRプログラミングとシーケンサーから少し前処理したあとのリード数データの取り扱いについての講義であった。司会の先生が格好良くライブコーディングを披露されていたのでそれを観察していたのだが、一般的なオブジェクトに対してcolSumsを適用する場面があり面食らった。

具体的には

library(scater)
importFrom(Biobase,"pData<-")
sce <- newSCESet(countData=all.counts)
x <- pData(sce)
colSums(x)

のような感じだったと記憶している。ダックタイピングが行われており、xはSCESetクラスのオブジェクトなのだが、matrixやdata.frameに対して実行されるcolSums関数が適用できてしまっている。S4クラスなら以下のように実装すれば良さそう。ExpressionSetというスーパークラスを継承しているので実際にはBioconductorの中身を調べる必要があるが、詳細を調べてはいないので注意。

以下のコードではstructクラス、struct2クラスを実装した。containsは継承元のクラスを指定する。

# ただのS4クラスだと「cannot coerce type 'S4' to vector of type 'matrix'」というエラーが出る。
# 実装例その1(おそらくこちらに近い)
setClass("struct",
    contains = "matrix",
    representation=representation(
        version="numeric"
    )
)

newStruct <- function(mat, version)
{
    new("struct", mat, version=version)
}

a <- newStruct(matrix(1:4, nrow=2)), 0.01)
colSums(a)

# 実装例その2(SetGenericを無限に繰り返す必要があり微妙)
setClass("struct2",
    representation = representation(
        data = "matrix",
        version = "numeric"
    ),
    prototype = prototype (
        data = matrix(0, 0, 0),
        version = 0
    )
)

as.matrix.struct <- function(object)
{
    object@data
}
setGeneric("as.matrix", def = as.matrix.struct)

b <- new("struct2", data=matrix(1:4, nrow=2), version=0.1)
as.matrix(b)

ところでR3.4でjitコンパイラが標準になったらしいですね。R3.3ではSpeed up your R code using a just-in-time (JIT) compiler | R-statistics blogを使えば早くなるのでしょうか。メモリ消費量も減るとなお良さそうです。R言語徹底解説を読めばこの手の問題は解決しそうですがC++に時間をかけているのでまたそのうち。