Rによるデータ分析

RによるLiNGAM

LiNGAM のRによる実施例です。

モデルの係数を調べる分析

モデル式の係数を調べる方法です。

ここでは、以下の式で作ったデータを使っています。 eのところは、一様分布の乱数を使っています。
LiNGAM

library(pcalg) #ライブラリの読み込み
setwd("C:/Rtest") # 作業用ディレクトリを変更
Data <- read.csv("Data.csv", header=T) # データを読み込み
Str <- lingam(Data)$Bpruned # LiNGAM
rownames(Str) <- colnames(Data) # 行名を追記
colnames(Str) <- colnames(Data) # 列名を追記
Str
LiNGAM

データを作った時の係数とほぼ同じ値が求まりました。

変数の影響の大きさの分析

重回帰分析 で、各変数の影響の大きさを調べたい時は、単純に回帰式の各変数の係数を比べることは間違いで、偏回帰係数を比べます。 偏回帰係数は、各変数を 標準化 してから、重回帰分析をして求まる係数になります。

因果関係の分析にLiNGAMを使う場合も、単純にLiNGAMの出力を使おうとすると、同じ間違いが起きます。 ここでも標準化をしてから、LiNGAMを実行することにします。

そして、この係数を影響の大きさを表す数値として、ネットワーク構造の太さに使います。

LiNGAM+ネットワークグラフ

library(pcalg) #ライブラリの読み込み
library(igraph) #ライブラリの読み込み
setwd("C:/Rtest") # 作業用ディレクトリを変更
Data <- read.csv("Data.csv", header=T) # データを読み込み
for (i in 1:ncol(Data)) {
Data[,i] <- (Data[,i] - mean(Data[,i]))/sd(Data[,i]) #データを標準化
}
Str <- lingam(Data)$Bpruned # LiNGAM
rownames(Str) <- colnames(Data) # 行名を追記
colnames(Str) <- colnames(Data) # 列名を追記
GM2 <- t(abs(Str)) # 絶対値にして転置する
GM3 <- GM2*5/max(GM2) # 値を適度な大きさにする
GM4 <- graph.adjacency(GM3,weighted=T, mode = "directed") # グラフ用のデータを作成
plot(GM4, edge.width=E(GM4)$weight) # グラフを作成

LiNGAM

矢印の元側の変数に誤差が加わって、矢印の先の変数になっていることを表しているグラフができます。

pcalgを使わない場合

参考文献のところにありますが、pcalgというライブラリを使うには、別のライブラリが先にインストールされている必要があります。 それが原因のようで、環境によっては、上記のコードはエラーになります。

そこで、pcalgを使わずにLiNGAMを実行するためのコードが下記になります。 筆者の自作のコードです。 R-EDA1 でも、このコードを使っています。

参考文献にあったハンガリアン法による行列の並び替えというのがわからなかったため、 対角成分の和が最小になる行列は、ランダムに行を並び変えたものを10000通り作って、その組合せの最小値を作るようにしています。 7の階乗が5040なので、 変数が8個以上になると、だいたい合っているものの、本当に最小の行列ではない可能性があります。

library(igraph) #ライブラリの読み込み
library(fastICA)
setwd("C:/Rtest")
# 作業用ディレクトリを変更
Data <- read.csv("Data.csv", header=T) # データを読み込み
n <- ncol(Data)
for (i in 1:n) {
Data[,i] <- (Data[,i] - mean(Data[,i]))/sd(Data[,i])
#データを標準化
}
fICA <- fastICA(Data, n)
#独立成分分析
K <- fICA$K
W <- fICA$W
tKW <- t(K %*% W)
MintKW <- tKW
MinSum <- sum(diag(1/abs(tKW)))
for (i in 1:10000) {
tKW2 <- tKW[order(sample(tKW,n)),]
SumdiagRabstKW <- sum(diag(1/abs(tKW2)))
if(MinSum > SumdiagRabstKW){
MinSum <- SumdiagRabstKW
MintKW <- tKW2
}
}
MintKW2 <- MintKW
for (i in 1:n) {
MintKW2[i,] <- MintKW2[i,]/MintKW2[i,i]
#対角成分が1になるように各行を割る
}
Str <- MintKW2
diag(Str) <- 0
# 対角成分を0にする
rownames(Str) <- colnames(Data) # 行名を追記
colnames(Str) <- colnames(Data) # 列名を追記
GM2 <- t(abs(Str)) # 絶対値にして転置する
GM3 <- GM2*5/max(GM2) # 値を適度な大きさにする
GM3[GM3<3] <- 0 # 3未満の場合は0にする(非表示にするため)
GM4 <- graph.adjacency(GM3,weighted=T, mode = "directed") # グラフ用のデータを作成
plot(GM4, edge.width=E(GM4)$weight) # グラフを作成

LiNGAM

pcalgを使う方法と、使わない方法の違い

LiNGAMが有効な分布 のページに2つの方法の比較があります。



参考文献

つくりながら学ぶ! Pythonによる因果分析 因果推論・因果探索の実践入門」 小川雄太郎 著 マイナビ出版 2020
LiNGAMの実装は、この本を参考にさせていただきました。


「統計的因果探索」の一部を動かしてみた
山川信之氏のブログです。 pcalgをインストールする前に、別のライブラリのインストールが必要なことが書かれています。 また、LiNGAMの簡単な実施例もあります。
https://techblog.nhn-techorus.com/archives/13805 の3つを紹介しています



Tweet データサイエンス教室