さんごー日記。

映画や本やゲームの感想をゆるく記録したり、プログラミングの勉強をゆるく記録するゆるい日記です。

Rのigraphライブラリの使い方メモ

Rのigraphというライブラリの使い方について、日本語の資料が少ないような気がするので調べた事をメモしておく。

「入門 機械学習」のソーシャルグラフ解析の章で出てきたのだけど、subgraphという関数がマトモに動いてくれなくて困った。

subgraphについて触れてる日本語資料を探したり、英語の資料を翻訳して読んでみたりしつつ、

基本的な使い方やライブラリで使っているデータの構造についても理解を深めていきたい。

 

 

igraphの概要

↓igraphパッケージの公式らしきサイト。

Welcome to igraph's new home

 

igraphはネットワーク解析を効率的に行うためのツールの集まり。とのこと。

R、python、Cのパッケージが作られているようです。

 

igraphの関数リスト

igraphにはたくさんのライブラリ関数が含まれている。

以下のページで一覧を見れます。800個以上あるみたいです。

igraph R manual pages

 

これだけあったら自分が知りたい関数についての記事が都合よく見つからないわけだ。

igraphの利用者も少ないだろうし。

基本的な所を一つずつ見ていくとしよう。

 

igraphクラス

igraphはigraphクラスという特殊なクラスを持っています。

igraphパッケージに含まれる関数を使って様々な形のソーシャルグラフを作る事ができるようです。

「make_〇〇」という名前の関数で作れます。

 

igraphクラス型のグラフを作る関数

全部試してないけど以下のものがigraph形式のグラフを作る関数のようです。

  • make_ … Make a new graph
  • make_bipartite_graph … Create a bipartite graph
  • make_chordal_ring … Create an extended chordal ring graph
  • make_clusters … Creates a communities object.
  • make_de_bruijn_graph … De Bruijn graphs
  • make_directed_graph  …  Create an igraph graph from a list of edges, or a notable graph
  • make_ego_graph … Neighborhood of graph vertices
  • make_empty_graph …  A graph with no edges
  • make_full_bipartite_graph  … Create a full bipartite graph
  • make_full_citation_graph  … Create a complete (full) citation graph
  • make_full_graph  … Create a full graph
  • make_graph  … Create an igraph graph from a list of edges, or a notable graph

 

いくつか試してみます。

 

make_ring()

make_ring()とかは分かりやすいですね。輪っかに繋がった形のグラフを生成します。

以下実行例。

> g <- make_ring(10)
> plot(g)

f:id:thirtyfive:20170818233956p:plain

 

make_star()

星型のグラフを作ります。mode引数にin、outを指定すると有向グラフになります。

modeに"undirected"を指定すると無向グラフになります。

> g <- make_star(10, mode = "out")
> plot(g)

f:id:thirtyfive:20170818234408p:plain

 

make_tree()

ツリー型のグラフを作ります。枝分かれするノードの数を指定するようです。

> g <- make_tree(10, 2)
> plot(g)

f:id:thirtyfive:20170818234949p:plain

 

他にもいろいろありますが、とりあえずこんな感じ。

 

igraphのグラフの確認方法いろいろ

グラフ情報の表示

グラフを格納した変数名を打ち込むと、グラフの情報がサマリーで表示されます。

> g <- make_tree(10, 2)

> g
IGRAPH 2e34d33 D--- 10 9 -- Tree
+ attr: name (g/c), children (g/n), mode (g/c)
+ edges from 2e34d33:
[1] 1-> 2 1-> 3 2-> 4 2-> 5 3-> 6 3-> 7 4-> 8 4-> 9 5->10

 このフォーマットのルールを知らないと読めないので、ルールを簡単にメモしておきます。

 

まず1行目の以下の部分を分解して見ていきます。

IGRAPH 2e34d33 D--- 10 9 -- Tree

  • 「IGRAPH」 … igraphである事を表す。
  • 2e34d33 … よくわからない。
  • D--- … グラフの種類を表す4つ文字。1つめは無向グラフ「U」、または有向グラフは「D」を示す。2つ目は頂点に名前がついているかどうかで、名前付きなら「N」、そうでなければ「-」。3つ目は重みエッジ属性が設定されているかどうかで、重み付けされていれば「W」、そうでなければ「-」。4つ目は2部グラフかどうかで、2部グラフなら「B」、そうでなければ「-」となります。
  • 10 9 … グラフの頂点の数と、辺の数。
  • -- … グラフの名前があれば表示される。
  • Tree … グラフの形式を表す文字。

 

以下のページを参考にしました。

igraph R manual pages

 

次に2行目の以下の部分を分けて見ていきます。

