本文へスキップ
からだにいいもの

Rのトピックスを中心に『まだ、まだ、知らない、役に立つ情報?』を発信します。

Rで解析:グラフ構造をベクトルとして扱える「graphvec」パッケージの紹介

「graphvec」パッケージは、ベクトルの要素どうしのつながりをグラフとして保持し、ノード側からもエッジ側からも同じデータを扱えるようにします。集約の階層を表す仕組みも含みます。グラフを備えたデータを、ふだんのベクトル操作の延長で整理できるのではないかと考えます。

パッケージバージョンは0.1.0。Windows 11 x64 (build 26200)のR version 4.6.1で確認しています。

パッケージのインストール

下記コマンドを実行してください。

# パッケージのインストール
install.packages("graphvec")
# igraphオブジェクトへの変換で使うため一緒に導入する
install.packages("igraph")
# パッケージの読み込み
library("graphvec")
スポンサーリンク

コマンド例

詳細はコメント、パッケージのヘルプを確認してください。

graphvecには2通りのグラフベクトルがあります。node_vecはノード(要素)を並べ、エッジをその属性として持ちます。edge_vecはエッジを並べ、ノードのデータを属性として持ちます。edgesとnodesで両者を行き来でき、どちらから見ても同じグラフを指します。

もう1つが、agg_vecとagg_dfです。これは「合計とその内訳」のような集約の親子関係を1本のベクトルやテーブルで表します。集約された値は<aggregated>として表示され、is_aggregatedでどの要素が集約値かを取り出せます。

ここでは、京都府の農産物出荷を「府全体」とその内訳の地域で集約する構造と、宇治茶を集荷して小売へ届ける4拠点の輸送ネットワークを模した擬似データを共通データとして使用します。

# 農産物の地域区分(先頭の欠損は集約値「府全体」を表す)
地域名 <- c(NA, "山城", "丹波", "丹後")

# 各要素が集約値かどうか
地域集約 <- c(TRUE, FALSE, FALSE, FALSE)

# 宇治茶を集荷して小売へ届ける4つの拠点
拠点 <- c("和束産地", "宇治集荷場", "中京問屋", "祇園小売")

# 各拠点の種別
種別 <- c("産地", "集荷場", "問屋", "小売")

# 輸送区間の始点と終点(拠点ベクトルの位置で示す)
区間元 <- c(1L, 2L, 3L, 2L)
区間先 <- c(2L, 3L, 4L, 4L)

# 各区間の輸送量(トン)
輸送量 <- c(120, 120, 80, 40)

[集約ベクトルの作成]:agg_vecコマンド

agg_vecは、集約値とその内訳を1本のベクトルにまとめます。xに値を、aggregatedに各要素が集約値かどうかの論理ベクトルを渡します。集約値の位置はxを欠損にしておき、表示は<aggregated>になります。

オプション意味初期値
x値のベクトルcharacter()
aggregated各値が集約値かどうかを示す論理ベクトルlogical(NROW(x))
# 「府全体」を集約値、3地域をその内訳とする集約ベクトルを作る
地域 <- agg_vec(x = 地域名, aggregated = 地域集約)
地域
<agg_vec[4]>
[1] <aggregated> 山城         丹波         丹後
# 集約フラグを省くと、すべて集約なしの集約ベクトルになる
agg_vec(x = c("宇治茶", "九条ねぎ", "賀茂なす"))
<agg_vec[3]>
[1] 宇治茶   九条ねぎ 賀茂なす

[集約かどうかの判定]:is_aggregatedコマンド

is_aggregatedは、集約ベクトルの各要素が集約値かどうかを論理ベクトルで返します。agg_dfの列に対しても使え、集約値の行だけを絞り込むときの目印になります。

オプション意味初期値
x判定するオブジェクトなし
# 各要素が集約値かどうかを論理ベクトルで返す
is_aggregated(地域)
[1]  TRUE FALSE FALSE FALSE
# 集約ベクトル以外を渡すと、すべてFALSEになる
is_aggregated(c("宇治茶", "九条ねぎ"))
[1] FALSE FALSE

[集約テーブルの作成]:agg_dfコマンド

agg_dfは、複数のagg_vec列をまとめた集約テーブルを作ります。列ごとに集約する・しないを指定できるため、地域と品目のように複数の軸を掛け合わせた集約(府全体、品目別の府合計、地域別の合計など)を1つのテーブルで表せます。

オプション意味初期値
同じ長さの名前付きagg_vec列なし
# 地域と品目を掛け合わせた集約構造をテーブルにする
出荷 <- agg_df(
  地域 = agg_vec(c(NA, NA, "山城", "丹波"), c(TRUE, TRUE, FALSE, FALSE)),
  品目 = agg_vec(c(NA, "茶", NA, NA), c(TRUE, FALSE, TRUE, TRUE))
)
出荷
<agg_df[4]>
[1] <aggregated>:<aggregated> <aggregated>:茶
[3] 山城:<aggregated>         丹波:<aggregated>
# 列を取り出せば集約フラグを個別に確認できる
is_aggregated(出荷$地域)
[1]  TRUE  TRUE FALSE FALSE

[ノードに沿ったグラフベクトルの作成]:node_vecコマンド

node_vecは、ノードを並べたグラフベクトルを作ります。xにノードの値を渡し、fromとtoでエッジを(xの位置を指す整数で)指定します。「…」には輸送量のような名前付きのエッジ属性を渡せます。角かっこで一部を取り出すと、切れたエッジを落とした誘導部分グラフになります。

