共起ネットワーク図をサクッと作る

#はじめに
最近何度も何度も共起ネットワーク図を作る場面があり、[前の記事](https://qiita.com/niship2/items/9d7e2b6ab2ca1be18eaf)などで、なんやかんややっていたけれど、とりあえず共起関係をサクッと作る関数を作っておくことにした。
<font color="red">@hiro429 さんに助力いただいて、重複削除が解消できました！ありがとうございます</font>

#関数本体
dataframe:処理対象の列が含まれるpd.dataframe
colname:共起ネットワーク図を作りたい項目（列名）
sep:区切り

```python
#!pip install pyvis
def make_co_occur_df(dataframe,colname,sep):
    df_co_occur_network = \
    pd.merge(dataframe[colname].str.split(sep,expand=True).stack().reset_index(),
             dataframe[colname].str.split(sep,expand=True).stack().reset_index(),
             on="level_0",how="outer")\
             .pipe(lambda df: df[df["0_x"] != df["0_y"]])\
             .groupby(["0_x","0_y"],as_index=False).size()\
             .reset_index()\
             .rename(columns={"0_x":"source","0_y":"target",0:"weight"})\
             .pipe(lambda df:df[pd.DataFrame(np.sort(df[['source','target']].values)).duplicated()])
             #20210408最終行追加
             

    #source,target,weight(共起回数)のdfを返す。
    return df_co_occur_network
```
少し工夫した点は、共起ネットワークでいうセルフループを消す処理↓。

```python
 .pipe(lambda df: df[df["0_x"] != df["0_y"]])\
```


* 20200809　sourceとtargetを入れ替えると二重に出力されているのを発見。要修正
* 20210408追加 <font color="red">@hiro429 さんに助力いただいて、重複削除が解消できました！ありがとうございます</font>

#使い方

####データ読みこみ(dataframeに読み込み)
```python
import pandas as pd
df=pd.read_csv("https://storage.googleapis.com/yoshino/yoshino.csv",encoding='cp932')
df.head()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/b4a1f9f8-46ba-32d3-c164-84d19a466add.png)


####今回作成対象の列のIPCは|で区切られていることを確認。

```python
#IPC列を処理
colname="IPC"
sep="|"　#sepはここに反映させる。
edges=make_co_occur_df(df,colname,sep)

# networkxで読み込み。必要に応じてcoefなど出す。
import networkx as nx
G = nx.from_pandas_edgelist(edges, edge_attr=True)

```


####pyvisでhtmlを出力する。可視化の際の出力設定などは[公式](https://pyvis.readthedocs.io/en/latest/)参照
```python


!pip install pyvis
from pyvis.network import Network
pyvis_G = Network(height='600px', width='800px')
pyvis_G.from_nx(G)
pyvis_G.force_atlas_2based()
pyvis_G.show_buttons()
#pyvis_G.set_options("physics")
pyvis_G.show("mygraph.html")

```

####[mygraph.html](https://storage.googleapis.com/yoshino/mygraph.html)を開く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/6650a6a9-fe9f-ea1c-1fc2-e7eeacfabab2.png)



#その他
html画面で、表示を色々弄った後に
下の方の「generate option」を押せば、今後のoption設定で使える（と思われる）設定が出る。

<details><summary>options</summary><div>
```python
var options = {
  "edges": {
    "color": {
      "inherit": true
    },
    "smooth": false
  },
  "physics": {
    "forceAtlas2Based": {
      "springLength": 100
    },
    "minVelocity": 0.75,
    "solver": "forceAtlas2Based"
  }
}
```
</div></details>

また、

    pyvis_G = Network(height='600px', width='800px',notebook=True)

とするとnotebook内に表示されるようだが、colaboratoryではエラーが出て見れなかった。

* ネットワーク図が動くのが嫌な場合、操作パネルの下の方にあるphysicsのうち、enabledのチェックを外せばいい。




# 20220530更新
データ量が多いと上の関数だとクラッシュしがちだったので、違うアプローチを検討。
itertoolsで組み合わせ抽出してからdataframeに投入
こちらの方がいいかも
```python

import itertools
def get_combi(lis):
    pairlist = []
    for pair in itertools.combinations(lis, 2):
        pairlist.append(pair)
    return pairlist


from itertools import chain
def make_co_occur_df2(dataframe,colname,sep):
    nested_tuple = dataframe[colname].astype(str).apply(lambda x:x.split(sep)).apply(get_combi)
    tuplelists = nested_tuple.tolist()
    my_unnested_list = list(chain(*tuplelists))

    
    edges = pd.DataFrame(my_unnested_list).groupby([0,1],as_index=False).size()\
        .pipe(lambda df:df[df[0]!=df[1]])\
        .sort_values(by=["size"],ascending=False)\
        .rename(columns={0:"source",1:"target"})

    return edges    

```