11

S4クラスを含むさまざまな変数のdata.frameを作成したいと思います。「POSIXlt」(日付用)のような組み込みクラスの場合、これは正常に機能します。

as.data.frame(list(id=c(1,2), 
                   date=c(as.POSIXlt('2013-01-01'),as.POSIXlt('2013-01-02'))

しかし今、私はユーザー定義のクラスを持っています。たとえば、名前と年齢を持つ「Person」クラスを考えてみましょう。

setClass("person", representation(name="character", age="numeric"))

しかし、以下は失敗します:

as.data.frame(list(id=c(1,2), pers=c(new("person", name="John", age=20),
                                     new("person", name="Tom", age=30))))

私もオーバーロードしようとしました[...]-を使用して人のクラスの演算子

setMethod(
  f = "[",
  signature="person",
  definition=function(x,i,j,...,drop=TRUE){ 
    initialize(x, name=x@name[i], age = x@age[i])
  }
)

これにより、ベクトルのような動作が可能になります。

persons = new("person", name=c("John","Tom"), age=c(20,30))
p1 = persons[1]

しかし、それでも次は失敗します。

as.data.frame(list(id=c(1,2), pers=persons))

おそらく、ユーザー定義クラスをデータフレームに取り込むために、より多くの演算子をオーバーロードする必要がありますか?POSIXltはS4クラスであり、機能するため、これを行う方法があるはずです。新しいR5参照クラスを使用するソリューションも問題ありません。

すべてのデータをpersonクラスに入れたくありません(「id」がpersonのメンバーではない理由は、データフレームを使用しないだけです)。アイデアは、私のdata.frameが、文字列、数値など、さまざまなタイプの多くの列を持つデータベースのテーブルを表すということですが、日付、間隔、ジオオブジェクトなどもあります。間隔、ジオオブジェクトなどのソリューション(POSIXlt)。おそらく、独自のS4/R5クラスを指定する必要があります。

よろしくお願いします。

4

2 に答える 2

9

これがあなたのクラスで、行ではなく、その定義の「列」の解釈があります。これはパフォーマンスにとって重要です。参照用の日付も

setClass("person", representation(name="character", age="numeric"))
pers <- new("person", name=c("John", "Tom"), age=c(20, 30))
date <- as.POSIXct(c('2013-01-01', '2013-01-02'))

methods(class="POSIXct")エラーメッセージを見て注意を払うことを含むいくつかの実験により、私は実装as.data.frame.personし、format.person(後者はdata.frameでの表示に使用されます)

as.data.frame.person <-
    function(x, row.names=NULL, optional=FALSE, ...)
{
    if (is.null(row.names))
        row.names <- x@name
    value <- list(x)
    attr(value, "row.names") <- row.names
    class(value) <- "data.frame"
    value
}

format.person <- function(x, ...) paste0(x@name, ", ", x@age)

これにより、オブジェクトがdata.frameに格納されます。

> lst <- list(id=1:2, date=date, pers=pers)
> as.data.frame(lst)
     id       date     pers
John  1 2013-01-01 John, 20
Tom   2 2013-01-02  Tom, 30

サブセット化したい場合は、

setMethod("[", "person", function(x, i, j, ..., drop=TRUE) {
    initialize(x, name=x@name[i], age=x@age[i])
})

より多くの操作が発生したときに他にどのようなメソッドが必要になるかdata.frameわかりません。「data.frameインターフェイス」はありません。

data.tableでベクトル化されたクラスを使用するには、構築にlengthメソッドが必要なようです。

> library(data.table)
> data.table(id=1:2, pers=pers)
Error in data.table(id = 1:2, pers = pers) : 
  problem recycling column 2, try a simpler type
> setMethod(length, "person", function(x) length(x@name))
[1] "length"
> data.table(id=1:2, pers=pers)
   id     pers
1:  1 John, 20
2:  2  Tom, 30

たぶんdata.tableインターフェースがありますか?

于 2013-01-30T15:15:40.520 に答える
2

メーリングリストのこのスレッドから判断すると:

http://tolstoy.newcastle.edu.au/R/e2/devel/06/11/1013.html

... John Chambersは2006年にこれについて考えていました。それでも、データフレームの列にS4オブジェクトを配置することはできません。また、複雑なS3クラスをデータフレームの列に配置することもできません。

それを行う可能性のある他の表形式のデータ構造がいくつかあります-data.tableおそらく:

require(data.table)
setClass("geezer", representation(name="character", age="numeric"))
tom=new("geezer",name="Tom",age=20)
dick=new("geezer",name="Dick",age=23)
harry=new("geezer",name="Harry",age=25)
gt = data.table(geezers=c(tom,dick,harry),weapons=c("Gun","Gun","Knife"))
gt
    geezers weapons
1: <geezer>     Gun
2: <geezer>     Gun
3: <geezer>   Knife

data.tableのセマンティクスはdata.frameとは少し異なり、data.frameを使用するコードにdata.tableをプラグインして、それが機能することを期待することはできません(たとえばlmglmぐらつくでしょう)。しかし、data.tableの作成者は列の複合クラスを許可しているようです...

于 2013-01-30T14:43:40.697 に答える