技術資料

金融変数と実体経済変数の因果探索と数法則発見法による波及経路のモデル化と可視化

目次 

目的 

VAR-LiNGAMによる時系列を考慮した因果探索を行い,時系列を考慮した3D因果グラフの作成,また数法則発見法を用いた経済変数のモデル化を行うことで,経済変数間の影響を直感的に理解できるようなシステムの実装を目指す.

使うモジュールのインストール 

使用するモジュール 

モジュールversion用途
pandasデータ収集やデータフレームへの格納などに用いる
LiNGAMVAR-LiNGAMによる分析に用いる
seleniumデータの収集,スクレイピングに用いる
pandas-market-calendars土日祝日を知ることができる.データの時間足調整に用いる
flaskシステムの実装に用いる
json3Dグラフの作成,ページ遷移先にデータを与えるのに用いる
pyvis3Dグラフの作成
webdriver_managerスクレイピングに用いる

モジュールのインストールはコマンドプロンプトでpip install モジュール名

バージョンまで指定する場合はコマンドプロンプトでpip install モジュール名==指定するバージョン でインストールする

データ収集と前処理 

スクレイピングによるデータ収集 

スクレイピングを用いてデータを収集する. スクレイピングには「selenium」を用いる. seleniumのバージョンについては上で示した通りである. seleniumではクリックなどのユーザーアクションを模倣することで深いところにあるデータも収集することができる. スクレイピングをする部分のコードはこれ↓

#ref(): File not found: "scraping.py" at page "蒲田さん卒論"

スクレイピング流れ.PNG.jpg

今回は日本銀行時系列統計データ検索サイトを例に説明する. 日本銀行時系列統計データ検索サイトではクリックアクションを繰り返すことで金利や物価指数など金融時系列データをcsvファイル形式で取得することができる.

ダウンロードしたデータはcsv形式でダウンロードされる.

そのため,ダウンロードされたcsvファイルを一つのフォルダにまとめて保存しする必要がある.

また,ダウンロードした時点のファイル名もダウンロードされた時間,回数によって勝手に決められてしまうものもあるため,ファイル名を変更する必要がある.

そのためにまず,ファイルのダウンロード先を指定する必要がある

dldir_path = Path('保存先のフォルダのパス')
dldir_path.mkdir(exist_ok=True)
download_dir = str(dldir_path.resolve())
options.add_experimental_option('prefs', {'download.default_directory': download_dir})

また,ファイル名を変更するコードとして以下を追加する.

filename_list=["変更後のファイル名(1)","変更後のファイル名(2)".....]
list_of_files = glob.glob('保存先のフォルダのパス/*')
latest_file = max(list_of_files, key=os.path.getctime)
file_name = str(latest_file.split('\\')[1])
print(latest_file)
print()
os.remove("csv/"+filename_list[i-1])
os.rename(latest_file,"csv/"+filename_list[i-1])

データの前処理 

分析するためにはデータの前処理を行わなければ正しい結果は得られない. 今回は前処理の手法として正規化を行う. 正規化の手法として,VAR-LiNGAMではMin-Max法によるデータの正規化,RF5に用いるデータの正規化手法としては説明変数にMax法による正規化,目的変数にはZ scoreによる正規化を行う.

VAR-LiNGAMへの適用 

VAR-LiNGAMの分析ではPythonのモジュール「LiNGAM」のVAR-LiNGAMを用いる. これはhttps://lingam.readthedocs.io/en/latest/tutorial/var.html を参考にすればよい

path = "用いるデータのパス"
df=pd.read_csv(path,parse_dates=True,index_col="Day",encoding="cp932")
scaler = MinMaxScaler()
normalized_df = pd.DataFrame(scaler.fit_transform(df), columns=df.columns)
model = lingam.VARLiNGAM(lags=2, prune=True)
model.fit(normalized_df)

上のコードではデータの読み取り,正規化を行い,それについてVAR-LiNGAMを実行している.

labels = [f'{col}(t)' for i, col in enumerate(normalized_df.columns)]+[f'{col}(t-1)' for i,col in enumerate(df.columns)]
make_dot(np.hstack(model.adjacency_matrices_),
        lower_limit=0.05,
        ignore_shape=True,
        labels=labels
        )

上のコードで2次元グラフを作成している.このコードは結果を出すうえで特に必要ないため,実行しなくても良いが必要になった場合にはgraphvizのインストールが必要になる. graphvizのインストールについては以下のサイトを参考にした

https://www.kkaneko.jp/tools/win/graphviz.html

model = lingam.VARLiNGAM()
result = model.bootstrap(normalized_df,n_sampling=100)

これでLiNGAMのVAR-LiNGAMをモデルとして設定し,ブートストラップ法による分析を行っている.n_samplingの数でサンプリング回数を設定し,今回は100回になっているが,用いるデータのサンプル数を考慮し設定する必要がある. ブートストラップ法では一般的に用いるデータのサンプル数よりも大きいものを設定することが望ましい.

