11.22.2015

Finding Community Structure in a Big Graph

C++: ビッググラフにおけるコミュニティ抽出のメモ

 

手法

ネットワークにおけるコミュニティ抽出 (グラフのクラスタリング) にはいくつかの手法がある。

こちらを参照 => R seminar on igraph

スパースなグラフに対する Non-overlapping で最も高速なのは、貪欲アルゴリズムを用いた手法 (O(n (log n)^2))。
今回はこちらを採用。

 

実装

R であれば igraph – Network analysis software に既に実装がある。

Python の NetworkX では過去に議論された形跡が見られるものの、取り込まれる見込みは薄そうだ。

GraphX には、もちろん無い。

今回はとにかく消費メモリを節約したかったので、論文作者本人が公開している C++ の実装を使うことにする。

 

ビルド

上記の URL で公開されているソースコードをビルドする。(ライセンスが GPL なので注意)

コンパイルオプションなどが今日のコンパイラに追随していなかったので、若干の修正を要した。

  • Makefile (-fforce-mem オプション削除)
@@ -8,7 +8,7 @@

 # compiler name and flags
 CCC = g++
-CCFLAGS = -O3 -fomit-frame-pointer -funroll-loops -fforce-mem -fforce-addr -fexpensive-optimizations
+CCFLAGS = -O3 -fomit-frame-pointer -funroll-loops -fforce-addr -fexpensive-optimizations

 # loader flags
 LDFLAGS =
  • fastcommunity_mh.cc (iostream.h -> iostream, string.h 追加)
@@ -71,12 +71,13 @@
 //
 ////////////////////////////////////////////////////////////////////////

-#include <iostream.h>
+#include <iostream>
 #include <fstream>
 #include <string>
 #include "stdlib.h"
 #include "time.h"
 #include "math.h"
+#include "string.h"

 #include "maxheap.h"
 #include "vektor.h"
  • maxheap.h (iostream.h -> iostream, namespace std 追加)
@@ -40,7 +40,8 @@
 #if !defined(MAXHEAP_INCLUDED)
 #define MAXHEAP_INCLUDED

-#include <iostream.h>
+#include <iostream>
+using namespace std;

 /*   Because using this heap requires us to be able to modify an arbitrary element's
        data in constant O(1) time, I use to tricky tactic of having elements in an array-
  • vektor.h (iostream.h -> iostream)
@@ -30,7 +30,7 @@
 #if !defined(vektor_INCLUDED)
 #define vektor_INCLUDED

-#include <iostream.h>
+#include <iostream>

 #if !defined(vektor_INCLUDED)
 #define vektor_INCLUDED

その後、ディレクトリ内で make コマンドを行えば、実行ファイル FastCommunityMH が生成される。

 

実行

まずは有名(?)な空手クラブの派閥争いのデータで動作確認してみる。

$ curl -O http://tuvalu.santafe.edu/~aaronc/hierarchy/karate.pairs
$ ./FastCommunity_GPL_v1.0.3/FastCommunityMH -f ./karate.pairs -l firstRun

以下の 2ファイルが成果物としてカレントディレクトリに出力される。

FASTCOMMUNITY_INFERENCE_ALGORITHM
START-----:     Sun Nov 22 01:54:13 2015
---FILES--------
D_IN------:     ./
D_OUT-----:     ./
F_IN------:     karate.pairs
F_JOINS---:     karate-fc_firstRun.joins
F_INFO----:     karate-fc_firstRun.info
---NET_STATS----
MAXID-----:     34
NUMNODES--:     34
NUMEDGES--:     78
---MODULARITY---
MAXQ------:     0.383136
STEP------:     32
EXIT------:     Sun Nov 22 01:54:13 2015
-1      -1      -0.0498028      0
17      6       -0.0376397      1
6       7       -0.0139711      2
7       1       -0.00147929     3
5       1       0.0177515       4
11      1       0.0490631       5
27      30      0.0612262       6
30      34      0.0784845       7
24      34      0.0946746       8
28      34      0.111111        9
26      25      0.123192        10
25      32      0.145874        11
13      4       0.157709        12
22      2       0.16905 13
31      9       0.180227        14
9       33      0.196992        15
10      3       0.208169        16
18      2       0.219181        17
12      1       0.229372        18
8       4       0.239563        19
4       3       0.253369        20
14      3       0.269149        21
2       3       0.289448        22
29      32      0.29931 23
32      34      0.311144        24
23      33      0.320513        25
19      33      0.329553        26
21      33      0.338264        27
33      34      0.349359        28
16      34      0.362837        29
15      34      0.375986        30
1       20      0.380671        31
20      3       0.383136        32

この *.joins ファイルを追っていけば、Q値の推移、検出されたクラスタの状態を把握することができる。

-c オプション(特定ステップ時点の状態をファイルに出力)や -v --v オプション(詳細表示)も約に立つが、その度に全データの再計算が行われてしまうので、ビッググラフでは扱いづらい。

ノード数が増えたら、*.joins ファイルを解析するためのツールを作る必要があるだろう。

 

ビッググラフへの適用

300万ノード、1300万エッジのグラフに対して、上記のプログラムを実行してみた。

期待どおりメモリ使用量は 10GB 以内とかなり少なく抑えられている。

しかし、並列処理には向いていないアルゴリズムなので、それなりの実行時間はかかりそう。
おそらく、完了までは10日程度を要するであろう。

0 件のコメント:

コメントを投稿