検索キーワードの共起ネットワーク図を cytoscape で描画する


以前、Google Search Console の キーワードの、共起ネットワーク図を python で描画する | Monotalk で、networkxmatplotlib を使って共起ネットワーク図を作成してみました。
その続きで、Cytoscape: An Open Source Platform for Complex Network Analysis and Visualization を使ってネットワーク図を作成してみた結果を記載します。
スクリプトを動作させると以下のようなグラフが複数描画されます。
keyword_network


参考

以下の記事を参考に実装は作成しています。


前提

以下の環境で動かしています。


os の version

% sw_vers 
ProductName:    Mac OS X
ProductVersion: 10.12.6
BuildVersion:   16G29

python の verison

% python -V
Python 2.7.10

必要なライブラリのインストール

スクリプトを動作させるのに必要なのは、以下になります。
実行する場合はあらかじめインストールお願い致します。

pip install networkx
pip install sklearn
pip install py2cytoscape     

py2cytoscapeインストール時のトラブル

私の Mac だと py2cytoscape のインストール時少しトラブりましたので、内容を記載しておきます。

  • sudo pip install py2cytoscape
    sudo で pip で以下のエラーが発生しました。
    いつもの、mac の python が /usr/bin/python 配下にいる問題でのエラーかと思います。

    % sudo pip install py2cytoscape
    Command "/usr/bin/python -u -c "import setuptools, tokenize;__file__='/private/tmp/pip-build-INLuYR/python-igraph/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-cALUsa-record/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /private/tmp/pip-build-INLuYR/python-igraph/
    

  • sudo pip install py2cytoscape –ignore-installed six
    関係はなさそうに見えましたが、とりあえず--ignore-installed six をつけて実行しました。
    エラーの内容は変わりましたが、インストールできませんでした。

    % sudo pip install py2cytoscape --ignore-installed six
    OSError: [Errno 1] Operation not permitted: '/System/Library/Frameworks/Python.framework/Versions/2.7/share'
    

  • pip install –user py2cytoscape
    最終的にログインユーザーのライブラリとしてインストールしました。

    % pip install --user py2cytoscape
    Successfully installed idna-2.5 py2cytoscape-0.6.2 python-igraph-0.7.1.post6
    


cytoscape のインストール

スクリプトの実行には、cytoscape のインストールと cyRest の追加が必要になります。
Cytoscape / cyRESTとpy2cytoscapeを用いたIPython Notebook上でのグラフ解析と可視化 Part 1 - Qiita が参考になりましたのでそちらをご参照ください。


作成したスクリプト一式

Github上に一式をUpしました。
kemsakurai/py2cytoscape_example: Google Search Console から取得した検索キーワードを py2cytoscape を使って Network図に描画


実行方法

py2cytoscape_example/README.md at master · kemsakurai/py2cytoscape_example に記載しましたのでそちらをご確認ください。


実装の説明

以下、実装について説明します。
スクリプトは、export_keyword_network.py[メインスクリプト]、exportor.py[cytoscapeをhtmlにexportするスクリプト]の2つになります。

export_keyword_network.py

処理の流れ

処理の流れは以下の通りです。
1. キーワード文字列を取得
2. 共起単語行列を作成する
3. networkx 描画データを作成
4. 描画のための調整とHTMLへのExport

共起単語行列を作成

keywords.txtから読み込んだ内容を、CountVectorizer で共起単語行列に変換しています。
実装の内容は、Google Search Console の キーワードの、共起ネットワーク図を python で描画する | Monotalk と比較して変更はありません。
TfidfVectorizer のコメントアウトを外し、CountVectorizer をコメントアウトすれば、TfidfVectorizerによる共起単語行列が返却されます。
パラメータの調整はしっかり行なっていませんが、感覚的にはTfidfVectorizerによる判定のほうがいい感じに出力されましたので、よければそちらも試してみてください。

networkx 描画データを作成

  • ノードの大きさ、エッジの太さを図形描画に反映させる
    matplotlibで描画した際は、networkx のGraph ノード、エッジの属性に反映した weightscore をpython 上で描画時の線の太さ、円の大きさとして設定していました。
    cytoscape で html に出力する場合は、JS 経由での設定となるため大きさをコントロールする実装はpythno上には記載されていません。

  • 初期ノードの追加

        G = nx.from_scipy_sparse_matrix(
            Xc_norm, parallel_edges=True, create_using=nx.DiGraph(), edge_attribute='weight')
    
    上記で、nx.DiGraph() で有効グラフを設定しています。
    nx.Graph() にすると無効グラフになるので矢印がなくなるかもしれませんが、試しておりません。

  • エッジと、ノードの削除

        if d["weight"] <= 0.0:
            G.remove_edge(u, v)
    
    で、エッジの削除、
       if a["score"] <= 10:
            G.remove_node(n)
    
    で、ノードの削除を行なっています。
    キーワード数が多いと、描画が遅くなりますので、上記のパラメータを変更してエッジとノードを削除してください。

描画のために調整と、HTMLへのExport

