`vapply`が` sapply`より安全なのはなぜですか?


84

ドキュメントには

vapplyに似てsapplyいますが、事前に指定されたタイプの戻り値があるため、より安全に使用できます[...]。

なぜ一般的に安全なのか、例を挙げて詳しく教えてください。


PS:私は答えを知っています、そして私はすでに避けがちsapplyです。同僚にそれを指摘できるように、ここSOに良い答えがあったらいいのにと思います。「マニュアルを読む」という答えはありません。


1
これはより予測可能であり、コードのあいまいさが少なくなり、より堅牢になります。特に大規模なプロジェクト、たとえば大規模なパッケージでは、これが関係します。
Paul Hiemstra 2012

1
FUN.VALUEのvapplyマニュアルの例は非常に複雑で、sapplyユーザーにとっては威圧的です。
jsta 2016

回答:


73

すでに述べたように、vapply2つのことを行います。

  • わずかな速度の改善
  • 限定された戻り値の型チェックを提供することにより、一貫性を向上させます。

2番目のポイントは、エラーが発生する前にエラーをキャッチするのに役立ち、より堅牢なコードにつながるため、より大きな利点です。この戻り値のチェックは使用して個別に行うことができるsapplyが続くstopifnot必ず戻り値は、あなたが期待したものと一致しているが、ことを確認するためにvapply、より制限された場合に、カスタムエラーチェックコード等の境界、内の値をチェックする可能性があるので、(少し簡単です)。

vapply結果が期待どおりであることを確認する例を次に示します。これは、PDFスクレイピング中に私が今取り組んでいたことと似ていfindDます。生のテキストデータのパターンに一致させるため(たとえばsplit、エンティティごとのリストと、各エンティティ内のアドレスに一致する正規表現があります。PDFが順不同に変換され、2つのアドレスが存在する場合があります。悪を引き起こした実体)。

> input1 <- list( letters[1:5], letters[3:12], letters[c(5,2,4,7,1)] )
> input2 <- list( letters[1:5], letters[3:12], letters[c(2,5,4,7,15,4)] )
> findD <- function(x) x[x=="d"]
> sapply(input1, findD )
[1] "d" "d" "d"
> sapply(input2, findD )
[[1]]
[1] "d"

[[2]]
[1] "d"

[[3]]
[1] "d" "d"

> vapply(input1, findD, "" )
[1] "d" "d" "d"
> vapply(input2, findD, "" )
Error in vapply(input2, findD, "") : values must be length 1,
 but FUN(X[[3]]) result is length 2

私が生徒たちに言っているように、プログラマーになることの一部は、あなたの考え方を「エラーは迷惑です」から「エラーは私の友達です」に変えることです。

ゼロ長入力
1つの関連するポイントは、入力長がゼロの場合、sapply入力タイプに関係なく、常に空のリストを返すことです。比較:

sapply(1:5, identity)
## [1] 1 2 3 4 5
sapply(integer(), identity)
## list()    
vapply(1:5, identity)
## [1] 1 2 3 4 5
vapply(integer(), identity)
## integer(0)

を使用vapplyすると、特定のタイプの出力が保証されるため、長さがゼロの入力に対して追加のチェックを作成する必要はありません。

ベンチマーク

vapply 結果を期待する形式がすでにわかっているため、少し速くなる可能性があります。

input1.long <- rep(input1,10000)

library(microbenchmark)
m <- microbenchmark(
  sapply(input1.long, findD ),
  vapply(input1.long, findD, "" )
)
library(ggplot2)
library(taRifx) # autoplot.microbenchmark is moving to the microbenchmark package in the next release so this should be unnecessary soon
autoplot(m)

自動プロット


15

関連する余分なキーストロークvapplyにより、後で混乱する結果をデバッグする時間を節約できます。呼び出している関数が異なるデータ型を返す可能性がある場合は、vapply必ず使用する必要があります。

頭に浮かぶ1つの例sqlQueryは、RODBCパッケージにあります。クエリの実行中にエラーが発生した場合、この関数はcharacterメッセージを含むベクトルを返します。したがって、たとえば、テーブル名のベクトルを反復処理し、tnames各テーブルの数値列「NumCol」から次のように最大値を選択しようとしているとします。

sapply(tnames, 
   function(tname) sqlQuery(cnxn, paste("SELECT MAX(NumCol) FROM", tname))[[1]])

すべてのテーブル名が有効な場合、これはnumericベクトルになります。ただし、データベース内でテーブル名の1つが変更され、クエリが失敗した場合、結果は強制的にモードになりますcharacter。ただし、vapplywithを使用するとFUN.VALUE=numeric(1)、ここでエラーが停止し、エラーがどこかでポップアップするのを防ぐことができます。


13

結果を常に特定のものにしたい場合...たとえば、論理ベクトル。 vapplyこれが確実にsapply行われるようにしますが、必ずしもそうとは限りません。

a<-vapply(NULL, is.factor, FUN.VALUE=logical(1))
b<-sapply(NULL, is.factor)

is.logical(a)
is.logical(b)

4
logical(1)この場合、最も明白なことは、タイプを指定する代わりにオプションを「オフ」に設定するように見えるためだと思います
空飛ぶ羊
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.