Rによるデータ分析

Rによる高次元を2次元に圧縮して可視化

高次元を2次元に圧縮して可視化 のRによる実施例です。

データの前処理

MDS、t-SNE、UMAP、SOM、LLEに使うデータを作ります。

基本的に量的変数を扱いますが、質的変数はダミー変換するコードにしてあるので、 量的と質的変数が混ざっていたり、質的変数だけでもできます。

library(dummies) # ライブラリを読み込み
library(som)
# ライブラリを読み込み
setwd("C:/Rtest")
# 作業用ディレクトリを変更
Data <- read.csv("Data.csv", header=T)
# データを読み込み
Data1 <- Data
# 加工用のデータの作成
Data1$Name <- NULL
# データからNameの列を消す
Data2 <- dummy_cols(Data1,remove_first_dummy = FALSE,remove_selected_columns = TRUE)
# ダミー変換
Data3 <- normalize(Data2[,1:ncol(Data2)],byrow=F)
# 標準化

高次元データを2次元データに凝縮

グラフに使うデータを作ります。

MDS、t-SNE、UMAP、SOM、LLEは、一長一短なので、使い分けると良いようです。

多次元尺度構成法(MDS)の場合

・長所:ハイパーパラメタがないので、一番簡単
・短所:すべて質的変数だと、エラーになる。距離が0になるサンプルの組合せがあるとエラーになる。

library(MASS) # ライブラリを読み込み
Data4 <- dist(Data3)
# サンプル間の距離を計算
sn <- sammon(Data4)
# 多次元尺度構成法
Data5 <- sn$points
# 得られた2次元データの抽出

t-SNEの場合

・長所:想定通りのグループになりやすい。
・短所:パラメタの調整が必須。距離が0になるサンプルの組合せがあるとエラーになる。

perplexityが小さいと、プロットが重なりやすくなります。
perplexityはデフォルトが30になっていて、サンプルが少ない場合はエラーになりやすいです。 この実施例のデータでperplexityを何も設定しないとエラーになります。 ここでは、「perplexity = 3」にしています。

library(Rtsne) # ライブラリを読み込み
ts <- Rtsne(Data3, perplexity = 3)
# t-SNE
Data5 <- ts$Y
# 得られた2次元データの抽出

UMAPの場合

・長所:想定通りのグループになりやすい。距離が0になるサンプルの組合せがあってもエラーにならない。
・短所:どのグループにも属さないようなサンプルでも、どこかのグループに入れてしまう

n_neighborsが小さいと、プロットが重なりやすくなります。
n_neighborsはデフォルトが10のようで、サンプルが少ない場合はエラーになりやすいです。 ここでは、「n_neighbors = 5」にしています。

library(Rcpp) # ライブラリを読み込み
library(umap)
# ライブラリを読み込み
ump_out <- umap(Data3,n_neighbors=5)
# UMAP
Data5 <- ump_out$layout
# 得られた2次元データの抽出

自己組織化マップ(SOM)の場合

・長所:すべて質的変数でも、エラーにならない。
・短所:計算時間が長い。 格子を多くすると、計算時間も長くなる。

library(som) # ライブラリを読み込み
sm <- som(Data3,xdim=10,ydim=10)
# 自己組織化マップ。10×10の格子に振り分ける場合
Data5 <- sm$visual
# SOMによって、得られた2次元データの抽出

LLEの場合

・長所:中程度の局所的な構造がわりとうまく出る。
・短所:kの調整が必要。kが大きいと計算時間が長い。

library(lle) # ライブラリを読み込み
le <- lle(Data1, m = 2, k = 20) # LLEの実施
# LLE。mが削減後の次元数。kがクラスターの数で、わからない時は大きめが良い。
Data5 <- le$Y
# LLEによって、得られた2次元データの抽出

グラフの作成

グラフの作成1:Name(サンプル名)の列が元データにある場合