+ attr: name (g/c), children (g/n), mode (g/c)

  •  + attr: … オプションの属性を表示しますよ。というような意味だと思う。
  • name (g/c) … name属性の種類と型を表している。gはグラフ、cは文字列を表す。種類はgの他にv(頂点)、e(エッジ)がある。型はn(数値)、l(論理値)、x(その他)がある。
  • children (g/n) … children属性の種類と型を表している。gはグラフ、bは数値を表す。
  • mode (g/c) … mode属性の種類と肩を表している。gはグラフ、cは文字列を表している。

あんまり役に立つ情報じゃないようなきがする…

以下のページを参考にしました。

igraph R manual pages

 

グラフの属性を見る(graph_attr_names)

graph_attr_names()関数を使ってグラフの属性リストを取得できます。

> g <- make_tree(10, 2)
> graph_attr_names(g)
[1] "name" "children" "mode"  

 

この木構造型のグラフにはname、children、modeという3つの属性がある事が分かります。

各属性の値を見るには以下のようにします。

> g$name
[1] "Tree"
> g$children
[1] 2
> g$mode
[1] "out"

 

グラフの頂点リストを取得する(V)

頂点(vertices)のリストを見るには以下のようにします。

> g <- make_tree(10, 2)
> V(g)
+ 10/10 vertices, from 2e34d33:
[1] 1 2 3 4 5 6 7 8 9 10

この例では1~10の数字が割り振られた10個の頂点がある事が分かります。 

 

グラフのエッジリストを取得する(E)

エッジのリストを見るには以下のようにします。

> g <- make_tree(10, 2)

> E(g)
+ 9/9 edges from 2e34d33:
[1] 1-> 2 1-> 3 2-> 4 2-> 5 3-> 6 3-> 7 4-> 8 4-> 9 5->10

 9個のエッジがある事が分かります。

 

頂点IDとエッジID

igraphには頂点とエッジに固有のIDというものが割り振られています。

頂点IDは常に1から始まる連続した数値になります。

頂点IDは1から始まります。

頂点に名前をつけると、その後は名前で頂点にアクセスすることが出来るようになります。(逆に名前を付けてしまうとIDは分からなくような気がするが、基本的にはどの関数でも頂点に名前でアクセスできるので困らないようです。)

 

サブグラフ

ソーシャルグラフの1部分を抜き出して新しいグラフを作ることができます。

これをサブグラフと呼ぶようです。

induced_subgraph()という関数でサブグラフを生成することが出来ます。

> g <- make_ring(10)
> g2 <- induced_subgraph(g, 1:7)

 

以下plotの結果。

> plot(g)

f:id:thirtyfive:20170819225527p:plain

 

> plot(g2)

f:id:thirtyfive:20170819225459p:plain

 

induced_subgraph()のエラー

余談ですが、「入門 機械学習」という本に掲載されているRのサンプルコードがエラーを吐いてしまい動かなくて困っていました。

「11章 ソーシャルグラフの分析」の以下のコードです。

> user.ego <- subgraph(user.net, c(0, neighbors(user.net, user, mode = "out")))

subgraph(user.net, c(0, neighbors(user.net, user, mode = "out"))) でエラー:
At iterators.c:759 : Cannot create iterator, invalid vertex id, Invalid vertex id

 

このエラーの原因は単純で、サブグラフの生成条件として渡している頂点のIDが元のグラフには存在しないという事を意味しています。

こうすると動くと思います。

user.ego <- subgraph(user.net, c(0, neighbors(user.net, user, mode = "out")))

↓「0, 」の所を消す

user.ego <- subgraph(user.net, c(neighbors(user.net, user, mode = "out")))

 

なんで0って入れてたんでしょうね。igraphの昔のバージョンは動いていたのだろうか。

ここでけっこうハマってしまいました。

 

隣接ノードの抽出(neighbors)

neighbors()という関数を使って、指定したノードに隣接するノードのリストを取得できる。

隣接しているノードの方向を指定することもできます。

> g <- make_ring(10)
> neighbors(g,1)
+ 2/10 vertices, from 50c1642:
[1] 2 10

リング上のグラフで試すと、1のノードの左右に繋がっているノードのインデックスとして「2」と「10」が返ってきているのが分かります。

 

全てのノード間の最短距離を取得する

shortest.paths()を使うと、グラフに含まれる全てのノードのお互いの距離を得る事ができます。

出力はn×nの行列になります。

> g <- make_ring(10)

> shortest.paths(g)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 0 1 2 3 4 5 4 3 2 1
[2,] 1 0 1 2 3 4 5 4 3 2
[3,] 2 1 0 1 2 3 4 5 4 3
[4,] 3 2 1 0 1 2 3 4 5 4
[5,] 4 3 2 1 0 1 2 3 4 5
[6,] 5 4 3 2 1 0 1 2 3 4
[7,] 4 5 4 3 2 1 0 1 2 3
[8,] 3 4 5 4 3 2 1 0 1 2
[9,] 2 3 4 5 4 3 2 1 0 1
[10,] 1 2 3 4 5 4 3 2 1 0

 

 

随時追記していこうと思います。