- 昨日の記事では、曲面の変形・共形変換・スピン変換をRでなぞってみているが、その中で、疎行列を扱っている
- 三角化メッシュの辺の両端頂点IDを番地とする行列を疎行列で作り、その要素を辺が含まれる三角形の数だけ操作をしたいのだが
- 何回の操作になるのかが不定なので、少し厄介
- それをループしないで行うべく、rle()関数などを使ってみる
- まず、疎行列・疎ベクトル
- 空の疎ベクトルを作ってみる。第1要素に0を入れて、長さ10の疎ベクトルを作る。要素を何も入れないと作れないみたいなので
library(Matrix)
v1 <- sparseVector(c(0),i=c(1),length=10)
v1
> v1
sparse vector (nnz/length = 0/10) of class "dsparseVector"
[1] . . . . . . . . . .
m1 <- Matrix(v1,2,5)
m1
> m1
2 x 5 sparse Matrix of class "dgTMatrix"
[1,] . . . . .
[2,] . . . . .
v2 <- sparseVector(c(1,2,3),i=c(3,2,5),length=10)
v2
> v2
sparse vector (nnz/length = 3/10) of class "dsparseVector"
[1] . 2 1 . 3 . . . . .
v3 <- sparseVector(c(1,2,3),i=c(1,3,1),length=10)
- 以下のようなエラーが出る。このエラーは「昇順」になっていない、からではなくて、重複番地があるから。
> v3 <- sparseVector(c(1,2,3),i=c(1,3,1),length=10)
以下にエラー validObject(.Object) :
invalid class “dsparseVector” object: 'i' must be sorted strictly increasingly
- さて、番地ごとに何回かずつ、アクセスして、加算したいとしよう
- banchiにvalueを加えたい。以下の例だと、第1番地に+1,+4+8、第2番地に+2+5+10とか
value <- 1:10
banchi <- c(1,2,3,1,2,4,50,1,3,2)
- rle()関数
- rle()関数は、連続値がいくつあるかを教えてくれる関数
v1 <- c(1,1,1,2,2,3,4,4,4)
rle(v1)
v1.sh <- sample(v1)
v1.sh
rle(v1.sh)
- 以下に見られるように、「ソートすれば、『出現回数』」がわかり、そうでなければ、「続き回数」がわかる
> v1 <- c(1,1,1,2,2,3,4,4,4)
> rle(v1)
Run Length Encoding
lengths: int [1:4] 3 2 1 3
values : num [1:4] 1 2 3 4
> v1.sh <- sample(v1)
> v1.sh
[1] 4 1 3 4 2 2 1 1 4
> rle(v1.sh)
Run Length Encoding
lengths: int [1:7] 1 1 1 1 2 2 1
values : num [1:7] 4 1 3 4 2 1 4
- 今、やりたいのは、複数回出る疎ベクトル番地には1回のアクセスをすることなので、番地をソートしてからやるのが大事
- 番地のソート順を出して、番地と値とをその順序にする
- 番地をソートしてrle()をかければ、それぞれの番地の出現回数が出る
- 番地数x最大出現回数の行列に値を納めてやって、行ごとに加算すれば、番地ごとの加算数が合算できるから、そのような行列を作りたい
- あくまでも「疎ベクトル」「疎行列」でやりたいので、rle()の出力から、「行列」をベクトル扱いした場合の「番地」を作ってやることにする
my.vector.access <- function(v,a,func=sum,zero=0){
if(is.vector(a)){
v <- matrix(v,ncol=1)
}
ord <- order(a)
rle.out <- rle(a[ord])
num.row <- length(rle.out[[1]])
num.col <- max(rle.out[[1]])
tmp1 <- rep(1:num.row,rle.out[[1]])
tmp2 <- c()
for(i in 1:num.row){
tmp2 <- c(tmp2,1:rle.out[[1]][i])
}
addr <- tmp1 + num.row*(tmp2-1)
ret.v <- matrix(0,num.row,ncol(v))
for(i in 1:ncol(v)){
if(zero==0){
tmp.V <- sparseVector(v[ord,i],i=addr,length=num.row*num.col)
M <- Matrix(tmp.V,num.row,num.col)
}else{
M <- matrix(zero,num.row,num.col)
M[addr] <- v[ord,i]
}
ret.v[,i] <- apply(M,1,func)
}
return(list(A = rle.out[[2]],V = ret.v))
}
v <- 1:10
a <- banchi <- c(1,2,3,1,2,4,50,1,3,2)
oo <- my.vector.access(v,a)
oo2 <- my.vector.access(v,a,func=prod,zero=1)