マトリックスの各要素に関数を適用するRの組み込み関数があるかどうか疑問に思っています(もちろん、関数はマトリックスインデックスに基づいて計算する必要があります)。同等のものは次のようになります。
matrix_apply <- function(m, f) {
m2 <- m
for (r in seq(nrow(m2)))
for (c in seq(ncol(m2)))
m2[[r, c]] <- f(r, c)
return(m2)
}
そのような組み込み関数がない場合、マトリックスインデックスをパラメーターとして持つ任意の関数を計算することで取得した値を含むようにマトリックスを初期化する最良の方法は何ですか?
outer
が欲しいと思う:
> mat <- matrix(NA, nrow=5, ncol=3)
> outer(1:nrow(mat), 1:ncol(mat) , FUN="*")
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 2 4 6
[3,] 3 6 9
[4,] 4 8 12
[5,] 5 10 15
> outer(1:nrow(mat), 1:ncol(mat) , FUN=function(r,c) log(r+c) )
[,1] [,2] [,3]
[1,] 0.6931472 1.098612 1.386294
[2,] 1.0986123 1.386294 1.609438
[3,] 1.3862944 1.609438 1.791759
[4,] 1.6094379 1.791759 1.945910
[5,] 1.7917595 1.945910 2.079442
これにより、ニースのコンパクトな出力が生成されます。しかし、mapply
は他の状況で役立つ可能性があります。 mapply
を、このページの他のユーザーがVectorize
を使用しているのと同じ操作を行う別の方法と考えると便利です。 mapply
は、Vectorize
が「プリミティブ」関数を使用できないため、より一般的です。
data.frame(mrow=c(row(mat)), # straightens out the arguments
mcol=c(col(mat)),
m.f.res= mapply(function(r,c) log(r+c), row(mat), col(mat) ) )
# mrow mcol m.f.res
1 1 1 0.6931472
2 2 1 1.0986123
3 3 1 1.3862944
4 4 1 1.6094379
5 5 1 1.7917595
6 1 2 1.0986123
7 2 2 1.3862944
8 3 2 1.6094379
9 4 2 1.7917595
10 5 2 1.9459101
11 1 3 1.3862944
12 2 3 1.6094379
13 3 3 1.7917595
14 4 3 1.9459101
15 5 3 2.0794415
おそらく、関数にrow()およびcol()関数が返すものを提供するつもりはなかったでしょう。これにより、15(やや冗長な)3 x 5行列の配列が生成されます。
> outer(row(mat), col(mat) , FUN=function(r,c) log(r+c) )
最も単純なアプローチisは、マトリックスの要素に直接適用できるf()
を使用するだけです。たとえば、@ adamleerich's Answerのm
行列を使用します
_m <- matrix(c(1,2,3,4,5,6,7,8), nrow = 2)
_
apply()
の例の場合、as.character()
を使用する理由はありません。代わりに、m
の要素をベクトルであるかのように操作し(実際は1)、in-placeを置き換えることができます。
_> m[] <- as.character(m)
> m
[,1] [,2] [,3] [,4]
[1,] "1" "3" "5" "7"
[2,] "2" "4" "6" "8"
_
このブロックの最初の部分がここのキーです。 _m[]
_は、m
の要素を、m
を文字のベクトルで上書きするのではなく、as.character()
からの出力に強制的に置き換えます。
つまり、isは、行列の各要素に関数を適用する一般的な解決策です。
行と列のインデックスで動作するf()
を本当に使用する必要がある場合は、f()
とrow()
を使用してcol()
を記述します。 :
_> m <- matrix(c(1,2,3,4,5,6,7,8), nrow = 2)
> row(m)
[,1] [,2] [,3] [,4]
[1,] 1 1 1 1
[2,] 2 2 2 2
> col(m)
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 1 2 3 4
> row(m) * col(m) ## `*`(row(m), col(m)) to see this is just f()
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 2 4 6 8
_
または、他の人が示したようにouter()
を使用するもの。 f()
がベクトル化されていない場合、可能な限り自分の戦略を再考しますi)おそらく真にベクトル化されたバージョンを記述する方法であり、ii)ベクトル化されていない関数非常にうまくスケーリングするつもりはありません。
各要素にどのような関数を適用するのか教えてくれませんでしたが、他の回答の例が機能する唯一の理由は、関数が既にベクトル化されているためだと思います。本当に各要素に関数を適用したい場合、outer
は、関数がまだ提供していない特別なものを提供しません。答えがouter
にマトリックスを渡さなかったことに気付くでしょう。
@Chaseのコメントをフォローしてapply
を使用してみてください。
たとえば、私は行列を持っています
m <- matrix(c(1,2,3,4,5,6,7,8), nrow = 2)
(例として)要素ごとに文字マトリックスに変換したい場合は、これを行うことができます
apply(m, c(1,2), as.character)
もちろん、 as.character
はすでにベクトル化されていますが、私の特別な関数my.special.function
は違います。 1つの引数、要素のみを取ります。 outer
を操作するための簡単な方法はありません。しかし、これは動作します
apply(m, c(1,2), my.special.function)
outer
を考えているかもしれません:
rows <- 1:10
cols <- 1:10
outer(rows,cols,"+")
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 2 3 4 5 6 7 8 9 10 11
[2,] 3 4 5 6 7 8 9 10 11 12
[3,] 4 5 6 7 8 9 10 11 12 13
[4,] 5 6 7 8 9 10 11 12 13 14
[5,] 6 7 8 9 10 11 12 13 14 15
[6,] 7 8 9 10 11 12 13 14 15 16
[7,] 8 9 10 11 12 13 14 15 16 17
[8,] 9 10 11 12 13 14 15 16 17 18
[9,] 10 11 12 13 14 15 16 17 18 19
[10,] 11 12 13 14 15 16 17 18 19 20
これは明らかにかなり単純なサンプル関数ですが、独自のカスタム関数を提供することもできます。見る ?outer
。
編集
以下のコメントに反して、outer
を非ベクトル化関数で使用することもできます。
m <- matrix(1:16,4,4)
#A non-vectorized function
myFun <- function(x,y,M){
M[x,y] + (x*y)
}
#Oh noes!
outer(1:4,1:4,myFun,m)
Error in dim(robj) <- c(dX, dY) :
dims [product 16] do not match the length of object [256]
#Oh ho! Vectorize()!
myVecFun <- Vectorize(myFun,vectorize.args = c('x','y'))
#Voila!
outer(1:4,1:4,myVecFun,m)
[,1] [,2] [,3] [,4]
[1,] 2 7 12 17
[2,] 4 10 16 22
[3,] 6 13 20 27
[4,] 8 16 24 32
これはあなたの質問に正確に答えるわけではありませんが、似たような質問を見つけようとしているときに見つけたので、何かお見せします。
1つの部分だけが必要な行列の各要素に適用する関数があるとします。
mydouble <- function(x) {
return(x+x)
}
そして、行列Xがあるとします。
> x=c(1,-2,-3,4)
> X=matrix(x,2,2)
> X
[,1] [,2]
[1,] 1 -3
[2,] -2 4
あなたはこれをします:
res=mydouble(X)
次に、各値の要素ごとの倍精度を実行します。
ただし、以下のような関数でロジックを実行すると、パラメーター化されておらず、期待どおりに動作しないという警告が表示されます。
myabs <- function(x) {
if (x<0) {
return (-x)
} else {
return (x)
}
}
> myabs(X)
[,1] [,2]
[1,] 1 -3
[2,] -2 4
Warning message:
In if (x < 0) { :
the condition has length > 1 and only the first element will be used
ただし、apply()関数を使用する場合は使用できます。
例えば:
> apply(X,c(1,2),myabs)
[,1] [,2]
[1,] 1 3
[2,] 2 4
素晴らしいですねさて、2つ以上のパラメーターを持つ関数がある場合、それは故障します。たとえば、これがあるとします:
mymath <- function(x,y) {
if(x<0) {
return(-x*y)
} else {
return(x*y)
}
}
この場合、apply()関数を使用します。ただし、マトリックスは失われますが、結果は正しく計算されます。あなたがそんなに傾いているなら、彼らは改革することができます。
> mapply(mymath,X,X)
[1] 1 -4 -9 16
> mapply(mymath,X,2)
[1] 2 4 6 8
> matrix(mapply(mymath,X,2),c(2,2))
[,1] [,2]
[1,] 2 6
[2,] 4 8