5

Java のような一般的なプログラミング言語では、通常、各ファイルはクラスに対応します。

R を使い始めたばかりです。小さなプログラムを作成したいのですが、このような特定のファイルとディレクトリ構造を作成したいと考えていました。

Main.R # the main control script 
MyClass.R # A class that is referenced from within Main.R 
ProcessData.R # Another class that uses an object of MyClass.R as input

だから私はこのようなことをしたいと思います(疑似コード):

Main.R

myc <- new MyClass # create a new instance of MyClass from within Main.R
pd <- new ProcessData 
pd$processMyClass( myc ) # call a method in ProcessData that processes the myc object in some way

これはかなり抽象的ですが、これがRで原則的に可能かどうかを知りたかっただけです.

更新:より具体的にする必要があります。したがって、質問: 次のおもちゃのプログラムと同じ数のファイルと構造を維持することによって、次の Java プログラムを R プログラムにどのように変換しますか?

Main.java:

public static void main( String[] args ) {
    MyClass myc = new MyClass("SampleWord");
    ProcessData pd = new ProcessData();
    pd.processData( myc );
}

MyClass.java

class MyClass {

    public String word;

    public MyClass( String word ) {
        this.word = word;
    }
}

ProcessData.java

class ProcessData.java {

    public void processData( MyClass myc ) {
        System.out.println( "pd.processData = " + myc.word );
    }

}
4

2 に答える 2

10

階級制度

R、S3、S4、および参照クラスの 3 つのクラス システムを確認してください。

## S3 methods, Section 5 of
RShowDoc("R-lang")

## S4 classes
?Classes
?Methods

## Reference classes
?ReferenceClasses

Java のバックグラウンドを持っていると、参照クラスを使いたくなるかもしれませんが、これらには「参照セマンティクス」と遠く離れたアクションがあります (1 つのオブジェクトを変更すると、同じデータを参照する別のオブジェクトが変更されます)。一方、ほとんどの R ユーザーは「変更時にコピー」を期待します。 ' セマンティクス。S3 クラスで大きな進歩を遂げることができますが、より規律あるアプローチでは S4 を採用すると思います。S4 の機能に驚くかもしれません。その理由の 1 つは、クラス システムが Java よりも一般的な Lisp オブジェクト システムに近いからです。

他の意見やオプションがあります。

基本的な実装

「ProcessData」の設計目標が何であるかはよくわかりません。あなたの 2 つのクラスをクラス、ジェネリック、および MyClass クラスで動作するジェネリックのメソッドとして実装します。

## definition and 'low-level' constructor
.MyClass <- setClass("MyClass", representation(word="character"))

## definition of a generic
setGeneric("processData", function(x, ...) standardGeneric("processData"))

setMethod("processData", "MyClass", function(x, ...) {
    cat("processData(MyClass) =", x@word, "\n")
})

これは完全で完全に機能します

> myClass <- .MyClass(word="hello world")
> processData(myClass)
processData(MyClass) = hello world 

3 つのコード行は、"AllGenerics.R" と "MyClass.R" (メソッドを含む) の 2 つのファイル、または "AllGenerics.R"、"AllClasses.R"、"processData-methods.R" (メソッドはジェネリックに関連付けられており、クラスでディスパッチされていることに注意してください)。

追加実装

通常、よりユーザーフレンドリーなコンストラクターを追加します。たとえば、予想されるデータ型についてユーザーにヒントを提供したり、複雑な引数の初期化手順を実行したりします。

MyClass <- function(word=character(), ...)
{
    .MyClass(word=word, ...)
}

通常、直接スロット アクセスではなく、スロット アクセサーが必要です。これは、単純な関数 (図のように) または一般的な + メソッドにすることができます。

word <- function(x, ...) x@word

スロットを更新する場合は、代わりの関数またはメソッドを記述します。関数またはメソッドには、通常、更新するオブジェクト、可能な追加の引数、およびオブジェクトを更新する値の 3 つの引数があります。これは一般的な + メソッドの実装です

setGeneric("word<-", function(x, ..., value) standardGeneric("word<-"))

setReplaceMethod("word", c("MyClass", "character"), function(x, ..., value) {
    ## note double dispatch on x=MyClass, value=character
    x@word <- value
    x
})

ややトリッキーな代替実装は

setReplaceMethod("word", c("MyClass", "character"), function(x, ..., value) {
    initialize(x, word=value)
})

これは、initializeジェネリックおよびデフォルト メソッドをコピー コンストラクターとして使用します。これは、複数のスロットを同時に更新する場合に効率的です。

getGeneric("show")クラスはユーザーに表示されるため、ジェネリック ( ) が既に存在する'show' メソッドを使用して、ユーザー フレンドリーな方法でクラスを表示する必要があります。

setMethod("show", "MyClass", function(object) {
    cat("class:", class(object), "\n")
    cat("word:", word(object), "\n")
})

そして今、私たちのユーザーセッションは次のようになります

> myClass
class: MyClass 
word: hello world 
> word(myClass)
[1] "hello world"
> word(myClass) <- "goodbye world"
> processData(myClass)
processData(MyClass) = goodbye world

効率

R はベクトルに対して効率的に機能します。S4 クラスも例外ではありません。そのため、クラスの各スロットは、1 つの行の要素ではなく、多くの行にまたがる列を表すように設計されています。スロット「単語」には、通常、長さが 1 よりもはるかに大きいベクトルが含まれており、操作がベクトルのすべての要素に作用することが予想されます。したがって、これを念頭に置いてメソッドを作成します。たとえば、show メソッドを次のように変更します。

