Rで、サンプルデータ作製からヒートマップ表示とクラスタリング表示 (Afiinity propagation含む) まで
Rで、サンプルデータ作製して、ヒートマップ表示と、k-medoids (pam) と Afiinity propagation含むいくつかのクラスタリング表示を作る機会がありました。せっかくなので、記載します。今回ようなデータの処理と目的では、k-means のような方法が適していました。DBSCAN などは他をご参考をいただけますようお願いします。ひたすら駆け足で、忘備録程度の内容です。
対象は、50人分、10種類の観測値のサンプルデータです。
目的は、ヒトごと、10種類の観測値ごとのそれぞれのクラスターを見付けることです。
平均値とSD の異なる正規分布で、50人分、10種類の観測値のサンプルデータを作ります。
A1=cbind( matrix(rnorm(50, -1, 1),nc=5), matrix(rnorm(50,0,1),nc=5) ) A2=cbind( matrix(rnorm(30,-0.5,1),nc=3), matrix(rnorm(50,0,2),nc=5), matrix(rnorm(20,-3,1),nc=2) ) A3=cbind( matrix(rnorm(20,0.5,2),nc=2), matrix(rnorm(30,-2,1),nc=3), matrix(rnorm(20,0.2,0.2),nc=2), matrix(rnorm(30,1,1),nc=3) ) A4=cbind( matrix(rnorm(10,2,0.8),nc=1), matrix(rnorm(40,1,0.7),nc=4), matrix(rnorm(10,-0.5,0.1),nc=1), matrix(rnorm(40,0,1),nc=4) ) A5=cbind( matrix(rnorm(10,-0.1,0.2),nc=1), matrix(rnorm(40,-2,1),nc=4), matrix(rnorm(10,2,1),nc=1), matrix(rnorm(40,0.4,1),nc=4) ) M_Example = rbind(A1,A2,A3,A4,A5)
データを50人の個人をランダムに並べ変えます。 クラスタライングの為には、正規化しておく方が良いことが多いです。 10種の観測値ごとに正規化し、data に納めます。 ここまでを1行で、次からは、行列に名前を付けます。
data = scale((M_Example[order(runif(50)),])) col_data =c() for (i in 1:10){ col_data <- c(col_data, paste("data", as.character(i), sep="")) } row_data =c( ) for (i in 1:50){ row_data <- c(row_data, paste("person", as.character(i), sep="")) } colnames(data)<-col_data rownames(data)<-row_data
できあがったサンプルデータを、順番を変えずに、ヒートマップで示します。ヒートマップは、一貫して heatmap.2 を使いました。
library(gplots) # 順番を変えずに描いてみましょう。 Colour <- colorRampPalette( c("blue3","white","red3") ) heatmap.2(data, dendrogram = "none", Colv=FALSE, Rowv=FALSE, scale="none", density.info="none", col=Colour(64), main="Heatmap (no cluster)", margin=c(8,10), trace = "none" )
平均値を白、低いものを青、高いものを赤で示しています。以下ではスケールバーは、同じなので、省略します。
つづいて、デフォルトであるところの最長距離法 (furthest neighbor method) または 完全連結法 (complete linkage method) と呼ばれる方法によるもの。
Colour <- colorRampPalette( c("blue3","white","red3") ) heatmap.2(data, dendrogram = "both", Colv=T, Rowv=T, scale="none", density.info="none", col=Colour(256), main="Heatmap (complet)", trace = "none" )
つついて、Ward 法を書きます。Dist と hclust でクラスタリングを別にする方が、中身が見えるので、やりやすいでしょう。
library(amap) # 距離関数で類似度のアルゴリズムとしてCosine係数を使用する # (method="pearson")は(1 - cosine)と同義である d1<-Dist(data, method="pearson") d2<-Dist(t(data), method="pearson") # クラスタリング c1<-hclust(d1, method="ward.D") c2<-hclust(d2, method="ward.D") Colour <- colorRampPalette( c("blue3","white","red3") ) heatmap.2(data, dendrogram = "both", Colv=as.dendrogram(c2), Rowv=as.dendrogram(c1), scale="none", key = T, col=Colour, density.info="none", main="Heatmap (Ward algorythm)", trace = "none" )
k-medoids です。パッケージユーザーの水準なら、k-medoids は k-means の改良版と考えて問題が生じることは少いのではないでしょうか。k-means は、走らせる度に、クラスターが変化しますが、k-medoids は変化しません。これだけでも、パッケージユーザーには利点があると考えます。今回は独断と偏見で、両方向ともクラスタラリング数は、8 としています。樹形図は出せないので、色分けでクラスタラリングを表現しています。
# クラスタリング library(cluster) # mat_k4_th_norm <- t(scale(t(mat_k4_th))) cluster_n <- 8 cluster_nc <- 6 result_pam <- pam(data, cluster_n) pam_clust <- result_pam$cluster result_pam_c <- pam(t(data), cluster_nc) pam_clust_c <- result_pam_c$cluster df_heat <- data[order(pam_clust, data[,1]),order(pam_clust_c)] # Heatmap の出力; library(gplots) library('RColorBrewer') # 右横にクラスター帯を作るための色を決めます。 col_col=c() i=1 while ( i < cluster_n ){ col_col=c(col_col, rep(brewer.pal(8,"Accent")[1],t(table(pam_clust))[i]), rep(brewer.pal(8,"Accent")[2],t(table(pam_clust))[i+1]), rep(brewer.pal(8,"Accent")[3],t(table(pam_clust))[i+2]), rep(brewer.pal(8,"Accent")[4],t(table(pam_clust))[i+3]), rep(brewer.pal(8,"Accent")[5],t(table(pam_clust))[i+4]), rep(brewer.pal(8,"Accent")[6],t(table(pam_clust))[i+5]), rep(brewer.pal(8,"Accent")[7],t(table(pam_clust))[i+6]), rep(brewer.pal(8,"Accent")[8],t(table(pam_clust))[i+7]) ) i= i + 6 } #上の帯 col_col_c=c() i=1 while ( i < cluster_nc ){ col_col_c=c(col_col_c, rep(brewer.pal(8,"Accent")[1],t(table(pam_clust_c))[i]), rep(brewer.pal(8,"Accent")[2],t(table(pam_clust_c))[i+1]), rep(brewer.pal(8,"Accent")[3],t(table(pam_clust_c))[i+2]), rep(brewer.pal(8,"Accent")[4],t(table(pam_clust_c))[i+3]), rep(brewer.pal(8,"Accent")[5],t(table(pam_clust_c))[i+4]), rep(brewer.pal(8,"Accent")[6],t(table(pam_clust_c))[i+5]) ) i= i + 6 } # ヒートマップ自身の色 Colour <- colorRampPalette( c("blue3","white","red3") ) heatmap.2(as.matrix(df_heat), dendrogram = "none", Rowv = "none", Colv = "none", scale="none", col= Colour(64), main="Heatmap (pam)", trace = "none", RowSideColors= (t(col_col[1:dim(df_heat)[1]])), ColSideColors= (t(col_col_c[1:dim(df_heat)[2]])) )
最後に、affinity propagation です。個人的には、affinity propagation が好きです。帯でクラスタリングを表現しています。この帯を描くところは、一般化が不十分のあコードです。クラスタリングの数によって、書き変えないと走らないことがあるので、注意して下さい。"q =" のオプション (0-1) で、クラスタリングの数をある程度コントロールできます。たぶん、樹形図の高さに相当していると考えます。
library(apcluster) result_apc <- apcluster(negDistMat(r=2), data) label_apc <- labels(result_apc,type="enum") cluster_n <- length(table(label_apc)) result_apc_c <- apcluster(negDistMat(r=2), t(data), q=0.1) label_apc_c <- labels(result_apc_c,type="enum") cluster_nc <- length(table(label_apc_c)) df_heat <- data[order(label_apc, data[,1]),order(label_apc_c)] # Heatmap の出力; library(gplots) library('RColorBrewer') # 右横にクラスター帯を作るための色を決めます。 col_col=c() i=1 while ( i < cluster_n ){ col_col=c(col_col, rep(brewer.pal(8,"Accent")[1],t(table(label_apc))[i]), rep(brewer.pal(8,"Accent")[2],t(table(label_apc))[i+1]), rep(brewer.pal(8,"Accent")[3],t(table(label_apc))[i+2]), rep(brewer.pal(8,"Accent")[4],t(table(label_apc))[i+3]), rep(brewer.pal(8,"Accent")[5],t(table(label_apc))[i+4]), rep(brewer.pal(8,"Accent")[6],t(table(label_apc))[i+5]), rep(brewer.pal(8,"Accent")[7],t(table(label_apc))[i+6]), rep(brewer.pal(8,"Accent")[8],t(table(label_apc))[i+7]) ) i= i + 6 } col_col_c=c() i=1 while ( i < cluster_nc ){ col_col_c=c(col_col_c, rep(brewer.pal(8,"Accent")[1],t(table(label_apc_c))[i]), rep(brewer.pal(8,"Accent")[2],t(table(label_apc_c))[i+1]) ) i= i + 3 } # ヒートマップ自身の色 Colour <- colorRampPalette( c("blue3","white","red3") ) heatmap.2(as.matrix(df_heat), dendrogram = "none", Rowv = "none", Colv = "none", scale="none", col= Colour(64), main="Heatmap (Affinity propagation)", trace = "none", RowSideColors= (t(col_col[1:dim(df_heat)[1]])), ColSideColors= (t(col_col_c[1:dim(df_heat)[2]])) )
クラスタリングの内訳は、heatmap() の中に結果を入れると描いてくれます。
library(viridis) heatmap(result_apc, col=magma(64)) heatmap(result_apc_c, col=magma(64))
スケールは、省略で恐縮ですが、viridis パッケージの magma を使っています。明確な平均を0としていないような非正規化データの場合は、magma などの色の方が、差が見えます。
以上、ひたすら駆け足ですが、おわりです。