PythonでQiitaタグのネットワークを可視化する

どうもmiyachi（[@_38ch](https://twitter.com/_38ch)）です。
ちょっと仕事でネットワーク分析的な事が必要になり、Pythonで描くんであればどんなライブラリ使うのかなで調べたら[networkx](https://networkx.github.io/documentation/stable/index.html#)が多かったので自分でも軽く書いてみました。

Qiitaにすでに出てる記事を参考にしながら、Qiitaのタグのネットワーク（どのタグとどのタグがセットで使われているか）を可視化してみます。先に結果を出しちゃうとこういうものを作りました。
![g2.png](https://qiita-image-store.s3.amazonaws.com/0/209160/90213daa-f447-dee3-dd4f-02d367fe4c0b.png)



## 環境
* Mac High Sierra 10.13.4
* Python 3.5.0
* Jupyter Notebook


## データの準備
Qiitaの記事取得のAPIを叩いて、タグのデータだけ取得します。

```python
import requests
import json
import collections
import itertools
import networkx as nx
%matplotlib inline
import matplotlib.pyplot as plt

params = {"page":1, "per_page":100}
for i in range(60):
    print("fetching... page " + str(i + 1))
    params["page"] = i + 1
    res = requests.get("https://qiita.com/api/v2/items", params=params)
    items.extend(json.loads(res.text))
```
いま、itemsにはタグ以外のデータも入ってしまっているので、タグだけを抽出。

```python
tags_list = []
for item in items:
    tags = [tag["name"] for tag in item["tags"]]
    tags_list.append(tags)
```
これでtags_listには、記事ごとのタグのリストが入ってきます。

```python:tags_listの中身
[['cli', 'ESP32', 'M5stack'],
 ['Wiki.js'],
 ['PHP', 'laravel', 'Eloquent'],
 ['Python', '初心者', '機械学習', 'gensim', 'word2vec'],
 ['Git', 'GitHub', 'バージョン管理'],
 ['ＨＴＴＰメソッド'],
 ['文字コード', 'バイナリ'],
 ['Node.js', 'npm', 'anyenv', 'ndenv'],
 ['RHEL', 'ext4'],
 ['R', 'Pandoc', 'RMarkdown']...
]
```
すべてのタグをネットワークに入れるとカオスになるので、頻出タグを選別しておきましょう。今回はTOP50を取得。

```python
tag_count = collections.Counter(itertools.chain.from_iterable(tags_list)).most_common(50)
```
```python:tag_countの中身
[('JavaScript', 39),
 ('Python', 39),
 ('PHP', 27),
 ('AWS', 24),
 ('python3', 18),
 ('Ruby', 17),
 ('laravel', 16),
 ('Rails', 15),
 ('MySQL', 15),
 ('docker', 14)...
]
```

## ネットワーク図の作成
それではnetworkxを使って、データの可視化を行なっていきます。

```python
G = nx.Graph()
G.add_nodes_from([(tag, {"count":count}) for tag, count in tag_count])
```
まだこの時点では、ノード（ネットワーク図に置ける"丸"）しか作成されていません。
ので、エッジ（丸と丸を繋ぐ線）を追加していきましょう。

```python
for tags in tags_list:
    for tag0, tag1 in itertools.combinations(tags, 2):
        if not G.has_node(tag0) or not G.has_node(tag1):
            continue
        if G.has_edge(tag0, tag1):
            G[tag0][tag1]["weight"] += 1
        else:
            G.add_edge(tag0, tag1, weight=1)
```
ここは少し複雑ですが、まず、tag_listから一つのリストを取得し、全ての組み合わせ（tag0, tag1）をみています。
例えば、`['Git', 'GitHub', 'バージョン管理']`というtag_listがあれば、`(Git, GitHub), (Git, バージョン管理), (Github, バージョン管理)`という3パターンがtag0, tag1に入ってきます。

その上で、すでに、GitとGitHubのノード間にエッジが追加されていた場合は、weight（線の太さ）を加算し、エッジが追加されていない場合は、エッジを追加します。


それではいよいよグラフを描画してみます。

```python 
plt.figure(figsize=(15,15)) # グラフのサイズを定義
pos = nx.spring_layout(G, k=1.5) # ノード間の反発力を定義。値が小さいほど密集する

node_size = [ d['count']*50 for (n,d) in G.nodes(data=True)] # ノードの大きさを調整
nx.draw_networkx_nodes(G, pos, node_color='b', alpha=0.2, node_size=node_size, font_weight="bold", font_family='VL Gothic') # ノードのスタイルを定義
nx.draw_networkx_labels(G, pos, fontsize=14)

edge_width = [ d['weight']*0.5 for (u,v,d) in G.edges(data=True)] # エッジの太さを調整
nx.draw_networkx_edges(G, pos, alpha=0.4, edge_color='r', width=edge_width)　# エッジのスタイルを定義

plt.axis('off')
```
結果として以下のようなネットワークになります。
（日本語の出し方がわからないので、わかる方教えてください・・・）

![g2.png](https://qiita-image-store.s3.amazonaws.com/0/209160/90213daa-f447-dee3-dd4f-02d367fe4c0b.png)

## 考察
* 強いところでいうと、Python、JavaScript、PHP、AWSあたりでしょうか。
* 多分Pythonの真下にあるのは機械学習かな？
* Excelが孤立しているのがエモい。


## 参考記事
[[Python]NetworkXでQiitaのタグ関係図を描く](https://qiita.com/inoory/items/088f719f2fd9a2ea4ee5)


## 宣伝
プライベートでWalicaという複雑な割り勘のサポートサービスを作っているのでもしよかったら、使ってみてください。
[![Custom Preset.png](https://qiita-image-store.s3.amazonaws.com/0/209160/c22a07a1-ff33-1b19-1255-2bf1296f1cc9.png)](https://walica.jp?share=qiita)