阿弥陀経のネットワーク化

# 1. はじめに
* 「知ってるつもり」を見て法然ー親鸞の話に感動した私は、実家が浄土真宗であることをにわかに思い出し、阿弥陀経を参照してみることに。
* ただ、お経が漢字の羅列なので、もう少し俯瞰しようということで、 阿弥陀経をネットワークで表すとどうなるの？（ついでにwordcloud）ということでやってみた。
* やはり「仏」が中心にくる！


# 2.入出力など　
* 阿弥陀経というのは
>『阿弥陀経』は、浄土真宗で最も大切にされる浄土三部経の１つで、
浄土真宗のお通夜などでよく読まれるお経です。

[とのこと](https://xn--udsw7h21snjj.jp/books/sanbukyo/amidakyo/)。

* 元データはこんな感じ、これが400行くらい続く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/66893816-83a3-06b7-4368-67239a7b4d20.png)


* 全体図：(<font color="red">リンク注意</font>)
円の色は固有ベクトル中心性のカラースケール、円の多きさはmin-maxで処理した単語出現回数
<a href="https://storage.googleapis.com/yoshino/okyo/amida.html">![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/817c8ba9-365c-7a53-3277-832eea992ea3.png)
</a>

* 中心部：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/69cc6beb-c7b2-3cf7-c67a-750046e79aeb.png)



* 次数中心性が高いものリスト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/86c7b200-859d-6007-2961-205348912781.png)

* wordcloud
なんかカッコいい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/662ea788-93da-683a-9327-eab31f935921.png)


# 3.ソースコード

<summary><details>

* 最初は分かち書きをどうしようか迷ったけど、日本語でもないし、sentencepieceで区切りをやってもらうことに

```python
#!pip install sentencepiece

import sentencepiece as spm
import pandas as pd
spm.SentencePieceTrainer.train('--model_prefix=m --input=amida2.txt --vocab_size=1000 --model_type=bpe --normalization_rule_name=nfkc_cf --split_digits=true --hard_vocab_limit=false')
s = spm.SentencePieceProcessor(model_file='m.model')

amida = pd.read_csv("amida2.txt",header=None)
amida['wakati'] = amida[0].apply(s.SampleEncodeAsPieces).apply("|".join)

```


* その後は自作のsource-targetのつながり情報を作る関数(make_co_occur_df2)と([前の記事](https://qiita.com/niship2/items/39fb40c965126828373d)参照)、pyvisでネットワークを出力する関数を利用

```python
# @title ノードの色付け用関数
import math
def colorscale(v):
    t = math.cos(4 * math.pi * v)
    c = int(((-t / 2) + 0.5) * 255)
    if v >= 1.0:
        return get_colocode(255, 0, 0)
    elif v >= 0.75:
        return get_colocode(255, c, 0)
    elif v >= 0.5:
        return get_colocode(c, 255, 0)
    elif v >= 0.25:
        return get_colocode(0, 255, c)
    elif v >= 0:
        return get_colocode(0, c, 255)
    else:
        return get_colocode(0, 0, 255)

def get_colocode(r,g,b):
    return '#%02X%02X%02X' % (r,g,b)


# @title ノードの大きさ標準化用関数   
def minmax(nodedf):
    minval = nodedf[0].min()
    maxval = nodedf[0].max()
    nodedf["adj_size"] = (nodedf[0] - minval) * 100 / (maxval - minval) + 1
    return nodedf

```

* 苦労したのはネットワークを出力する関数。色付けとかノードの大きさをどうやって伝えるか苦労した結果、{各ノード名：対応する属性の値}という辞書を作り、それらをmapで充てる形で実現。
いつもこの部分で苦労していたので、今回まとめられてすっきり。

```python

#@title ネットワーク生成関数
import networkx as nx
import pandas as pd
from pyvis.network import Network

#ネットワーク図作成の関数
def re_construct_network(edge_df,sizedic):
    #nodeの生成
    G = nx.DiGraph
    G = nx.from_pandas_edgelist(edge_df,source="from",target="to") 

    #node_df生成。一回edgelistからnetworkxを経由してノードリストを生成しておく。
    node_df=pd.DataFrame(list(G.nodes()),columns=['nodes']).sort_values(by='nodes')  

    #nodeの色付け用辞書（中心性の計算）     
    eigen_centrality = nx.eigenvector_centrality_numpy(G)
    bet_centrality = nx.betweenness_centrality(G,k=1)
    degree_centrality = nx.degree_centrality(G)

    color_dic = {}
    color_dic[0] = eigen_centrality
    color_dic[1] = bet_centrality
    color_dic[2] = degree_centrality

    #edgelistの生成（）
    edges=[]
    for index, row in edge_df.iterrows():
        edges.append((row[0],row[1]))
    
    #nodeをpyvisに読ませる＋同時にedgeをpyvisに読ませる。
    pyvis_G = Network(height='750px', width='100%')
    node_id = node_df['nodes'].tolist()
    node_x = 1 #lambda式などでの処理もOK
    node_y = 1
    node_value = node_df['nodes'].tolist()
    node_color = node_df['nodes'].map(color_dic[0]).apply(colorscale).tolist()#あらかじめ単語ー値の辞書を作ってそれをmap 
    node_label = node_df["nodes"].astype(str).tolist()
    node_size = node_df['nodes'].map(sizedic).tolist() #あらかじめ単語ー値の辞書を作ってそれをmap

    
    #add_nodesで指定できるのが ["size", "value", "title", "x", "y", "label", "color"]
    pyvis_G.add_nodes(node_id,label=node_label,size=node_size,color=node_color)
    pyvis_G.add_edges(edges)
    pyvis_G.show_buttons(filter_=['physics'])
    return pyvis_G



from pyvis.network import Network
net = make_co_occur_df2(amida,colname="wakati",sep="|")
net.rename(columns={"source":"from","target":"to"},inplace=True)
net2 = net[net["from"]!="▁"][net["to"]!="▁"] #sentencepieceの先頭文字の「_」を削除

nodedf = amida['wakati'].str.split("|",expand=True).stack().value_counts().reset_index()
nodedf = minmax(nodedf)
sizedic = nodedf.set_index("index")["adj_size"].to_dict()

pyvis_G = re_construct_network(net2,sizedic)
pyvis_G.show_buttons(filter_=['physics'])
pyvis_G.show("amida.html")

```

</details></summary>





# 4.その他
* 他の仏教典もやってみようと思う（追加予定）

* 仏説観無量寿経↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/007908be-4312-a859-af7d-2c27e414981b.png)
 
* 仏説無量寿経↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/04e28eb0-6b72-4c93-3267-bd49469ea8d0.png)

以上３つが浄土三部経というものだそうで。全然知らなかったので浄土真宗の者（？）としては知れてよかった。無差別ランダムに救済してくれる、という宗教だそうでありがたや。