前回の続き。
交互平均法で出てくるのは第一成分だけなので,複数の次元を出すために残差行列を計算してさらに交互平均法をする,という作業を繰り返す必要がある。
実装してみたコードがこちら。このコードの中に交互平均法のアルゴリズムも含まれています。
DualScaling <- function(dat,eps=1e-10,iter.max=1000){ nc <- ncol(dat) nr <- nrow(dat) cname <- colnames(dat) rname <- rownames(dat) mg.col <- colSums(dat) mg.row <- rowSums(dat) mg.t <- sum(mg.row) dm <- min(nc,nr)-1 normed.col <- matrix(ncol=nc,nrow=dm) projected.col <- matrix(ncol=nc,nrow=dm) normed.row <- matrix(ncol=nr,nrow=dm) projected.row <- matrix(ncol=nr,nrow=dm) singular <- c() dat.tmp <- dat # 0-exp for( i in 1:nrow(dat)){ for( j in 1:ncol(dat)){ dat.tmp[i,j] <- dat.tmp[i,j]- (mg.row[i]*mg.col[j]/mg.t) } } # 1-n for(i in 1:dm){ FLG <- FALSE iter <- 0 u <- rnorm(nc) tmp <- 0 while(FLG==FALSE){ #algorithm v <- u %*% t(dat.tmp) v <- v / mg.row av <- (mg.row %*% t(v))/mg.t v <- v - (av * rep(1,nr)) gy <- max(abs(v)) v <- v/gy u <- v %*% dat.tmp u <- u / mg.col av <- (mg.col %*% t(u))/mg.t u <- u - (av *rep(1,nc)) gx <- max(abs(u)) u <- u/gx #conv. check if(abs(tmp-gx)<eps){FLG <- TRUE}else{tmp <- gx} if(iter>iter.max){FLG <- TRUE}else{iter <- iter + 1} } if(u[which.max(abs(u))]<0) u *-1 if(v[which.max(abs(v))]<0) v *-1 eta2 <- gx * gy # Correlation ratio nu.c <- sqrt(sum(mg.col)/mg.col%*%t(u^2)) #multiplied constant nv.c <- sqrt(sum(mg.row)/mg.row%*%t(v^2)) nu <- nu.c %*% u #normed u nv <- nv.c %*% v #normed v pu <- nu * sqrt(eta2) pv <- nv * sqrt(eta2) if(iter>iter.max){ cat("Warning::did not converge.") }else{ singular[i] <- sqrt(eta2) normed.col[i,] <- nu normed.row[i,] <- nv projected.col[i,] <- pu projected.row[i,] <- pv } # residual Matrix dat.tmp <- dat.tmp-(mg.row %*% t(mg.col)/mg.t)*((sqrt(eta2)*t(nv)%*%nu)) } # Correct dims delta_k <- singular^2 / sum(singular^2) * 100 cum_delta_k <- c() cum_delta_k[1] <- delta_k[1] for(i in 2:dm) cum_delta_k[i] <- cum_delta_k[i-1]+delta_k[i] dm.cr <- which.max(cum_delta_k) if(dm.cr<dm){ singular <- singular[-(dm.cr+1:dm)] delta_k <- delta_k[-(dm.cr+1:dm)] cum_delta_k <- cum_delta_k[-(dm.cr+1:dm)] normed.col <- normed.col[-(dm.cr+1:dm),] normed.row <- normed.row[-(dm.cr+1:dm),] projected.row <- projected.row[-(dm.cr+1:dm),] projected.col <- projected.col[-(dm.cr+1:dm),] } # var names colnames(normed.col) <- cname colnames(projected.col) <- cname colnames(normed.row) <- rname colnames(projected.row) <- rname return(list(ndims=dm.cr,sing=singular,eig=singular^2,deltaK=delta_k,cum_dk=cum_delta_k,nc=normed.col,nr=normed.row,pc=projected.col,pr=projected.row)) }
ちなみに,青木先生のサイトにも双対尺度法のコードがあって,こちらはRの固有値分解関数などをつかっているので,より安心安全にお使いいただけます。こっちのコードは交互平均法による習作ですから。
あと,西里先生の研究チームによる双対尺度法のRパッケージ,dualScaleというのもある。
dualScale: Dual Scaling Analysis of Multiple Choice Data
これは多肢選択法にdual scalingをするdsMC,強制分類法をするdsFCという二つの関数しかないけれども,どちらもとても魅力的な手法なので,パッケージで供給されているのはとてもありがたい。今後このパッケージがどんどん発展してくれるといいですね。
dsMCをつかって5件法でデータ取ってる研究全部やり直したいぐらいだよ,ほんとに。