CyRestClient 経由で、cytoscape に描画リクエストを送付し、描画されたグラフをHTMLに Export します。
基本的な解説は、Cytoscape / cyRESTとpy2cytoscapeを用いたIPython Notebook上でのグラフ解析と可視化 Part 1 - Qiita に詳しく記載されています。
ここでは、個人的に実装をカスタマイズした部分について記載します。

  • レイアウトアルゴリズム について
    Cytoscope のplugin として追加も可能で、デフォルトでもいくつか選択ができます。
    Cytoscope が立ち上がっていれば、以下のURLを叩くと、使用可能なレイアウトアルゴリズムがJSON配列で取得できます。

    • URL
      http://localhost:1234/v1/apply/layouts
      
    • OUTPUT
      [
        "attribute-circle",
        "stacked-node-layout",
        "degree-circle",
        "circular",
        "attributes-layout",
        "kamada-kawai",
        "force-directed",
        "cose",
        "grid",
        "hierarchical",
        "fruchterman-rheingold",
        "isom",
        "force-directed-cl"
      ]
      
      アルゴリズムの違いでグラフ描画がどれくらいかわるのか試してみたかったので、使用可能なアルゴリズムを実装上複数指定しています。
          for layout_algorithm in ["attribute-circle", "stacked-node-layout", "degree-circle", "circular", "attributes-layout", "kamada-kawai", "force-directed", "cose", "grid", "hierarchical", "fruchterman-rheingold", "isom", "force-directed-cl"]:
      
  • HTMLのエクスポートについて
    py2cytoscape には、Jupyter NoteBook にグラフ描画するためのAPIが用意されていますが、HTMLのExportを行うAPIが見当たらなかったので、 py2cytoscape/viewer.py at develop · idekerlab/py2cytoscapeを参考に、 HTMLに出力して、マウスでぐりぐりグラフを操作したかったので、py2cytoscape_example/exporter.py at master · kemsakurai/py2cytoscape_example を作成しました。
    template.html の調整 と、python側で Jupyter NoteBook の API を呼び出していたのを削除するくらいで動作しました。

  • ノードの大きさ、エッジの幅を調整するには
    NetworkX のノードとエッジに設定したscoreweight は JSONデータ側に反映されます。
    これをスタイルに反映するためには、style.json内で、mapData関数を呼び出す必要があります。
    以下スクリプト内で、使用している style.json の抜粋になります。

  • style.json (default_style.json内の一部)

    {
      "format_version" : "1.0",
      "generated_by" : "cytoscape-3.5.1",
      "target_cytoscapejs_version" : "~2.1",
      "title" : "custermizedCurved",
      "style" : [ {
        "selector" : "node",
        "css" : {
          "border-opacity" : 1.0,
          "background-opacity" : 1.0,
          "font-size" : 14,
          "color" : "rgb(102,102,102)",
          "text-opacity" : 1.0,
          "background-color" : "rgb(254,196,79)",
          "width" : "mapData(score, 0, 500, 20, 60)",
          "text-valign" : "bottom",
          "text-halign" : "right",
          "height" : "mapData(score, 0, 500, 20, 60)",
          "font-family" : "SansSerif",
          "font-weight" : "normal",
          "shape" : "ellipse",
          "border-width" : 7.0,
          "border-color" : "rgb(255,255,255)",
          "content" : "data(name)"
        }
      }, {
        "selector" : "node:selected",
        "css" : {
          "background-color" : "rgb(255,255,0)"
        }
      }, {
        "selector" : "edge",
        "css" : {
          "content" : "",
          "text-opacity" : 1.0,
          "font-family" : "SansSerif",
          "font-weight" : "normal",
          "source-arrow-shape" : "none",
          "color" : "rgb(0,0,0)",
          "font-size" : 10,
          "line-color" : "rgb(255,255,255)",
          "opacity" : 1.0,
          "target-arrow-shape" : "triangle",
          "width" : "mapData(weight, 0, 2, 1, 8)",
          "source-arrow-color" : "rgb(255,255,255)",
          "line-style" : "solid",
          "target-arrow-color" : "rgb(255,255,255)"
        }
      }, {
        "selector" : "edge:selected",
        "css" : {
          "line-color" : "rgb(255,0,0)"
        }
      } ]
    }
    

  • ノードの大きさをコントロールしている箇所

        "width" : "mapData(score, 0, 500, 20, 60)",
    
        "height" : "mapData(score, 0, 500, 20, 60)"
    

  • エッジの幅をコントロールしている箇所

        "width" : "mapData(weight, 0, 2, 1, 8)",
    

  • mapDate() の引数の意味
    mapData の第一引数は、考慮する属性。
    第二、第三引数は属性が取り得る最小値、最大値。
    第四、第五引数はcss 属性に反映させる際の最小値、最大値を示しています。


まとめ

以下、cytoscape でグラフ描画した感想をまとめます。

  • matplotlib に比べるとアプリケーションのインストールが必要なので手間はかかる。

  • 出力されるグラフは個人的には、matplotlib よりも好き。

  • HTML、Javascript にエクスポートできるので出力したグラフは Webアプリケーションに組み込める。

直接マウスでグラフを操作できるのは、楽しいです。
ノードに対してクリックイベントをつけたりいろいろやれることはありそうに思いました。
以上です。

コメント