私はRに大きな行列(行列Matrixとして)を持つ。それは疎である(01のみを含む)。 (Mが行列の場合)私は何大きい行列のインデックスを高速化する
がある
j<-list()
for(i in 1:dim(M)[1]){
which(M[i,]==1)->j[[i]]
}
これは、通常は高速ですが、このような大規模なマトリックス(5000に1.7ミル薄暗い)に、それは非常に遅いです。私はちょうどカントは
私はRに大きな行列(行列Matrixとして)を持つ。それは疎である(01のみを含む)。 (Mが行列の場合)私は何大きい行列のインデックスを高速化する
がある
j<-list()
for(i in 1:dim(M)[1]){
which(M[i,]==1)->j[[i]]
}
これは、通常は高速ですが、このような大規模なマトリックス(5000に1.7ミル薄暗い)に、それは非常に遅いです。私はちょうどカントは
編集コメントの後に....すべての行に1をされているこれらのCOLSのインデックスを取得するために何より高速な方法がないことを信じている:
apply(M, 1, function(i) which(i == 1))
# [[1]]
# [1] 1 2 3
#
# [[2]]
# [1] 1 3
#
# [[3]]
# [1] 2 3
#
# [[4]]
# [1] 2 3
この例を試してみてください。
#data
M <- matrix(c(1,1,0,0,1,0,1,1,1,1,1,1), 4)
# [,1] [,2] [,3]
# [1,] 1 1 1
# [2,] 1 0 1
# [3,] 0 1 1
# [4,] 0 1 1
# index of rows with all ones
which(rowSums(M == 1) == ncol(M))
# [1] 1
# index of cols with all ones
which(colSums(M == 1) == nrow(M))
# [1] 3
@のzx8754で例を使用して
M <- matrix(c(1,1,0,0,1,0,1,1,1,1,1,1), 4)
oneMat <- which(M==1, arr.ind=TRUE)
を我々は各行の1に等しい列番号を含むリストを作成することができ、この補助マトリックスから:我々は、1に等しいエントリの行と列のインデックスが含まれている補助行列を定義することができ行列M
が大きく、スパースである場合
oneList <- lapply(1:nrow(M), function(x) oneMat[oneMat[,1] == x, 2])
#[[1]]
#[1] 1 2 3
#
#[[2]]
#[1] 1 3
#
#[[3]]
#[1] 2 3
#
#[[4]]
#[1] 2 3
で、行列oneMat
はM
よりもはるかに小さくする必要があります。その場合、私は、第2ステップで使用されたlapply()
ループが、OPに記載されているfor
ループに関してスピードアップにつながると思います。
いくつかのテストの後、私は残念ながらこの回答が特に遅いことを認めなければなりません。 @ColonelBeauvelによって溶液が勝者です:
j <- list()
set.seed(123)
M <- matrix(rbinom(1e5,1,0.01),ncol=100)
library(microbenchmark)
f_which_and_lappy <- function(x) {oneMat <- which(x==1, arr.ind=TRUE);
lapply(1:nrow(x), function(i) oneMat[oneMat[,1] == i, 2])}
f_only_apply <- function(x) {apply(x, 1, function(i) which(i == 1))}
f_with_data.frame <- function(x) {with(data.frame(which(!!x, arr.ind=T)), split(col, row))}
f_OP <- function(x) {for(i in 1:dim(x)[1]){which(x[i,]==1)->j[[i]]}}
res <- microbenchmark(
f_which_and_lappy(M),
f_only_apply(M),
f_with_data.frame(M),
f_OP(M),times=1000L)
#> res
#Unit: microseconds
# expr min lq mean median uq max neval cld
# f_which_and_lappy(M) 11063.170 11254.032 12090.9506 11351.1830 11570.662 31313.48 1000 d
# f_only_apply(M) 3204.572 3359.410 4117.4971 3456.3960 3610.945 25352.35 1000 b
# f_with_data.frame(M) 739.556 811.906 912.4726 918.0315 946.700 18623.77 1000 a
# f_OP(M) 5642.639 5854.751 6955.9980 5969.3685 6151.209 148847.22 1000 c
私はむしろベクトル化のアプローチを選ぶと、これらの適用/ lapply家族の機能の代わりにsplit
を使用します。
M = matrix(c(1,1,0,0,1,0,1,1,1,1,1,1), 4)
with(data.frame(which(!!M, arr.ind=T)), split(col, row))
#$`1`
#[1] 1 2 3
#$`2`
#[1] 1 3
#$`3`
#[1] 2 3
#$`4`
#[1] 2 3
エラーを回避する可能性があります(!(!M)、arr.ind = T) : 関数 'which'のメソッドを選択する際に引数 'x'を評価する際にエラーが発生しました:asMethod(オブジェクト)のエラー: Cholmodエラー 'ファイルが大きすぎます' ../Core/cholmod_dense.c、行105 エラーここに?まだそれを速くする?それは普通の行列ではありませんが、単純に 'which(!! M、arr.ind = T)'であるのに対し、 '(!(!M)、arr.ind = T)'を投稿した行列 – kutyw
は –
です(!(!M)、arr.ind = T)のエラー(data.frame(which!(M、arr.ind = T))、split(col、row)) - > j : 関数 'which'のメソッドを選択する際に引数 'x'を評価する際にエラーが発生しました:asMethod(オブジェクト)のエラー: ファイルの../Core/cholmod_dense.c、行105のCholmodエラー 'too too large'エラーの場合: – kutyw
あなたができた「マトリックス」を有します'split($ j、$ i)'またはおそらくより効率的な 'split(rep(seq_len(ncol(M))、diff(Mp) i + 1L) ' –