setMethod("show", "MyClass", function(object) {
    cat("class:", class(object), "\n")
    cat("word() length:", length(word(object)), "\n")
})

これはより大きなデータオブジェクトです(私のLinuxシステムのファイルを使用)

> amer <- MyClass(readLines("/usr/share/dict/american-english"))
> brit <- MyClass(readLines("/usr/share/dict/british-english"))
> amer
class: MyClass 
word() length: 99171 
> brit
class: MyClass 
word() length: 99156 
> sum(word(amer) %in% word(brit))
[1] 97423
> amer_uc <- amer  ## no copy, but marked to be copied if either changed
> word(amer_uc) <- toupper(word(amer_uc))  ## two distinct objects

これらはすべて非常に高性能です。

参照クラス「アクション・アット・ア・ディスタンス」のハザード

S4 クラスのより単純な実装に戻りましょう。直接スロット アクセスがあり、手の込んだコンストラクターはありません。これがアメリカの辞書と大文字に変換されたコピーです

.MyClass <- setClass("MyClass", representation(word="character"))
amer <- .MyClass(word=readLines("/usr/share/dict/american-english"))
amer_uc <- amer
amer_uc@word <- toupper(amer_uc@word)

大文字であることに注意してamer_ucくださいamer

> amer@word[99 + 1:10]
 [1] "Adana"      "Adar"       "Adar's"     "Addams"     "Adderley"  
 [6] "Adderley's" "Addie"      "Addie's"    "Addison"    "Adela"     
> amer_uc@word[99 + 1:10]
 [1] "ADANA"      "ADAR"       "ADAR'S"     "ADDAMS"     "ADDERLEY"  
 [6] "ADDERLEY'S" "ADDIE"      "ADDIE'S"    "ADDISON"    "ADELA"     

これは実際に R ユーザーが期待していることです。別のオブジェクトを作成して変更しました。元のオブジェクトは変更されていません。これは私の主張です。Rユーザーが何を期待しているのか、私にはわからないかもしれません。R ユーザーは、これが参照クラスであるという事実にあまり注意を払っていないと思いますが、integer()ベクトルや のような別の R オブジェクト、data.frameまたは の戻り値であると考えていますlm()

対照的に、参照クラスの最小限の実装と同様の操作を次に示します。

.MyRefClass <- setRefClass("MyRefClass", fields = list(word="character"))
amer <- .MyRefClass(word=readLines("/usr/share/dict/american-english"))
amer_uc <- amer
amer_uc$word <- toupper(amer_uc$word)

しかし、今ではameramer_uc!の両方を変更しました。C または Java プログラマーは完全に期待していますが、R ユーザーは期待していません。

> amer$word[99 + 1:10]
 [1] "ADANA"      "ADAR"       "ADAR'S"     "ADDAMS"     "ADDERLEY"  
 [6] "ADDERLEY'S" "ADDIE"      "ADDIE'S"    "ADDISON"    "ADELA"     
> amer_uc$word[99 + 1:10]
 [1] "ADANA"      "ADAR"       "ADAR'S"     "ADDAMS"     "ADDERLEY"  
 [6] "ADDERLEY'S" "ADDIE"      "ADDIE'S"    "ADDISON"    "ADELA"     
于 2013-04-20T13:54:12.370 に答える
7

参照クラス以下では、R をできるだけ近い方法で使用して、問題の Java コードを複製しようとします。その点で、組み込みの 3 つの R クラス システム (S3、S4、参照クラス) の中で、参照クラスがそのスタイルに最も近いようです。参照クラスは、R に追加された最新のクラス システムであり、その急速な普及は、そのスタイルに精通している R にやってくる Java プログラマーによるものかもしれません。

(これからパッケージを作成する場合は、すべてのソースステートメントを省略してください。)

Main.R ファイル:

source("MyClass.R")
source("ProcessData.R")

main <- function() {
    myc <- new("MyClass", word = "SampleWord")
    pd <- new("ProcessData")
    cat("pd$processData =", pd$processData(myc), "\n")
}

MyClass.R ファイル:

setRefClass("MyClass", 
    fields = list(word = "character")
)

ProcessData.R ファイル:

setRefClass("ProcessData",
    fields = list(myc = "MyClass"),
    methods = list(
        processData = function(myc) myc$word
    )
)

走る:

source("Main.R")
main()

proto パッケージproto パッケージ は、Self プログラミング言語に由来するオブジェクト指向プログラミングのプロトタイプ モデルを実装し、javascript や Lua にある程度存在し、特にio 言語の基礎となっています。proto はこのスタイルを簡単にエミュレートできます ( proto vignetteの特徴セクションで説明されているように):

Main.R ファイル:

source("MyClass.R")
source("ProcessData.R")  

library(proto)

main <- function() {
    myc <- MyClass$new("SampleWord")
    pd <- ProcessData$new()
    cat("pd$processData =", pd$processData(myc), "\n")
}

MyClass.R ファイル:

MyClass <- proto(
    new = function(., word) proto(word = word)
)

ProcessData.R ファイル:

ProcessData <- proto(
    new = function(.) proto(.), 
    processData = function(., myc) myc$word
)

走る:

source("Main.R")
main()

更新: プロトの例を追加しました。

更新 2: 改善さmainMyClass、参照クラスの例で。

于 2013-04-20T14:39:01.170 に答える