p_values = model.get_error_independence_p_values()

これで誤差変数間の独立性を分析する.

cdc = result.get_causal_direction_counts(n_directions=8, min_causal_effect=0.3,
split_by_causal_effect_sign=True)

このコードで因果関係の方向性を取得する.n_directionは上位いくつの因果方向を限定するかを設定するものであり,min_causal_effectでは係数が何以上の因果方向に限定するかを指定できる.

print_causal_directions(cdc, 100, labels=labels)

でその結果を描画できる.

dagc = result.get_directed_acyclic_graph_counts(n_dags=3, 
min_causal_effect=0.2, split_by_causal_effect_sign=True)

これではDAGのランキングを取得できる.また,

causal_effects = result.get_total_causal_effects(min_causal_effect=0.01)
df = pd.DataFrame(causal_effects)
df['from'] = df['from'].apply(lambda x : labels[x])
df['to'] = df['to'].apply(lambda x : labels[x])
df

これで合計因果関係を取得することができ,この結果を用いて3Dグラフの作成を行うため,pandasのto_csvを用いることでcsvファイルに保存しておく.

ingakekka.PNG

得られた因果性は上のような形式で保存される. fromには影響を与えている要素,toには影響を与えられている要素,valueには因果性の大きさが格納されている. 一行ずつ因果の向きと大きさが格納されている

数法則発見法(RF5法)によるモデル化 

数法則発見法の1つであるRF5を用いて経済変数間のモデル化を行う. RF5のプログラムは以下に貼っておく.

RF5では何度も反復を行い学習することでモデルを作成するため,反復回数を設定する必要がある. 反復回数を設定する際にはwhile s < 500:の500の部分を反復したい回数に設定する. この反復回数は従来研究では10000回や20000回が望ましいと述べられていたのでそれ以上の値に設定した方が良いだろう. 実行して得られたBICが低ければ低いほど良い結果をとりやすいのでBICが最も小さくなったものの結果を見て考察を行えばよい.

結果はtheta.csvに出力され,それをRF5の定式化に当てはめることで構築されたモデルを復元することができる. RF5の定式化は以下に示す.

RF_teishikika.png

θは(w_0,w_j,w_jk)かなっている.

因果3Dグラフの作成 

VAR-LiNGAMによって得られた結果から因果3Dグラフを作成する. ここではVARLiNGAMで得られた合計因果関係を格納したcsvファイルを用いて3Dグラフを作成する. csvファイルは以下の形式で保存されており,以下のプログラムでグラフが作成される.

import pandas as pd
import json
from pyvis.network import Network
def kyoki_word_network():
   got_net = Network(height="1000px", width="95%", bgcolor="#FFFFFF", font_color="black", notebook=True, directed=True)
   got_data = pd.read_csv("ultra_kekka.csv")[:2000]
   sources = got_data['from']
   targets = got_data['to']
   weights = got_data['effect']
   unique_nodes = set(sources) | set(targets)
   nodes = [{"id": node, "label": node, "title": node} for node in unique_nodes]
   edges = [{"from": src, "to": dst, "color": 'red' if w < 0 else 'blue', "label": str(round(w, 4)), "arrows": "to"} for src, dst, w in zip(sources, targets, weights)]
   nodes_json = json.dumps(nodes, ensure_ascii=False)
   edges_json = json.dumps(edges, ensure_ascii=False)
   html_code = """
   <!DOCTYPE html>
   <html lang="en">
   <head>
       <meta charset="UTF-8">
       <meta http-equiv="X-UA-Compatible" content="IE=edge">
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
       <title>Your Network</title>
       <style>
           #mynetwork {
               height: 1000px;
               width: 95%;
               border: 1px solid lightgray;
           }
       </style>
   </head>
   <body>
       <div id="mynetwork"></div>
       <script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
       <script>
           var container = document.getElementById("mynetwork");
           var nodes = new vis.DataSet(""" + nodes_json + """);
           var edges = new vis.DataSet(""" + edges_json + """);
           var data = {nodes: nodes, edges: edges};
           var options = {};
           var network = new vis.Network(container, data, options);
           // ノードのダブルクリック用のイベントリスナーを追加
           network.on("doubleClick", function (params) {
               if (params.nodes.length > 0) {
                   var nodeId = params.nodes[0];
                   var nodeLabel = nodes.get(nodeId).label;
                   // ページ遷移や他のダブルクリックされたノードに基づくアクションを実行
                   window.location.href = "page/" + nodeLabel;  // ページ遷移のURLを変更してください
               }
           });
       </script>
   </body>
   </html>
   """
   with open("your_network.html", "w", encoding="utf-8") as html_file:
       html_file.write(html_code)
       got_net.show_buttons(filter_=['physics'])
       return got_net
kyoki_word_network()

jscode=""の部分でクリックアクションなどを設定している. 今回はダブルクリックしたときにページ遷移するようにした.

networka.PNG

ここからノードをクリックすることで,ページ遷移を行う.


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS