2016-09-08 9 views
2

の異種行に関数を適用しますが、私はいくつかの(非ベクトル化)機能fooがあるとします。data.frame

foo <- function (bar, baz, frobozz, frotz = 42) { 
    if (frobozz) { 
     frotz 
    } 
    else { 
     bar * nchar(baz) 
    } 
} 

それは愚かな機能は、間違いなくだが、この質問の目的のために、与えられたように取る。 (IOW、fooを変更することを前提回答が範囲外である。)

また、以下に示すように、私は、data.framedfを持っていると仮定する:

> df 
    frobozz bar baz 
1 TRUE 1 a 
2 FALSE 2 b 
3 TRUE 3 c 
4 FALSE 4 d 
5 TRUE 5 e 

次に、dfの各行はみなすことができます異種名義リスト(以下、というレコードと略記します)。

実際に、そのようなレコードとしてdfの行のいずれかをキャストすることは困難ではない。

> df[1, , drop = TRUE] 
$frobozz 
[1] TRUE 

$bar 
[1] 1 

$baz 
[1] "a" 

また、その名前のスロットのいずれかのために、このようなレコードの値は、のような適切なタイプのものです同じ名前の引数はfooの署名にあります。

これは私がdfのいずれか単一行にfooを適用するためにdo.callを使用できることを意味します(これもdfの順序付けの列とfooの順序 "かかわらず動作することに注意してください

> do.call(foo, df[1, , drop = TRUE]) 
[1] 42 
> do.call(foo, df[2, , drop = TRUE]) 
[1] 2 

必要な引数が一致しません)

fooにすべての行のを適用して新しい列を作成します。

私はapplyは、タスクまでだろうと期待していたが、それは失敗します。もちろん

> apply(df, 1, foo) 
Error in FUN(newX[, i], ...) : 
    argument "frobozz" is missing, with no default 

、私はこのような何かに頼ることができます:

sapply(1:nrow(df), function (i) { do.call(foo, df[i, , drop = TRUE]) }) 

が少ない無知ありこれを達成するための見通しの方法?


ここでは、より扱いやすいかもしれないこの質問の変形です。それは必要なすべての引数、recordは、barという名前の要素、baz、およびfrobozzを持っているということですので

foo_wrapper <- function (record) { 
    foo(record$bar, record$baz, record$frobozz) 
} 

この機能、fooよりも柔軟である;:

は機能foo_wrapperを考えてみましょうそれが持つかもしれない他の要素については気にしません。また、1はdo.callに頼らずに、dfの行に直接foo_wrapperを適用することができます。

> foo_wrapper(df[4, , drop = TRUE]) 
[1] 4 

残念ながら、applyも同様foo_wrapperで失敗します。

> apply(df, 1, foo_wrapper) 
Error in record$frobozz : $ operator is invalid for atomic vectors 
+5

参照を '実行できますか?mapply'。 'do.call(mapply、c(foo、df))'を試してください。 – nicola

+1

[this](http://stackoverflow.com/questions/10078211/use-multiple-columns-as-variables-with-sapply)が役立つかもしれないと思います。 '?mapply'またはそのラッパー'?Vectorize' - 'do.call(Vectorize(foo)、df)' –

+0

@ Hack-R 'baz'カラムは' foo'の順に文字でなければなりません。 – nicola

答えて

2

あなただけVectorizeあなたの機能することができますし、変数にアクセスするにはwith()を使用します。たとえば、あなたのサンプルデータが...

dd <- read.table(text="frobozz bar baz 
1 TRUE 1 a 
2 FALSE 2 b 
3 TRUE 3 c 
4 FALSE 4 d 
5 TRUE 5 e", header=T, stringsAsFactors=F) 

次に、あなたは

with(dd, Vectorize(foo)(frobozz=frobozz, bar=bar, baz=baz)) 
# [1] 42 2 42 4 42 
+0

とてもエレガントです。 +1! – kjo