タイトルとして、Rでベクトル化された関数を定義する方法を知りたいです。
- 関数でループを使用するだけですか?
- この方法は効率的ですか?
- そして、ベストプラクティスは何ですか?
Rレベルのループはベクトル化されていません。Rループは、ベクトルの各要素に対して同じRコードを呼び出すため、非効率的です。ベクトル化された関数は通常、ベクトルを取り、効率的な方法でベクトル全体を操作する関数を指します。最終的に、これにはforループが含まれますが、そのループはCなどの低水準言語で実行されているため、非常に効率的で、特定のタスクに合わせて調整できます。
このばかげた関数を考えて、2つのベクトルの要素をペアごとに追加します
sillyplus <- function(x, y) {
out <- numeric(length = length(x))
for(i in seq_along(x)) {
out[i] <- x[i] + y[i]
}
out
}
それは正しい結果をもたらします
R> sillyplus(1:10, 1:10)
[1] 2 4 6 8 10 12 14 16 18 20
また、ベクトル全体を一度に操作できるという意味でベクトル化されていますが、非常に非効率的であるため、上記の意味ではベクトル化されていません。+
はRのCレベルでベクトル化されるため、R1:10 + 1:10
の明示的なループではなく、実際に必要なのはです。
ベクトル化された関数を作成する通常の方法は、すでにベクトル化されている既存のR関数を使用することです。ゼロから始めたいと思っていて、関数でやりたいことがRのベクトル化された関数として存在しない場合(奇妙ですが可能です)、手を汚して関数の内臓を書く必要がありますCを作成し、Rで小さなラッパーを準備して、処理するデータのベクトルを使用して作成したC関数を呼び出します。Vectorize()
ベクトル化されていないR関数のベクトル化を偽造するような関数を使用する方法があります。
ここでのオプションはCだけではありません。C++と同様にFORTRANも可能です。また、DirkEddelbuettelとRomainFrancoisのおかげで、rcppパッケージを使用すると後者の方がはるかに簡単になります。
ベクトル化された関数は、引数の1つと同じ長さのベクトルを返します。一般に、このような関数は、「+」などの組み込み関数、cos
またはexp
ベクトル化された関数の組み合わせを使用して取得できます。
vecexpcos <- function(x) exp(cos(x))
vecexpcos( (1:10)*pi )
> vecexpcos( (1:10)*pi )
# [1] 0.3678794 2.7182818 0.3678794 2.7182818 0.3678794 2.7182818 0.3678794 2.7182818 0.3678794 2.7182818
のようなベクトル化されていない関数を使用する必要がある場合は、またはsum
を呼び出して、目的の動作を取得する必要があります。mapply
Vectorize
パーティーに遅れましたが、質問はまだ非常に関連性が高く、最近いくつかの新しい方法が人気を博していると思います。したがって、メソッドを使用してRの関数をベクトル化するもう1つの方法がありtidyverse
ます。
まず、いくつかのデータを定義します。
x <- c(1,2,3)
y <- c(1,2,4)
ここで、これら2つのベクトルに対して要素ごとf(x,y)
に計算を実行したいとします。
たとえば、xとyの各(ペアの)要素の合計を計算すると、2,4,7が得られます。
map2_dbl
from purrr
(tidyverseエコシステムのパッケージ)を使用してみましょう:
x <- c(1,2,3)
y <- c(1,2,4)
library(tidyverse)
map2_dbl(.x = x,
.y = y,
.f = sum)
#> [1] 2 4 7
見てわかるように、結果は、xとyの要素の各ペアについて合計が計算されたという意味でベクトル化されています。
要約するmap()
と、とそのバリアントを使用することは、少なくともいくつかの状況では、関数をベクトル化するための便利な方法です。