5

ほとんどのプロ R ユーザーは、R でループを使用しないようにアドバイスしてくれました。代わりに適用関数を使用してください。問題は、関数型プログラミングに慣れていない場合、すべての for/while ループに相当する適用を記述するのはそれほど直感的ではないことです。たとえば、以下の例を見てください。

F <- data.frame(name = c("a", "b", "c", "d"), var1 = c(1,0,0,1), var2 = c(0,0,1,1),  
var3 = c(1,1,1,1), clus = c("one", "two", "three", "four"))
F$ObjTrim <- ""
for (i in 1:nrow(F))
{
 for (j in 2:(ncol(F)-1))
{
 if(F[i, j] == 1) 
 {F$ObjTrim[i]  <- paste(F$ObjTrim[i], colnames(F)[j], sep = " ") }

 }
  print(i)
}

ここでの目的は、値 == 1 を持つすべての列名の値を取る変数「ObjTrim」を作成することです。誰かがこれに相当する適切な適用を提案できますか?

たとえば、上記のコードは次のようになります。

 name var1 var2 var3  clus         ObjTrim
1    a    1    0    1   one       var1 var3
2    b    0    0    1   two            var3
3    c    0    1    1 three       var2 var3
4    d    1    1    1  four  var1 var2 var3

ありがとう!

4

3 に答える 3

4

あなたが引用した例ではなく、あなたの一般的な質問と思われるものに答えるために --- for ループを適用バリアントに変換する方法 --- 以下はいくつかの有用なポインタかもしれません:

  1. 反復するオブジェクトの構造を考慮してください。たとえば、次のようなさまざまなタイプがあります。

    a) ベクトル/行列の要素。b) マトリックスの行/列。c) 高次元配列の次元。d) リストの要素 (それ自体が上記のオブジェクトの 1 つである可能性があります)。e) 複数のリスト/ベクトルの対応する要素。

    いずれの場合も、使用する機能はわずかに異なる場合がありますが、使用する戦略は同じです。さらに、apply ファミリを学習します。さまざまな *pply 関数は同様の抽象化に基づいていますが、入力として受け取るものと出力としてスローするものが異なります。

  2. たとえば、上記のケースリストでは。

    a) ベクトルの要素: R のコアの強みである既存のベクトル化されたソリューション (上記のような) を探します。その上で、行列代数を検討します。ループ (またはネストされたループ) が必要と思われるほとんどの問題は、行列代数の方程式として記述できます。

    b) 行列の行/列: を使用しapplyます。MARGIN引数には正しい値を使用してください。c) 高次元配列についても同様です。

    d) を使用しlapplyます。simplify2array(lapply(...))返される出力が「単純な」構造 (スカラーまたはベクトル) である場合は、単純で適切な次元の配列を返すsapply を考慮することができます。

    e) を使用しmapplyます。「m」は、多変量適用を表すことができます。

  3. 繰り返し処理しているオブジェクトと対応するツールを理解したら、問題を単純化します。繰り返し処理しているオブジェクト全体ではなく、その 1 つのインスタンスについて考えてください。たとえば、行列の行を反復処理するときは、行列のことは忘れて、行だけを覚えておいてください。

    次に、イテランドの 1 つのインスタンス (要素) のみを操作する関数 (またはラムダ) を作成し、*pply ファミリの正しいメンバーを使用して単純に「適用」します。

それでは、この戦略を使用して、@agstudy によって提供されたクリーンなソリューションを複製するために、問題の例を取り上げてみましょう。

  1. 最初に特定することは、行列の行を反復処理していることです。明らかに、ループ ソリューションが で始まるので、これは理解できますfor (i in 1:nrow(F))

  2. applyあなたの友人として識別します。

  3. この行で何をする必要があるかを理解してください。まず、どの値が 1 であるかを調べます。次に、これらの値の列名を見つける必要があります。そして、これらの colnames を連結する方法を見つけます。説明を助けるために@agstudyのソリューションを自由に書き直すことができる場合:

    process.row <- function (arow) {
      ones <- arow == 1 # Returns logical vector.
      cnames <- colnames[ones] # Logical subsetting.
      cnames <- paste(cnames, collapse=' ') # Paste the names together.
      cnames # Return
    }
    

    そして、あなたは解決策を得る:

    F$ObjTrim = apply(X=F, MARGIN=1, FUN=process.row)
    

    そして、このような思考が本能的になってきたら、R の機能を使用して、次のような密な式を記述することができます。

    F$ObjTrim = apply(F,1,function(x) paste(colnames(F)[x==1],collapse=' '))
    

これは、オンザフライでロールされる「ラムダ」を使用してジョブを完了します。

于 2013-06-09T13:31:40.133 に答える