実例で動かすグラフアルゴリズムとグラフデータベース、02_アルゴリズム編、PageRankで重要なアカウントを探す

前編：
https://qiita.com/s_zh/items/3b183e258bcd6506e8cb

後編：
https://qiita.com/s_zh/items/75b129f8279e290fe705

Colabは[こちら](https://colab.research.google.com/drive/1OeY7KkHBsYsOj0jQusDT4U2UCgcN0van?usp=sharing)です。

![politician_02_PageRank.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239303/480393a5-7827-5573-8507-5b79caacd0bd.png)


# カウントベースで小手調べ

まずナイーブに重要なアカウントはたくさんフォローされると考えて、よくフォローされているアカウントを調べてみます。


```python
from neo4j import GraphDatabase
from tqdm.notebook import tqdm
import json

import pandas as pd
```


```python
auth_path = './data/neo4j_graph/auth.json'
with open(auth_path, 'r') as f:
    auth = json.load(f)

# ローカルの場合は通常 uri: bolt(or neo4j)://localhost:7687, user: neo4j, pd: 設定したもの
# サンドボックスの場合は作成画面から接続情報が見られます
uri = 'neo4j://localhost:7687'
driver = GraphDatabase.driver(uri=uri, auth=(auth['user'], auth['pd']))
```


```python
# Sandboxの場合はこんな感じ
# uri = 'bolt://54.175.38.249:35275'
# driver = GraphDatabase.driver(uri=uri, auth=('neo4j', 'spray-missile-sizing'))
```

クエリ結果の数が多くなると表示の問題でNeo4j Browserが固まりやすくなりますが、プログラムなら問題なく扱えることがあります。


```python
with driver.session() as session:
    res = session.run('''
    MATCH (u:User)<-[r:FOLLOW]-(u2:User)--(g:Group)
    RETURN u.userId as id, u.screenName as screen_name, u.name, count(DISTINCT r) as count
    ORDER BY count DESC
    ''')

res = list(res)
```


```python
res_df = pd.DataFrame.from_dict([r.data() for r in res])
print(res_df.shape)
res_df.head(10)
```

    (19944, 4)





<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>id</th>
      <th>screen_name</th>
      <th>u.name</th>
      <th>count</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0</td>
      <td>204245399</td>
      <td>None</td>
      <td>None</td>
      <td>139</td>
    </tr>
    <tr>
      <td>1</td>
      <td>104388107</td>
      <td>konotarogomame</td>
      <td>河野太郎</td>
      <td>136</td>
    </tr>
    <tr>
      <td>2</td>
      <td>468122115</td>
      <td>AbeShinzo</td>
      <td>安倍晋三</td>
      <td>129</td>
    </tr>
    <tr>
      <td>3</td>
      <td>245677083</td>
      <td>None</td>
      <td>None</td>
      <td>123</td>
    </tr>
    <tr>
      <td>4</td>
      <td>265205959</td>
      <td>None</td>
      <td>None</td>
      <td>118</td>
    </tr>
    <tr>
      <td>5</td>
      <td>89631948</td>
      <td>ecoyuri</td>
      <td>小池百合子</td>
      <td>110</td>
    </tr>
    <tr>
      <td>6</td>
      <td>96684891</td>
      <td>kharaguchi</td>
      <td>原口　一博</td>
      <td>110</td>
    </tr>
    <tr>
      <td>7</td>
      <td>124415804</td>
      <td>None</td>
      <td>None</td>
      <td>109</td>
    </tr>
    <tr>
      <td>8</td>
      <td>94482602</td>
      <td>SekoHiroshige</td>
      <td>世耕弘成 Hiroshige SEKO</td>
      <td>108</td>
    </tr>
    <tr>
      <td>9</td>
      <td>169480493</td>
      <td>None</td>
      <td>None</td>
      <td>108</td>
    </tr>
  </tbody>
</table>
</div>



政治家アカウント以外のアカウントはIDしか情報がないのでscreen_nameやnameがnullとなっています。まず政治家について見てみます。政治家によくフォローされる政治家アカウントランキングです。


```python
res_df[res_df.screen_name.notnull()].head(10)
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>id</th>
      <th>screen_name</th>
      <th>u.name</th>
      <th>count</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>104388107</td>
      <td>konotarogomame</td>
      <td>河野太郎</td>
      <td>136</td>
    </tr>
    <tr>
      <td>2</td>
      <td>468122115</td>
      <td>AbeShinzo</td>
      <td>安倍晋三</td>
      <td>129</td>
    </tr>
    <tr>
      <td>5</td>
      <td>89631948</td>
      <td>ecoyuri</td>
      <td>小池百合子</td>
      <td>110</td>
    </tr>
    <tr>
      <td>6</td>
      <td>96684891</td>
      <td>kharaguchi</td>
      <td>原口　一博</td>
      <td>110</td>
    </tr>
    <tr>
      <td>8</td>
      <td>94482602</td>
      <td>SekoHiroshige</td>
      <td>世耕弘成 Hiroshige SEKO</td>
      <td>108</td>
    </tr>
    <tr>
      <td>10</td>
      <td>58359180</td>
      <td>jimin_koho</td>
      <td>自民党広報</td>
      <td>107</td>
    </tr>
    <tr>
      <td>11</td>
      <td>94050482</td>
      <td>ichita_y</td>
      <td>山本一太</td>
      <td>105</td>
    </tr>
    <tr>
      <td>12</td>
      <td>112551613</td>
      <td>SatoMasahisa</td>
      <td>佐藤正久</td>
      <td>104</td>
    </tr>
    <tr>
      <td>16</td>
      <td>106595422</td>
      <td>TAIRAMASAAKI</td>
      <td>平将明</td>
      <td>97</td>
    </tr>
    <tr>
      <td>17</td>
      <td>80985167</td>
      <td>renho_sha</td>
      <td>蓮　舫　・　立　憲　民　主　党　( り　っ　け　ん　)</td>
      <td>97</td>
    </tr>
  </tbody>
</table>
</div>



首位３名は順当な感じがしますね、原口さんは最近あまりニュースで聞かない印象ですが、元総務大臣ということで、（すくなくともTwitter上では）影響力がある、かもしれません。

次に政治家以外のアカウントについてですが、こちらは現在idしかなくて、idはtwitterがユーザアカウントに割り当てるもので、APIを使えば詳細を調べられますが、IDからユーザ情報、あるいはユーザ情報からIDを調べるツールもあります（https://idtwi.com/）。ここでは上位ユーザについての情報を追加収集しました。[こちら](https://github.com/lightondust/topics_by_jupyter_notebook/raw/master/data/neo4j_graph/politicians_0909_additional.json)からダウンロードできます。


```python
additional_data_path = './data/neo4j_graph/politicians_0909_additional.json'

with open(additional_data_path, 'r') as f:
    additional_user_data = json.load(f)
```


```python
for idx, item in res_df[res_df['screen_name'].isnull()].head(20).iterrows():
    u_id = item['id']
    count = item['count']
    for u in additional_user_data:
        if u['id'] == u_id:
            user = u
    print('{}, {}, {}, {}'.format(u_id, user['screen_name'], user['name'], count))
```

    204245399, nhk_news, NHKニュース, 139
    245677083, hashimoto_lo, 橋下徹, 123
    265205959, Kantei_Saigai, 首相官邸(災害・危機管理情報), 118
    124415804, namatahara, 田原総一朗, 109
    169480493, nikkei, 日本経済新聞 電子版, 108
    412940784, kantei, 首相官邸, 103
    99008565, masason, 孫正義, 100
    109488235, Yomiuri_Online, 読売新聞オンライン, 97
    180585090, MHLWitter, 厚生労働省, 94
    42816371, asahi, 朝日新聞(asahi shimbun）, 93
    25073877, realDonaldTrump, Donald J. Trump, 89
    92686016, kenichiromogi, 茂木健一郎, 88
    297254593, kogashigeaki, 古賀茂明@フォーラム4, 87
    46282367, mainichijpnews, 毎日新聞ニュース, 86
    94701166, YoichiTakahashi, 高橋洋一（嘉悦大）, 85
    148961902, HeizoTakenaka, 竹中平蔵, 83
    97244324, hatoyamayukio, 鳩山友紀夫（由紀夫）Yukio Hatoyama, 82
    48264099, asao_keiichiro, あさお慶一郎　前衆議院議員, 81
    90521746, hmikitani, 三木谷浩史 H. Mikitani, 80
    4171231, tsuda, 津田大介, 80


案の定ニュース新聞系や関係の深いキャスターが出てきましたが、孫さんや三木谷さんなど社長が上位にランクインしたのが以外です。また橋下さん、竹中さん、鳩山さんなど元政治家が出てくるのも面白いですね。

カウントベースで面白い結果が出ていますが、カウントベースだとたくさん人をフォローしている人がフォローしていても、本当に数人しか重要な人しかフォローしない人がフォローしていても、同じ１としてカウントされるので、本当に重要なノードが得られるとは限りません。次にPageRankを使って重要なユーザを探していきます。その前にPageRankなどのアルゴリズムを使うためのNeo4jのGraph　Data Science Librayについて説明します。

# Neo4j Graph Data Science Library

Neo4jはPageRankなどのグラフアルゴリズムを実行するためにGraph Data Science Libraryが用意されています。データベースには様々なタイプのデータや繋がりを登録したいが、実際にグラフアルゴリズムを使うときにはその中の一部の種類のノードとリレーションシップにフォーカスしたり、部分グラフに注目したり、あるいは既存のグラフから加工して新しいグラフを作った上でアルゴリズムを適応したいことがよくあります。そういうときにクエリと組み合わせて対象となるグラフを抽出・構成したり、事前にアルゴリズムに必要なリソースを見積もったりする便利な機能などが用意されています。

インストールに関しては、Neo4j Desktopの場合は次のように「Manage」をクリックして、「Plugins」タブからインストールします。Neo4j Sandboxの場合は最初から入っているため、インストールは不要です。

![politician_02_install_gds1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239303/7bf948dd-ddc8-dd95-e1ca-db05e3608291.png)
![politician_02_install_gds2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239303/d99cd928-9a84-086b-0178-2f53e1a14103.png)

## アルゴリズムを適応するためのグラフを定義します。

データベースにはカテゴリとグループノードがありますが、PageRankを考える場合はUserノードとFOLLOW関係に集中します。実際に作る前にグラフを作るためのリソースを次のように見積もります。


```
CALL gds.graph.create.estimate('User', 'FOLLOW') YIELD nodeCount, relationshipCount, requiredMemory
```


```python
with driver.session() as session:
    res = session.run('''
    CALL gds.graph.create.estimate('User', 'FOLLOW') YIELD nodeCount, relationshipCount, requiredMemory
    ''')
```


```python
res = list(res)
print(res)
```

    [<Record nodeCount=19945 relationshipCount=166491 requiredMemory='[991 KiB ... 1055 KiB]'>]


特に問題がなければ実際に作ります。グラフ名（「follow-net-all」）をつけます。

```
CALL gds.graph.create('follow-net-all', 'User', 'FOLLOW')
```


```python
with driver.session() as session:
    res = session.run('''
    CALL gds.graph.create('follow-net-all', 'User', 'FOLLOW')
    ''')
```

また、全アカウントじゃなくて政治家アカウントのみで計算したいことがあるかもしれません。その場合クエリを使ってネットワークを定義します。具体的にはノードのid、リレーションの始点と終点をリターンします。必要あればリレーションシップのウェイトを指定することもできます


```python
with driver.session() as session:
    res = session.run('''
    CALL gds.graph.create.cypher.estimate( 
    'MATCH (g:Group)--(u:User) RETURN id(u) AS id', 
    'MATCH (:Group)--(u:User)-[r:FOLLOW]->(u2:User)--(:Group) WITH DISTINCT r, u, u2 RETURN id(u) AS source, id(u2) AS target')
    ''')
```


```python
res = list(res)
print(res)
```

    [<Record requiredMemory='299 KiB' treeView="HugeGraph: 299 KiB\n|-- this.instance: 72 Bytes\n|-- nodeIdMap: 35 KiB\n    |-- this.instance: 32 Bytes\n    |-- Neo4j identifiers: 3088 Bytes\n    |-- Mapping from Neo4j identifiers to internal identifiers: 32 KiB\n    |-- Node Label BitSets: 0 Bytes\n|-- adjacency list for 'RelationshipType{name='__ALL__'}': 256 KiB\n    |-- this.instance: 24 Bytes\n    |-- pages: 256 KiB\n|-- adjacency offsets for 'RelationshipType{name='__ALL__'}': 8224 Bytes\n    |-- this.instance: 16 Bytes\n    |-- page: 8208 Bytes\n" mapView={'name': 'HugeGraph', 'components': [{'name': 'this.instance', 'memoryUsage': '72 Bytes'}, {'name': 'nodeIdMap', 'components': [{'name': 'this.instance', 'memoryUsage': '32 Bytes'}, {'name': 'Neo4j identifiers', 'memoryUsage': '3088 Bytes'}, {'name': 'Mapping from Neo4j identifiers to internal identifiers', 'memoryUsage': '32 KiB'}, {'name': 'Node Label BitSets', 'memoryUsage': '0 Bytes'}], 'memoryUsage': '35 KiB'}, {'name': "adjacency list for 'RelationshipType{name='__ALL__'}'", 'components': [{'name': 'this.instance', 'memoryUsage': '24 Bytes'}, {'name': 'pages', 'memoryUsage': '256 KiB'}], 'memoryUsage': '256 KiB'}, {'name': "adjacency offsets for 'RelationshipType{name='__ALL__'}'", 'components': [{'name': 'this.instance', 'memoryUsage': '16 Bytes'}, {'name': 'page', 'memoryUsage': '8208 Bytes'}], 'memoryUsage': '8224 Bytes'}], 'memoryUsage': '299 KiB'} bytesMin=306456 bytesMax=306456 nodeCount=381 relationshipCount=58 heapPercentageMin=0.1 heapPercentageMax=0.1>]



```python
with driver.session() as session:
    res = session.run('''
    CALL gds.graph.create.cypher( 
    'follow-net-politicians', 
    'MATCH (g:Group)--(u:User) WITH DISTINCT u as u RETURN id(u) AS id', 
    'MATCH (:Group)--(u:User)-[r:FOLLOW]->(u2:User)--(:Group) RETURN id(u) AS source, id(u2) AS target')
    ''')
```

作ったグラフの一覧を見てみましょう。


```python
with driver.session() as session:
    res = session.run('''
    CALL gds.graph.list
    ''')
```


```python
res = list(res)
[print(r) for r in res]
```

    <Record graphName='follow-net-all' memoryUsage='5635 KiB' sizeInBytes=5770392 nodeProjection={'User': {'properties': {}, 'label': 'User'}} relationshipProjection={'FOLLOW': {'orientation': 'NATURAL', 'aggregation': 'DEFAULT', 'type': 'FOLLOW', 'properties': {}}} nodeQuery=None relationshipQuery=None nodeCount=19945 relationshipCount=166491 degreeDistribution={'p99': 170, 'min': 0, 'max': 2349, 'mean': 8.347505640511406, 'p90': 0, 'p50': 0, 'p999': 1612, 'p95': 0, 'p75': 0} creationTime=neo4j.time.DateTime(2020, 9, 15, 21, 9, 17.393649, tzinfo=<DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD>) modificationTime=neo4j.time.DateTime(2020, 9, 15, 21, 9, 17.515731999) schema={'relationships': {'FOLLOW': {}}, 'nodes': {'User': {}}}>
    <Record graphName='follow-net-politicians' memoryUsage='462 KiB' sizeInBytes=473832 nodeProjection=None relationshipProjection=None nodeQuery='MATCH (g:Group)--(u:User) WITH DISTINCT u as u RETURN id(u) AS id' relationshipQuery='MATCH (:Group)--(u:User)-[r:FOLLOW]->(u2:User)--(:Group) RETURN id(u) AS source, id(u2) AS target' nodeCount=346 relationshipCount=13756 degreeDistribution={'p99': 193, 'min': 0, 'max': 239, 'mean': 39.75722543352601, 'p90': 88, 'p50': 28, 'p999': 239, 'p95': 128, 'p75': 57} creationTime=neo4j.time.DateTime(2020, 9, 15, 21, 9, 18.764751, tzinfo=<DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD>) modificationTime=neo4j.time.DateTime(2020, 9, 15, 21, 9, 18.931898, tzinfo=<DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD>) schema={'relationships': {'__ALL__': {}}, 'nodes': {'__ALL__': {}}}>





    [None, None]



作成したグラフを削除するのは次のように行います。

```
CALL gds.graph.drop('follow_net_all');
```

# PageRank

いよいよPageRankです。PageRankはGoogleの創業者たちが論文で提唱し、それをきっかけに創業したことで有名です。ざっくり言えば、重要な人にフォローされている人が重要である、との仮定に基づいてノードの重要度をスコアとして算出するものです。仮想ユーザをウェブ上にランダムにリンクを辿らせて遷移していった時に、そのユーザが各ノードに止まる確率のようなものです。

さっそく実行してみます。

```
CALL gds.pageRank.stream('follow-net-all') YIELD nodeId, score
WITH gds.util.asNode(nodeId) as u, score
RETURN u.userId as id, u.name AS name, u.screenName as screen_name, score
ORDER BY score DESC LIMIT 10
```


```python
with driver.session() as session:
    res = session.run('''
    CALL gds.pageRank.stream('follow-net-all') YIELD nodeId, score
    WITH gds.util.asNode(nodeId) as u, score
    RETURN u.userId as id, u.name AS name, u.screenName as screen_name, score
    ORDER BY score DESC LIMIT 200
    ''')
```


```python
res = list(res)
res_df = pd.DataFrame([r.data() for r in res])

res_df
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>id</th>
      <th>name</th>
      <th>screen_name</th>
      <th>score</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0</td>
      <td>2291282737</td>
      <td>細川護熙</td>
      <td>morihirotokyo</td>
      <td>0.452028</td>
    </tr>
    <tr>
      <td>1</td>
      <td>2298092184</td>
      <td>小泉純一郎 J.Koizumi</td>
      <td>J_Koizumi_Japan</td>
      <td>0.346655</td>
    </tr>
    <tr>
      <td>2</td>
      <td>2481369336</td>
      <td>None</td>
      <td>None</td>
      <td>0.342734</td>
    </tr>
    <tr>
      <td>3</td>
      <td>135029283</td>
      <td>谷垣禎一</td>
      <td>Tanigaki_S</td>
      <td>0.339184</td>
    </tr>
    <tr>
      <td>4</td>
      <td>104388107</td>
      <td>河野太郎</td>
      <td>konotarogomame</td>
      <td>0.325671</td>
    </tr>
    <tr>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
    </tr>
    <tr>
      <td>195</td>
      <td>759251</td>
      <td>None</td>
      <td>None</td>
      <td>0.176333</td>
    </tr>
    <tr>
      <td>196</td>
      <td>61324547</td>
      <td>くしぶち万里　元衆議院議員</td>
      <td>kushibuchi</td>
      <td>0.176177</td>
    </tr>
    <tr>
      <td>197</td>
      <td>345178332</td>
      <td>衆議院議員森山浩行@立憲民主党堺（りっけん）</td>
      <td>MORIYAMAhiro</td>
      <td>0.176125</td>
    </tr>
    <tr>
      <td>198</td>
      <td>1195640294261182466</td>
      <td>None</td>
      <td>None</td>
      <td>0.176123</td>
    </tr>
    <tr>
      <td>199</td>
      <td>613201682</td>
      <td>None</td>
      <td>None</td>
      <td>0.176091</td>
    </tr>
  </tbody>
</table>
<p>200 rows × 4 columns</p>
</div>



今が人気だけじゃなくて、陰の実力者のアカウントもすこしあぶり出された、というような気もしますね。圧倒的重要さを誇るのは細川さん（二位とのスコア差が大きい）です。細川さんも小泉さんも元総理という重要なポジションであり、そしてカウントベースではむしろ下位に位置していることを考えれば、PageRankがよく機能していると言えるかもしれません。

政治家以外のアカウントを見てみます。


```python
for k, item in res_df[res_df.name.isnull()].iterrows():
    user = {}
    u_id = item['id']
    for u in additional_user_data:
        if u['id'] == u_id:
            user = u
    print('{}, {}, {}, {}, {}'.format(k, u_id, user.get('screen_name'), user.get('name'), item['score']))
```

    2, 2481369336, None, None, 0.3427342087764733
    7, 245677083, hashimoto_lo, 橋下徹, 0.3104444960829783
    10, 305320802, None, None, 0.29620774772489844
    15, 265205959, Kantei_Saigai, 首相官邸(災害・危機管理情報), 0.26993426864236714
    18, 99008565, masason, 孫正義, 0.25991508577836087
    19, 25073877, realDonaldTrump, Donald J. Trump, 0.25841955984103876
    21, 204245399, nhk_news, NHKニュース, 0.2536393801962411
    23, 69861141, None, None, 0.25213300565757085
    28, 124415804, namatahara, 田原総一朗, 0.23418672573544158
    33, 42816371, asahi, 朝日新聞(asahi shimbun）, 0.22684923383383965
    35, 903338594, sugawitter, 菅 義偉, 0.22650765601559872
    36, 412940784, kantei, 首相官邸, 0.22143552415051596
    37, 169480493, nikkei, 日本経済新聞 電子版, 0.2214105514823688
    39, 48264099, asao_keiichiro, あさお慶一郎　前衆議院議員, 0.22006568025766313
    40, 275355095, None, None, 0.2186452617306928
    41, 297254593, kogashigeaki, 古賀茂明@フォーラム4, 0.2180277926388264
    43, 148961902, HeizoTakenaka, 竹中平蔵, 0.2163264090153946
    44, 90521746, hmikitani, 三木谷浩史 H. Mikitani, 0.21538645175146418
    45, 97244324, hatoyamayukio, 鳩山友紀夫（由紀夫）Yukio Hatoyama, 0.21532410236155686
    47, 94701166, YoichiTakahashi, 高橋洋一（嘉悦大）, 0.21393892916563398


データがないアカウントはフォローしている政治家アカウントがすくないものの、重要な政治家アカウントにフォローされているということですね。高い順で「一般社団法人自然エネルギー推進会議」と「古川元久事務所」です。「一般社団法人自然エネルギー推進会議」は名前だけからするとなにやら目立たないけれど有力者とつながってそうな匂いを感じてしまいます。「古川元久事務所」は政治家のアカウントですが、スクレイピング元のデータに欠損がありました。これは逆に考えれば、グラフデータのラベルに欠損がつきものであるが、グラフアルゴリズムを使うことで一部のラベルだけから効率よく残りの類似ノードを見つけられるということかもしれません。

次にDamping Factorを変えてみます。Damping Factorはdefaultの0.85で設定されています。詳細の説明は割愛しますが、循環参照（もともと論文の場合は先行研究しか引用しないので通常循環参照が生じない）があるとスコアがそこに集中したり、収束しないことがありますが、それを抑えるのがDumping Factorです。Dampling Factorの値が大きい（１に近い）と抑えが効かず値が収束しにくかったり、循環参照のスコアが不正に大きくなりがちだが、小さいとスコアが伝搬せずグラフの構造を反映できなくなってしまいます。0.85で使うことが多いです。


```python
with driver.session() as session:
    res = session.run('''
    CALL gds.pageRank.stream('follow-net-all', {dampingFactor: 0.75}) YIELD nodeId, score
    WITH gds.util.asNode(nodeId) as u, score
    RETURN u.userId as id, u.name AS name, u.screenName as screen_name, score
    ORDER BY score DESC LIMIT 20
    ''')
```


```python
res = list(res)
res_df = pd.DataFrame([r.data() for r in res])

res_df
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>id</th>
      <th>name</th>
      <th>screen_name</th>
      <th>score</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0</td>
      <td>2291282737</td>
      <td>細川護熙</td>
      <td>morihirotokyo</td>
      <td>0.630261</td>
    </tr>
    <tr>
      <td>1</td>
      <td>135029283</td>
      <td>谷垣禎一</td>
      <td>Tanigaki_S</td>
      <td>0.523063</td>
    </tr>
    <tr>
      <td>2</td>
      <td>104388107</td>
      <td>河野太郎</td>
      <td>konotarogomame</td>
      <td>0.502890</td>
    </tr>
    <tr>
      <td>3</td>
      <td>2298092184</td>
      <td>小泉純一郎 J.Koizumi</td>
      <td>J_Koizumi_Japan</td>
      <td>0.492805</td>
    </tr>
    <tr>
      <td>4</td>
      <td>58359180</td>
      <td>自民党広報</td>
      <td>jimin_koho</td>
      <td>0.492129</td>
    </tr>
    <tr>
      <td>5</td>
      <td>468122115</td>
      <td>安倍晋三</td>
      <td>AbeShinzo</td>
      <td>0.491159</td>
    </tr>
    <tr>
      <td>6</td>
      <td>2481369336</td>
      <td>None</td>
      <td>None</td>
      <td>0.487239</td>
    </tr>
    <tr>
      <td>7</td>
      <td>245677083</td>
      <td>None</td>
      <td>None</td>
      <td>0.481302</td>
    </tr>
    <tr>
      <td>8</td>
      <td>94050482</td>
      <td>山本一太</td>
      <td>ichita_y</td>
      <td>0.465500</td>
    </tr>
    <tr>
      <td>9</td>
      <td>122343424</td>
      <td>松本純</td>
      <td>junmatsumoto411</td>
      <td>0.462421</td>
    </tr>
    <tr>
      <td>10</td>
      <td>305320802</td>
      <td>None</td>
      <td>None</td>
      <td>0.461928</td>
    </tr>
    <tr>
      <td>11</td>
      <td>914762049481084929</td>
      <td>立憲民主党（りっけん）</td>
      <td>CDP2017</td>
      <td>0.460617</td>
    </tr>
    <tr>
      <td>12</td>
      <td>89631948</td>
      <td>小池百合子</td>
      <td>ecoyuri</td>
      <td>0.460385</td>
    </tr>
    <tr>
      <td>13</td>
      <td>94482602</td>
      <td>世耕弘成 Hiroshige SEKO</td>
      <td>SekoHiroshige</td>
      <td>0.449965</td>
    </tr>
    <tr>
      <td>14</td>
      <td>112551613</td>
      <td>佐藤正久</td>
      <td>SatoMasahisa</td>
      <td>0.436635</td>
    </tr>
    <tr>
      <td>15</td>
      <td>265205959</td>
      <td>None</td>
      <td>None</td>
      <td>0.423003</td>
    </tr>
    <tr>
      <td>16</td>
      <td>134715633</td>
      <td>松井一郎(大阪市長)</td>
      <td>gogoichiro</td>
      <td>0.413342</td>
    </tr>
    <tr>
      <td>17</td>
      <td>106595422</td>
      <td>平将明</td>
      <td>TAIRAMASAAKI</td>
      <td>0.411991</td>
    </tr>
    <tr>
      <td>18</td>
      <td>99008565</td>
      <td>None</td>
      <td>None</td>
      <td>0.409122</td>
    </tr>
    <tr>
      <td>19</td>
      <td>83774916</td>
      <td>平井卓也（ひらいたくや）</td>
      <td>hiratakuchan</td>
      <td>0.405061</td>
    </tr>
  </tbody>
</table>
</div>



多少順番が入れ替わった感じですね。

次にネットワークを政治家ノードに限定して算出します。


```python
with driver.session() as session:
    res = session.run('''
    CALL gds.pageRank.stream('follow-net-politicians') YIELD nodeId, score
    WITH gds.util.asNode(nodeId) as u, score
    RETURN u.userId as id, u.name AS name, u.screenName as screen_name, score
    ORDER BY score DESC LIMIT 20
    ''')
```


```python
res = list(res)
res_df = pd.DataFrame([r.data() for r in res])

res_df
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>id</th>
      <th>name</th>
      <th>screen_name</th>
      <th>score</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0</td>
      <td>58359180</td>
      <td>自民党広報</td>
      <td>jimin_koho</td>
      <td>4.628814</td>
    </tr>
    <tr>
      <td>1</td>
      <td>112551613</td>
      <td>佐藤正久</td>
      <td>SatoMasahisa</td>
      <td>4.434653</td>
    </tr>
    <tr>
      <td>2</td>
      <td>89631948</td>
      <td>小池百合子</td>
      <td>ecoyuri</td>
      <td>3.974174</td>
    </tr>
    <tr>
      <td>3</td>
      <td>134715633</td>
      <td>松井一郎(大阪市長)</td>
      <td>gogoichiro</td>
      <td>3.398299</td>
    </tr>
    <tr>
      <td>4</td>
      <td>145599783</td>
      <td>吉村洋文（大阪府知事）</td>
      <td>hiroyoshimura</td>
      <td>3.087031</td>
    </tr>
    <tr>
      <td>5</td>
      <td>468122115</td>
      <td>安倍晋三</td>
      <td>AbeShinzo</td>
      <td>2.958654</td>
    </tr>
    <tr>
      <td>6</td>
      <td>104388107</td>
      <td>河野太郎</td>
      <td>konotarogomame</td>
      <td>2.634810</td>
    </tr>
    <tr>
      <td>7</td>
      <td>2291282737</td>
      <td>細川護熙</td>
      <td>morihirotokyo</td>
      <td>2.615294</td>
    </tr>
    <tr>
      <td>8</td>
      <td>2298092184</td>
      <td>小泉純一郎 J.Koizumi</td>
      <td>J_Koizumi_Japan</td>
      <td>2.547026</td>
    </tr>
    <tr>
      <td>9</td>
      <td>94050482</td>
      <td>山本一太</td>
      <td>ichita_y</td>
      <td>2.519077</td>
    </tr>
    <tr>
      <td>10</td>
      <td>914762049481084929</td>
      <td>立憲民主党（りっけん）</td>
      <td>CDP2017</td>
      <td>2.296642</td>
    </tr>
    <tr>
      <td>11</td>
      <td>96684891</td>
      <td>原口　一博</td>
      <td>kharaguchi</td>
      <td>2.228331</td>
    </tr>
    <tr>
      <td>12</td>
      <td>94482602</td>
      <td>世耕弘成 Hiroshige SEKO</td>
      <td>SekoHiroshige</td>
      <td>2.205480</td>
    </tr>
    <tr>
      <td>13</td>
      <td>135029283</td>
      <td>谷垣禎一</td>
      <td>Tanigaki_S</td>
      <td>2.131317</td>
    </tr>
    <tr>
      <td>14</td>
      <td>106595422</td>
      <td>平将明</td>
      <td>TAIRAMASAAKI</td>
      <td>2.000736</td>
    </tr>
    <tr>
      <td>15</td>
      <td>2590575655</td>
      <td>ここりん（公式）</td>
      <td>nipponkokoro</td>
      <td>1.966871</td>
    </tr>
    <tr>
      <td>16</td>
      <td>83774916</td>
      <td>平井卓也（ひらいたくや）</td>
      <td>hiratakuchan</td>
      <td>1.852419</td>
    </tr>
    <tr>
      <td>17</td>
      <td>76031812</td>
      <td>浅田 均（参議院議員）</td>
      <td>asalogue</td>
      <td>1.826080</td>
    </tr>
    <tr>
      <td>18</td>
      <td>119577038</td>
      <td>公明党</td>
      <td>komei_koho</td>
      <td>1.756745</td>
    </tr>
    <tr>
      <td>19</td>
      <td>80985167</td>
      <td>蓮　舫　・　立　憲　民　主　党　( り　っ　け　ん　)</td>
      <td>renho_sha</td>
      <td>1.713555</td>
    </tr>
  </tbody>
</table>
</div>



また、全政治家ではなく、自民党内での重要性を見てみます。


```python
with driver.session() as session:
    res = session.run(  
        '''
        CALL gds.graph.create.cypher(  
        'follow-net-parties',  
        'MATCH (g:Group {name:"自由民主党"})--(u:User) RETURN id(u) AS id',  
        'MATCH (g:Group {name:"自由民主党"})--(u:User)-[r:FOLLOW]->(u2:User)--(g) WITH DISTINCT r, u, u2 RETURN id(u) AS source, id(u2) AS target') 
        ''')
```


```python
with driver.session() as session:
    res = session.run('''
    CALL gds.pageRank.stream('follow-net-parties') YIELD nodeId, score
    WITH gds.util.asNode(nodeId) as u, score
    RETURN u.userId as id, u.name AS name, u.screenName as screen_name, score
    ORDER BY score DESC LIMIT 20
    ''')
```


```python
res = list(res)
res_df = pd.DataFrame([r.data() for r in res])

res_df
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>id</th>
      <th>name</th>
      <th>screen_name</th>
      <th>score</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0</td>
      <td>112551613</td>
      <td>佐藤正久</td>
      <td>SatoMasahisa</td>
      <td>2.940377</td>
    </tr>
    <tr>
      <td>1</td>
      <td>58359180</td>
      <td>自民党広報</td>
      <td>jimin_koho</td>
      <td>2.151208</td>
    </tr>
    <tr>
      <td>2</td>
      <td>135029283</td>
      <td>谷垣禎一</td>
      <td>Tanigaki_S</td>
      <td>1.994588</td>
    </tr>
    <tr>
      <td>3</td>
      <td>468122115</td>
      <td>安倍晋三</td>
      <td>AbeShinzo</td>
      <td>1.799998</td>
    </tr>
    <tr>
      <td>4</td>
      <td>104388107</td>
      <td>河野太郎</td>
      <td>konotarogomame</td>
      <td>1.745840</td>
    </tr>
    <tr>
      <td>5</td>
      <td>83774916</td>
      <td>平井卓也（ひらいたくや）</td>
      <td>hiratakuchan</td>
      <td>1.619778</td>
    </tr>
    <tr>
      <td>6</td>
      <td>94050482</td>
      <td>山本一太</td>
      <td>ichita_y</td>
      <td>1.603370</td>
    </tr>
    <tr>
      <td>7</td>
      <td>94482602</td>
      <td>世耕弘成 Hiroshige SEKO</td>
      <td>SekoHiroshige</td>
      <td>1.591588</td>
    </tr>
    <tr>
      <td>8</td>
      <td>106595422</td>
      <td>平将明</td>
      <td>TAIRAMASAAKI</td>
      <td>1.451602</td>
    </tr>
    <tr>
      <td>9</td>
      <td>122343424</td>
      <td>松本純</td>
      <td>junmatsumoto411</td>
      <td>1.385155</td>
    </tr>
    <tr>
      <td>10</td>
      <td>78646435</td>
      <td>片山さつき</td>
      <td>katayama_s</td>
      <td>1.111217</td>
    </tr>
    <tr>
      <td>11</td>
      <td>148169494</td>
      <td>柴山昌彦</td>
      <td>shiba_masa</td>
      <td>1.076998</td>
    </tr>
    <tr>
      <td>12</td>
      <td>91760590</td>
      <td>牧島かれん</td>
      <td>makishimakaren</td>
      <td>1.043077</td>
    </tr>
    <tr>
      <td>13</td>
      <td>95405735</td>
      <td>あいさわ一郎</td>
      <td>ichiroaisawa</td>
      <td>0.938201</td>
    </tr>
    <tr>
      <td>14</td>
      <td>99275472</td>
      <td>熊谷 ゆたか</td>
      <td>kumagai_yutaka</td>
      <td>0.925106</td>
    </tr>
    <tr>
      <td>15</td>
      <td>137884361</td>
      <td>三原じゅん子</td>
      <td>miharajunco</td>
      <td>0.920131</td>
    </tr>
    <tr>
      <td>16</td>
      <td>202979703</td>
      <td>茂木敏充</td>
      <td>moteging</td>
      <td>0.903428</td>
    </tr>
    <tr>
      <td>17</td>
      <td>12458472</td>
      <td>新藤　義孝</td>
      <td>shindo_y</td>
      <td>0.842672</td>
    </tr>
    <tr>
      <td>18</td>
      <td>246575371</td>
      <td>山本ともひろ℗</td>
      <td>ty_polepole</td>
      <td>0.841348</td>
    </tr>
    <tr>
      <td>19</td>
      <td>135884288</td>
      <td>宮川典子</td>
      <td>norikomiya</td>
      <td>0.834485</td>
    </tr>
  </tbody>
</table>
</div>



民進党内を見てみます


```python
with driver.session() as session:
    res = session.run('''
        CALL gds.graph.drop('follow-net-parties')
    ''')
    res = session.run(  
        '''
        CALL gds.graph.create.cypher(  
        'follow-net-parties',  
        'MATCH (g:Group {name:"自由民主党"})--(u:User) RETURN id(u) AS id',  
        'MATCH (g:Group {name:"自由民主党"})--(u:User)-[r:FOLLOW]->(u2:User)--(g) WITH DISTINCT r, u, u2 RETURN id(u) AS source, id(u2) AS target') 
        '''.replace('自由民主党', '民進党'))
```


```python
with driver.session() as session:
    res = session.run('''
    CALL gds.pageRank.stream('follow-net-parties') YIELD nodeId, score
    WITH gds.util.asNode(nodeId) as u, score
    RETURN u.userId as id, u.name AS name, u.screenName as screen_name, score
    ORDER BY score DESC LIMIT 20
    ''')
```


```python
res = list(res)
res_df = pd.DataFrame([r.data() for r in res])

res_df
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>id</th>
      <th>name</th>
      <th>screen_name</th>
      <th>score</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0</td>
      <td>107039196</td>
      <td>福山哲郎・立憲民主党（りっけん）</td>
      <td>fuku_tetsu</td>
      <td>1.718304</td>
    </tr>
    <tr>
      <td>1</td>
      <td>174604776</td>
      <td>川内 博史</td>
      <td>kawauchihiroshi</td>
      <td>1.580158</td>
    </tr>
    <tr>
      <td>2</td>
      <td>80985167</td>
      <td>蓮　舫　・　立　憲　民　主　党　( り　っ　け　ん　)</td>
      <td>renho_sha</td>
      <td>1.341613</td>
    </tr>
    <tr>
      <td>3</td>
      <td>772827848985841664</td>
      <td>前原誠司</td>
      <td>Maehara2016</td>
      <td>1.272803</td>
    </tr>
    <tr>
      <td>4</td>
      <td>536910778</td>
      <td>細野豪志　Goshi Hosono</td>
      <td>hosono_54</td>
      <td>1.163544</td>
    </tr>
    <tr>
      <td>5</td>
      <td>96785342</td>
      <td>玉木雄一郎（国民民主党代表）</td>
      <td>tamakiyuichiro</td>
      <td>1.158696</td>
    </tr>
    <tr>
      <td>6</td>
      <td>34773800</td>
      <td>逢坂誠二 立憲民主党（りっけん）</td>
      <td>seiji_ohsaka</td>
      <td>1.133889</td>
    </tr>
    <tr>
      <td>7</td>
      <td>96684891</td>
      <td>原口　一博</td>
      <td>kharaguchi</td>
      <td>1.051628</td>
    </tr>
    <tr>
      <td>8</td>
      <td>116097539</td>
      <td>小西ひろゆき （参議院議員）</td>
      <td>konishihiroyuki</td>
      <td>1.026933</td>
    </tr>
    <tr>
      <td>9</td>
      <td>107846407</td>
      <td>馬淵澄夫</td>
      <td>mabuchi_sumio</td>
      <td>0.962776</td>
    </tr>
    <tr>
      <td>10</td>
      <td>45708362</td>
      <td>階猛(しな たけし)</td>
      <td>shinatakeshi</td>
      <td>0.958277</td>
    </tr>
    <tr>
      <td>11</td>
      <td>116426900</td>
      <td>山井和則</td>
      <td>yamanoikazunori</td>
      <td>0.954659</td>
    </tr>
    <tr>
      <td>12</td>
      <td>95338477</td>
      <td>有田芳生</td>
      <td>aritayoshifu</td>
      <td>0.930065</td>
    </tr>
    <tr>
      <td>13</td>
      <td>279935870</td>
      <td>長妻昭りっけん立憲民主党</td>
      <td>nagatsumaakira</td>
      <td>0.886719</td>
    </tr>
    <tr>
      <td>14</td>
      <td>55165402</td>
      <td>金子洋一・前参議院議員（神奈川県選出）</td>
      <td>Y_Kaneko</td>
      <td>0.856139</td>
    </tr>
    <tr>
      <td>15</td>
      <td>157592722</td>
      <td>あべともこ（衆議院議員・神奈川１２区・立憲民主党）</td>
      <td>abe_tomoko</td>
      <td>0.822089</td>
    </tr>
    <tr>
      <td>16</td>
      <td>711473829759946752</td>
      <td>民進党</td>
      <td>MinshintoNews</td>
      <td>0.796128</td>
    </tr>
    <tr>
      <td>17</td>
      <td>160175660</td>
      <td>長島昭久 Akihisa NAGASHIMA, MP</td>
      <td>nagashima21</td>
      <td>0.781087</td>
    </tr>
    <tr>
      <td>18</td>
      <td>2904204817</td>
      <td>山尾しおり</td>
      <td>ShioriYamao</td>
      <td>0.774538</td>
    </tr>
    <tr>
      <td>19</td>
      <td>114697823</td>
      <td>柚木みちよし</td>
      <td>yunoki_m</td>
      <td>0.745531</td>
    </tr>
  </tbody>
</table>
</div>



最後に重要なノードの大きさをPageRankの値に比例し、リンクの太さをスコアの流れの大きさに比例するようにした図を載せます（政治家のみのネットワークで、PageRank上位25程度のノードを表示、作図はNeo4j Bloomを使用）。

![politician_02_PageRank.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239303/480393a5-7827-5573-8507-5b79caacd0bd.png)

# 備考

- ドキュメント
    - Neo4j Document一覧：https://neo4j.com/docs/
    - DB管理、インストール、設定config等:https://neo4j.com/docs/operations-manual/current/
    - Cyper Query: https://neo4j.com/docs/cypher-manual/current/
    - Driver(Pythonなどのプログラムからアクセスする場合): https://neo4j.com/docs/driver-manual/4.0/
    - Graph Data Science（内蔵のグラフアルゴリズム）: https://neo4j.com/docs/graph-data-science/current/
   
- チュートリアル: https://neo4j.com/graphacademy/online-training/
- 開発者向けのテーマやトピック：https://neo4j.com/developer/get-started/
- 実験的な機能や新しい機能について：https://neo4j.com/labs/