行列またはデータ フレームのすべての行に関数を適用する
質問
n 行 2 列の行列と、引数の 1 つとして 2 ベクトルを取る関数があるとします。この関数を行列の各行に適用して、n ベクトルを取得したいと思います。Rでこれを行うにはどうすればよいでしょうか?
たとえば、次の 3 つの点における 2D 標準正規分布の密度を計算したいとします。
bivariate.density(x = c(0, 0), mu = c(0, 0), sigma = c(1, 1), rho = 0){
exp(-1/(2*(1-rho^2))*(x[1]^2/sigma[1]^2+x[2]^2/sigma[2]^2-2*rho*x[1]*x[2]/(sigma[1]*sigma[2]))) * 1/(2*pi*sigma[1]*sigma[2]*sqrt(1-rho^2))
}
out <- rbind(c(1, 2), c(3, 4), c(5, 6))
の各行に関数を適用する方法 out
?
指定した方法でポイント以外の他の引数の値を関数に渡すにはどうすればよいですか?
解決
あなたは単に、 apply()
関数:
R> M <- matrix(1:6, nrow=3, byrow=TRUE)
R> M
[,1] [,2]
[1,] 1 2
[2,] 3 4
[3,] 5 6
R> apply(M, 1, function(x) 2*x[1]+x[2])
[1] 4 10 16
R>
これは行列を受け取り、各行に (愚かな) 関数を適用します。追加の引数を 4 番目、5 番目、... として関数に渡します。に対する引数 apply()
.
他のヒント
合計や平均などの一般的な関数を適用したい場合は、次を使用する必要があります。 rowSums
または rowMeans
彼らはより速いので apply(data, 1, sum)
アプローチ。それ以外の場合は、そのままにしておいてください apply(data, 1, fun)
. 。FUN 引数の後に追加の引数を渡すことができます (Dirk がすでに提案しているように)。
set.seed(1)
m <- matrix(round(runif(20, 1, 5)), ncol=4)
diag(m) <- NA
m
[,1] [,2] [,3] [,4]
[1,] NA 5 2 3
[2,] 2 NA 2 4
[3,] 3 4 NA 5
[4,] 5 4 3 NA
[5,] 2 1 4 4
次に、次のようなことができます。
apply(m, 1, quantile, probs=c(.25,.5, .75), na.rm=TRUE)
[,1] [,2] [,3] [,4] [,5]
25% 2.5 2 3.5 3.5 1.75
50% 3.0 2 4.0 4.0 3.00
75% 4.0 3 4.5 4.5 4.00
以下は、行列の各行に関数を適用する短い例です。(ここでは、適用される関数はすべての行を 1 に正規化します。)
注記: の結果 apply()
そうでなければならなかった 転置された 使用して t()
入力行列と同じレイアウトを取得するには A
.
A <- matrix(c(
0, 1, 1, 2,
0, 0, 1, 3,
0, 0, 1, 3
), nrow = 3, byrow = TRUE)
t(apply(A, 1, function(x) x / sum(x) ))
結果:
[,1] [,2] [,3] [,4]
[1,] 0 0.25 0.25 0.50
[2,] 0 0.00 0.25 0.75
[3,] 0 0.00 0.25 0.75
最初のステップは関数オブジェクトを作成し、それを適用することです。同じ行数を持つ行列オブジェクトが必要な場合は、それを事前に定義し、図に示すように object[] 形式を使用できます (そうでない場合、戻り値はベクトルに単純化されます)。
bvnormdens <- function(x=c(0,0),mu=c(0,0), sigma=c(1,1), rho=0){
exp(-1/(2*(1-rho^2))*(x[1]^2/sigma[1]^2+
x[2]^2/sigma[2]^2-
2*rho*x[1]*x[2]/(sigma[1]*sigma[2]))) *
1/(2*pi*sigma[1]*sigma[2]*sqrt(1-rho^2))
}
out=rbind(c(1,2),c(3,4),c(5,6));
bvout<-matrix(NA, ncol=1, nrow=3)
bvout[] <-apply(out, 1, bvnormdens)
bvout
[,1]
[1,] 1.306423e-02
[2,] 5.931153e-07
[3,] 9.033134e-15
デフォルトのパラメータ以外を使用したい場合は、呼び出しで関数の後に名前付き引数を含める必要があります。
bvout[] <-apply(out, 1, FUN=bvnormdens, mu=c(-1,1), rho=0.6)
apply() は高次元の配列でも使用でき、MARGIN 引数には単一の整数だけでなくベクトルも使用できます。
apply はうまく機能しますが、かなり遅いです。sapply と vapply を使用すると便利です。DplyrのRowWiseは有用である可能性があります。データフレームのRow Wise製品を実行する方法の例を見てみましょう。
a = data.frame(t(iris[1:10,1:3]))
vapply(a, prod, 0)
sapply(a, prod)
vapply/sapply/apply を使用する前に変数に代入すると、時間が大幅に短縮されるため、推奨されます。マイクロベンチマークの結果を見てみましょう
a = data.frame(t(iris[1:10,1:3]))
b = iris[1:10,1:3]
microbenchmark::microbenchmark(
apply(b, 1 , prod),
vapply(a, prod, 0),
sapply(a, prod) ,
apply(iris[1:10,1:3], 1 , prod),
vapply(data.frame(t(iris[1:10,1:3])), prod, 0),
sapply(data.frame(t(iris[1:10,1:3])), prod) ,
b %>% rowwise() %>%
summarise(p = prod(Sepal.Length,Sepal.Width,Petal.Length))
)
t() がどのように使用されているかを注意深く見てください。
単一の値ではなくデータセットの変化する部分を使用したい場合の別のアプローチは、 rollapply(data, width, FUN, ...)
. 。幅のベクトルを使用すると、データセットのさまざまなウィンドウに関数を適用できます。私はこれを使用して適応フィルタリング ルーチンを構築しましたが、あまり効率的ではありません。