オプション意味初期値
xグラフのノードを表すベクトルlist()
fromエッジの始点となるノード位置の整数ベクトルinteger()
toエッジの終点となるノード位置の整数ベクトルinteger()
名前付きのエッジ属性ベクトル。エッジ数に合わせて再利用される。fromとtoは予約済みで属性名に使えないなし
directed単一の論理値。エッジをfrom→toの向きとみなすか、対称とみなすかTRUE
# 拠点をノード、輸送区間をエッジとするグラフベクトルを作る
経路 <- node_vec(
  x = 拠点,
  from = 区間元,
  to = 区間先,
  輸送量 = 輸送量
)
経路
<node_vec[4]>
[1] 和束産地   宇治集荷場 中京問屋   祇園小売
# 集荷場から下流の3拠点だけを取り出す(誘導部分グラフ)
経路[2:4]
<node_vec[3]>
[1] 宇治集荷場 中京問屋   祇園小売

[エッジに沿ったグラフベクトルの作成]:edge_vecコマンド

edge_vecは、エッジを並べたグラフベクトルを作ります。fromとtoにノード番号を、nodesにノードのデータ(データフレームも可)を渡します。エッジ属性は「…」で、node_vecと同じく名前付きで指定します。$でエッジ属性やノードのデータをエッジの並び順で取り出せます。

オプション意味初期値
fromエッジの始点となるノード番号の整数ベクトルinteger()
toエッジの終点となるノード番号の整数ベクトルinteger()
名前付きのエッジ属性ベクトル。エッジ数に合わせて再利用される。fromとtoは予約済みで属性名に使えないなし
nodesノードデータのベクトル。大きさはfromとtoの最大値以上にするdata.frame()
directed単一の論理値。エッジをfrom→toの向きとみなすか、対称とみなすかTRUE
# 輸送区間をエッジ、拠点の属性をノードデータとするグラフベクトルを作る
区間 <- edge_vec(
  from = 区間元,
  to = 区間先,
  輸送量 = 輸送量,
  nodes = data.frame(名称 = 拠点, 種別 = 種別)
)
区間
<edge_vec[4]>
[1] [和束産地:産地]->[宇治集荷場:集荷場] [宇治集荷場:集荷場]->[中京問屋:問屋]
[3] [中京問屋:問屋]->[祇園小売:小売]     [宇治集荷場:集荷場]->[祇園小売:小売]
# $でエッジ属性とノードのデータを取り出す
区間$輸送量
[1] 120 120  80  40

区間$from$名称
[1] "和束産地"   "宇治集荷場" "中京問屋"   "宇治集荷場"

[エッジ視点への並べ替え]:edgesコマンド

edgesは、グラフベクトルをエッジ視点へ並べ替え、edge_vecとして返します。node_vecを渡すと、ノードの並びをエッジの並びに置き換えたものになります。輸送量などのエッジ属性は並べ替えても保持されます。

オプション意味初期値
xnode_vecまたはedge_vecなし
メソッドへ渡す追加のオプションなし
# ノード視点のグラフベクトルをエッジ視点へ並べ替える
edges(経路)
<edge_vec[4]>
[1] [和束産地  ]->[宇治集荷場] [宇治集荷場]->[中京問屋  ]
[3] [中京問屋  ]->[祇園小売  ] [宇治集荷場]->[祇園小売  ]
# 並べ替えても輸送量などのエッジ属性は保持される
edges(経路)$輸送量
[1] 120 120  80  40

[ノード視点への並べ替え]:nodesコマンド

nodesは、グラフベクトルをノード視点へ並べ替え、node_vecとして返します。edgesと対になっており、nodes(edges(x))のように重ねるともとのノード集合に戻ります。どちらの視点でも同じグラフを指すため、扱いやすい向きを選べます。

オプション意味初期値
xnode_vecまたはedge_vecなし
メソッドへ渡す追加のオプションなし
# エッジ視点のグラフベクトルをノード視点へ並べ替える
nodes(区間)
<node_vec[4]>
[1] 和束産地:産地     宇治集荷場:集荷場 中京問屋:問屋     祇園小売:小売
# nodesとedgesは互いに逆変換で、もとのノード集合に戻る
nodes(edges(経路))
<node_vec[4]>
[1] 和束産地   宇治集荷場 中京問屋   祇園小売

[igraphオブジェクトへの変換]:as.igraphコマンド

as.igraphは、グラフベクトルをigraphパッケージのグラフオブジェクトへ変換します。渡すのはグラフの構造(ノードとエッジ)で、変換後はigraphの各種コマンドで中心性や経路などを調べられます。node_vecとedge_vecのどちらからでも同じ構造が得られます。

オプション意味初期値
xnode_vec、agg_vec、agg_df、edge_vecのいずれかのオブジェクトなし
追加のオプション(現状は未使用)なし
# igraphパッケージを読み込む
library("igraph")

Attaching package: 'igraph'

The following object is masked from 'package:graphvec':

    edges

The following objects are masked from 'package:stats':

    decompose, spectrum

The following object is masked from 'package:base':

    union

# 経路をigraphオブジェクトへ変換する
g <- as.igraph(経路)
# ノード数とエッジ数を数える
c(vcount(g), ecount(g))
[1] 4 4
# igraphのコマンドで解析する(拠点ごとの出次数)
degree(g, mode = "out")
[1] 1 2 1 0

この記事が誰かの役に立ちますように。

スポンサーリンク
価格および配送状況は変更される場合があります。購入時は商品ページをご確認ください。
当サイトに表示されている商品情報はAmazonから提供されたものであり、更新または削除される場合があります。
karada-goodはAmazonアソシエイトとして、適格販売により収入を得ています。