行列またはデータフレームのすべての行に関数を適用する


129

私が2行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

指定する方法で関数へのポイント以外の引数に値を渡す方法は?

回答:


180

あなたは単に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()


ありがとう!行列の行が関数の最初の引数でない場合はどうなりますか?行列の各行が割り当てられている関数のどの引数を指定するのですか?
Tim

ヘルプをお読みくださいapply()-行ごとにスイープし(2番目の引数が1の場合はそれ以外、列ごと)、現在の行(またはcol)は常に最初の引数です。それが物事を定義する方法です。
Dirk Eddelbuettel、2010年

@Tim:内部R関数を使用し、行が最初の引数でない場合は、Dirkが行ったようにして、行最初の引数である独自のカスタム関数を作成します。
Joris Meys、2010年

3
plyrパッケージは、これらの幅広い種類の関数を提供します。また、並列処理など、より多くの機能を提供します。
Paul Hiemstra、2011年

6
@ cryptic0この答えは遅いですが、グーグルの場合、適用の2番目の引数はMARGIN引数です。ここでは、行に関数を適用することを意味します(の最初の次元dim(M))。2の場合、関数を列に適用します。
デ・ノボ

17

場合は、あなたがそのような和として共通の機能を適用するかを意味したい、あなたが使うべきrowSumsrowMeans、彼らはより速くしているので、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

15

以下は、行列の各行に関数を適用する短い例です。(ここで、適用された関数はすべての行を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

6

最初のステップは、関数オブジェクトを作成し、それを適用することです。同じ行数の行列オブジェクトが必要な場合は、それを事前定義して、図のように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引数は、単一の整数だけでなくベクトルでもかまいません。


4

Applyはうまく機能しますが、かなり遅いです。sapplyとvapplyを使用すると便利です。dplyrの行ごとの情報も役立ちます。データフレームの行ごとの結果をどのように生成するかの例を見てみましょう。

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()の使用方法を注意深く確認してください


とを使用b <- t(iris[1:10, 1:3])した場合は、適用ファミリーを比較した方が公平かもしれませんapply(b, 2 prod)
DaSpeeg 2018

2

単一の値の代わりにデータセットの可変部分を使用したい場合の別のアプローチは、を使用することrollapply(data, width, FUN, ...)です。幅のベクトルを使用すると、データセットのさまざまなウィンドウに関数を適用できます。これを使用して、適応フィルタリングルーチンを構築しましたが、あまり効率的ではありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.