こんにちは。スタメンでエンジニアインターンをしております河井と申します。 本記事では、TUNAGにおけるユーザーネットワークの可視化の取り組みについて紹介いたします。
はじめに
弊社ではTUNAGという社内制度をコミュニケーションの起点とする社内SNSを開発しています。
TUNAG から社内制度を利用すると Facebook のような タイムライン に、制度を利用したことが共有されます。 そして同じ社内のユーザーは投稿に対してコメントやスタンプなどで コミュニケーションを取ることができます。
投稿とそれに付くコメントは社内での人間関係をある程度反映しているとの仮説と、 交流の度合いをひと目で確認できると嬉しいというニーズから、ネットワーク図に落とし込んで可視化しようと考えました。
使用ツールについて
今回はRとigraphを用います。 igraphはネットワーク解析・可視化用のライブラリで、R、Python、C/C++で使うことができます。 将来はサービスに組み込みたいと考えていますが、まずは手元で簡単に実行できるという理由で今回の組み合わせを選定しました。
実装の詳細
対象とする入力
ネットワーク(グラフ)はノード(点)とリンク(ノードを結ぶ線)で構成されています。 今回で言えば、ノードはユーザーリスト、リンクはコメントのリストです。 igraphに渡すデータとして、ノードとリンクでそれぞれCSVを作成します。具体的には以下に示すような形になっています。
- nodes.csv
id | name | department_id |
---|---|---|
1 | Alice | 1 |
2 | Bob | 1 |
- links.csv
from | to | weight |
---|---|---|
1 | 2 | 1 |
2 | 1 | 1 |
テーブルのヘッダーの内容は以下のとおりです。
id
:ユーザーID
name
:ユーザー名
department_id
:所属部署のID
from
:コメントをしたユーザーのID
to
:投稿にコメントをもらったユーザーのID
weight
:コメント数。テーブル作成時はすべて1とし、後で集計します。
以上のようなCSVを2018年の6、7、8月と1ヶ月ごとに作成しました。
データの読み込みからプロットまで
まずパッケージとCSVをファイルを読み込みます。
library(igraph) nodes <- read.csv('nodes.csv', header = T) links <- read.csv('links.csv', header = T)
次に取り込んだデータの前処理です。
links <- aggregate(links[3], links[-3], sum) net <- graph.data.frame(d=links, vertices=nodes, directed=T) net <- simplify(net, remove.multiple = F, remove.loops = T)
- 1行目 `aggregate(links[3], links[-3], sum)`では、`links`の3列目(`weight`)について、`links`の3列目以外(`from`と`to`)が一致するもの同士を足し合わせる(`sum`)という操作をしています。
2行目 graph.data.frame()にリンクとノードの情報を渡してグラフオブジェクトを作成します。
3行目 今回、自分の投稿へのコメント情報は不要なため省略したいです。 自身に対するリンクをもたず、かつ同じノード間に複数のリンクをもたないグラフを単純グラフといい、任意のグラフを単純グラフ化する関数である`simplify()`を適応しています。
ネットワークをプロットする前に、図の設定をしておきます。
# ノードの設定 V(net)$size <- 4 V(net)$color <- V(net)$department.id # 所属部署で色分け V(net)$frame.color <- 'white' V(net)$label = NA # ラベル非表示
# リンクの設定 E(net)$width <- E(net)$weight/5 # コメント数に応じてリンクの太さを変える E(net)$arrow.size <- 0.2 edge.start <- ends(net, es=E(net), names=F)[,1] E(net)$color <- V(net)$color[edge.start] # リンクをコメントしたユーザーの所属部署の色に
最後にプロットです。
set.seed(1) plot(net, layout=layout_with_fr)
ネットワーク図のレイアウトを決めるためにFruchterman-Reingoldアルゴリズムを採用しました。力学モデルと呼ばれる計算方法の一種で、繋がりのあるノードほど近くに配置されるようになります。結果として、密に繋がっているノードが中心近くに集まります。
結果
1ヶ月ごとのコメントを可視化した結果は以下のようになりました。 ノードは各ユーザーに相当し、その色は所属部署を示しています。 リンクの色はコメントを送ったユーザーと同じ色を示しており、リンクの太さはコメントを送った数に比例して太くなっています。
6月
7月

8月
考察
上の図はスタメン社内のデータを可視化したものになります。 図から読み取れることとして、
- 黃、緑、ピンク、水色の部署は横断的にコミュニケーションをとっている
- オレンジのグループは中心の集団から少しずれた場所にいる
- 最初遠くにいたノードが時間の経過とともに中心に寄ってきている(離れているノードもありますが。。)
などがあります。 さらに、追加的な情報を使うことでもう少し込み入った考察をすることができます。
6月の時点で外側にいる青色のノードは内定者です。 7月になると、6月の塊はほぼそのままで外側に新たなノードが出現します。(2つのオレンジのノードと1つの青色のノード) こちらも7月にTUNAGに登録した内定者です。 8月になると、6月7月時点で遠くにいたノードが中心の集団に近づいていることがわかると思います。 近づいているということは繋がりが生まれているということなので、順調に社内に馴染んできていると言えるのではないでしょうか。
このようにネットワーク図を社内コミュニケーションのスナップショット的に毎月取得していくと、新しいメンバーが最初は遠くにいたところから近づいて来ているか、部署をまたいだ交流があるかどうか、などを分析することができます。
まとめと展望
今回はRとigraphでネットワークの可視化を行いました。 TUNAG上でのコミュニケーションは決して現実のコミュニケーションと等価ではないですが、コメントのみでその実態を反映できている可能性が示されました。
また今回は触れませんでしたが、ネットワーク解析という分野では、ネットワークのつながりの度合いやコミュニティで影響力の強い人物などを定量的に求めることができるので、今後はそのような分析も行っていきたいと思います。
最後に今回用いたコードをまとめておきます。
library(igraph)nodes <- read.csv('nodes.csv', header = T) links <- read.csv('links.csv', header = T)
links <- aggregate(links[3], links[-3], sum) net <- graph.data.frame(d=links, vertices=nodes, directed=T) net <- simplify(net)
V(net)$size <- 4 V(net)$color <- V(net)$department_id V(net)$frame.color <- 'white' V(net)$label = NA
E(net)$width <- E(net)$weight/5 E(net)$arrow.size <- 0.2 edge.start <- ends(net, es=E(net), names=F)[,1] E(net)$color <- V(net)$color[edge.start]
set.seed(1) plot(net, layout=layout_with_fr)