library(ggplot2) # ライブラリを読み込み#
Data6 <- cbind(Data5 ,Data) 
# 2次元に凝縮されたデータに、元データを合体
ggplot(Data6, aes(x=Data6[,1], y=Data6[,2],label=Name)) + geom_text()
# Nameを使った言葉の散布図
sammon
近くに配置されているほど、類似していることを表します。 縦軸と横軸の数値には定量的な意味はありません。
自己組織化マップでは、同じ格子に分類されると、同じ座標になるため、グラフ上で重なります。 重なりを解くために、少しばらつかせるのなら、下記にすると良いです。 「0.2」としているところを変えると、ばらつき方が変わります。 あまり大きくすると、隣の格子と区別がつかなくなります。
ggplot(Data6, aes(x=Data6[,1], y=Data6[,2],label=Name)) + geom_text(position=position_jitter(0.2))

グラフの作成2:Name(サンプル名)の列が元データにない場合

library(ggplot2) # ライブラリを読み込み#
Data6 <- transform(Data5 ,Data,Index = row.names(Data)) 
# 2次元に凝縮されたデータ、元データ、元データの行番号を合体
ggplot(Data6, aes(x=Data6[,1], y=Data6[,2],label=Index)) + geom_text()
# 行番号を使った言葉の散布図
sammon

グラフの作成3:サンプルが多い場合

library(ggplot2) # ライブラリを読み込み
Data6 <- transform(Data5 ,Data, Index = row.names(Data)) 
# 2次元に凝縮されたデータ、元データ、元データの行番号を合体
Data6$Index <- as.numeric(Data6$Index)
# Indexを数値型に変換
ggplot(Data6, aes(x=Data6[,1], y=Data6[,2])) + geom_point(aes(colour=Index)) + scale_color_viridis_c(option = "D")
# 行番号を使った散布図
sammon
サンプル番号で色分けされています。

グループの色分け

グラフの作成3の例では、データが大きく2つの領域に分かれることがわかりました。 そこで、この2つに色を付けます。

思ったような色分けになるとは限らないのですが、クラスター分析を使うと、グループ分けした変数を簡単に作ることができます。

library(ggplot2) # ライブラリを読み込み
library(mclust)
# ライブラリを読み込み
mc <- Mclust(Data6[,1:2],2)
# 混合分布によるクラスター分析。これは2個のグループ分けの場合
Data7 <- transform(Data6 ,clust = mc$classification) 
# クラスター分析の結果とデータを合体
Data7$clust <- as.factor(Data7$clust)
# clustを文字型に変換
ggplot(Data7, aes(x=Data6[,1], y=Data6[,2])) + geom_point(aes(colour=clust))
# グループごとに色分けした散布図
sammon

グループが分かれる原因の分析

サンプルの類似度の分析では、サンプルがいくつかのグループに分かれることがありますが、何によって分かれたのかがわかりません。

この後の分析としては、 カテゴリの類似度の分析
Data <- read.csv("Data.csv", header=T)
の部分を
Data <- Data7
に変更して、clustの内容と他の変数の関係を調べる方法があります。

2次元以外を出力にする場合

上記で、多次元尺度構成法は、コードの中に距離行列を作る部分があります。 そのため、距離行列の形のデータを最初に持っている場合のやり方は、想像しやすいです。

t-SNE、UMAPも、距離行列による次元圧縮 の方法です。距離行列の形のデータから分析をスタートすることはできます。

また、アウトプットの次元数を2次元以外にすることもできます。 下記の例では、3次元にしています。

多次元尺度構成法(MDS)の場合

library(MASS)
sn <- sammon(DM, k = 3)
Data5 <- sn$points

t-SNEの場合

library(Rtsne)
ts <- Rtsne(DM, perplexity = 3, dims = 3)
Data5 <- ts$Y

t-SNEの場合は、dimを4以上にすると、エラーになります。

UMAPの場合

library(Rcpp)
library(umap)
ump_out <- umap(DM,n_neighbors=5, n_components = 3)
Data5 <- ump_out$layout



Tweet データサイエンス教室