{Rcpp}が支えるパッケージは非常に多く、全てを紹介するには時間が足りない。そこで「{Rcpp}と関わりがあり、他のパッケージと依存度が高いもの」を紹介しておいた方がよい有用なパッケージと考え、それらの代表的なパッケージを選定する。
選定方法はパッケージのReverse dependenciesからグラフを構築し、コミュニティ抽出と抽出されたコミュニティでHUB値の高いものを代表的なパッケージとして紹介する。
ここではコミュニティ外で関係性を考慮するため、HUB値の計算はコミュニティ抽出後のグラフではなく、最初に構築したグラフで行っている。
なお、コミュニティ検出とHUB値の算出には{igraph}を利用した。
参考ページ
{Rcpp}
Rcpp: Seamless R and C++ Integration
Rcpp: Seamless R and C++ Integration - Overview -by Dirk Eddelbuettel
Rcppのすすめ
Rcpp 入門
{igraph}
igraph: Network Analysis and Visualization
R igraph manual pages
Rによるネットワーク分析
Network visualization with R
visNetwork, an R package for interactive network visualization
Rでウイスキー分析(2/3) ネットワーク分析
Application of PageRank algorithm to analyze packages in R
SET_LOAD_LIB <- c("knitr", "dplyr", "igraph", "miniCRAN", "visNetwork")
sapply(X = SET_LOAD_LIB, FUN = library, character.only = TRUE, logical.return = TRUE)
## knitr dplyr igraph miniCRAN visNetwork
## TRUE TRUE TRUE TRUE TRUE
knitr::opts_chunk$set(comment = NA)
# 対象とするパッケージ名
SET_TARGET_PACKAGE <- "Rcpp"
# パッケージリストを用いるCRANリポジトリ
# 再現性を持たせるため、スナップショットを指定
SET_PACKAGE_REPOSITRY <- "https://mran.revolutionanalytics.com/snapshot/2016-08-13/"
# 次数による頂点除外用の閾値
SET_DEGREE_THRESHOLD <- 1
# 各コミュニティ内のスコア上位Xまでを抽出
SET_COMMUNITY_TOP_N <- 5
{Rcpp}が依存するパッケージを確認
pdb <- miniCRAN::pkgAvail(repos = c(CRAN = SET_PACKAGE_REPOSITRY))
dplyr::as_data_frame(pdb) %>%
dplyr::select(Package, Version, Depends, Imports, LinkingTo, Suggests, Enhances) %>%
head(n = 10) %>%
knitr::kable(format = "markdown")
Package | Version | Depends | Imports | LinkingTo | Suggests | Enhances |
---|---|---|---|---|---|---|
A3 | 1.0.0 | R (>= 2.15.0), xtable, pbapply | NA | NA | randomForest, e1071 | NA |
abbyyR | 0.5.0 | R (>= 3.2.0) | httr, XML, curl, readr, progress | NA | testthat, rmarkdown, knitr (>= 1.11) | NA |
abc | 2.1 | R (>= 2.10), abc.data, nnet, quantreg, MASS, locfit | NA | NA | NA | NA |
ABCanalysis | 1.1.1 | R (>= 2.10) | Hmisc, plotrix | NA | NA | NA |
abc.data | 1.0 | R (>= 2.10) | NA | NA | NA | NA |
abcdeFBA | 0.4 | Rglpk,rgl,corrplot,lattice,R (>= 2.10) | NA | NA | LIM,sybil | NA |
ABCoptim | 0.13.11 | NA | NA | NA | NA | NA |
ABCp2 | 1.2 | MASS | NA | NA | NA | NA |
abcrf | 1.3 | R(>= 2.10.0) | MASS, randomForest, parallel, foreach, doParallel, doRNG | NA | NA | NA |
abctools | 1.0.4 | R (>= 2.10), abc, abind, parallel, plyr | NA | NA | ggplot2, abc.data | NA |
# 依存パッケージ一覧
miniCRAN::pkgDep(
pkg = SET_TARGET_PACKAGE, availPkgs = pdb,
depends = TRUE, suggests = TRUE, enhances = TRUE
)
[1] "Rcpp" "RUnit" "inline" "rbenchmark" "highlight"
[6] "pkgKitten"
# 依存構造を可視化
plot(
miniCRAN::makeDepGraph(
pkg = SET_TARGET_PACKAGE, availPkgs = pdb, suggests = TRUE, enhances = TRUE
)
)
{Rcpp}に依存するパッケージを抽出
{miniCRAN}では{Rcpp}が依存するパッケージは出せても{Rcpp}に依存するパッケージが抽出できなかったので、ここでは{pacman}を利用した
depends_reverse_pkgs <- pacman::p_depends_reverse(
package = SET_TARGET_PACKAGE, local = FALSE, character.only = TRUE
)
str(object = depends_reverse_pkgs)
List of 4
$ Depends : chr [1:129] "AdaptiveSparsity" "Amelia" "ASPBay" "BaBooN" ...
$ Imports : chr [1:572] "AbsFilterGSEA" "accelerometry" "acebayes" "ACEt" ...
$ LinkingTo: chr [1:719] "AbsFilterGSEA" "accelerometry" "acebayes" "ACEt" ...
$ Suggests : chr [1:9] "crmPack" "cxxfunplus" "devtools" "hyperSpec" ...
# {Rcpp}に依存するパッケージリスト({Rcpp}を加える)
rcpp_pkgs <- c(SET_TARGET_PACKAGE, unique(x = unlist(x = depends_reverse_pkgs)))
# {Rcpp}に依存するパッケージリストをグラフ化
rcpp_pkgs_dg <- miniCRAN::makeDepGraph(
pkg = rcpp_pkgs, suggests = TRUE, enhances = TRUE, availPkgs = pdb
)
# 試しにグラフ可視化するが、{igraph}だと頂点が多すぎてプロットの枠に収まらない
plot(rcpp_pkgs_dg)
# Reverse dependenciesに限定
rcpp_pkgs_dg <- rcpp_pkgs_dg %>%
igraph::delete_vertices(
v = setdiff(
x = igraph::as_data_frame(x = rcpp_pkgs_dg, what = "vertices")$name,
y = rcpp_pkgs
)
)
# それでもプロットしきれない
plot(rcpp_pkgs_dg)
前述の通り、{Rcpp}が支えるパッケージはとても多かったので、ネットワーク分析の手法を用いて絞り込んだ。
# 次数が小さい頂点を除去
rcpp_pkgs_dg <- rcpp_pkgs_dg %>%
igraph::delete_vertices(
v = rcpp_pkgs_dg %>%
igraph::vertex_attr(
name = "name",
index = igraph::V(graph = rcpp_pkgs_dg)[
igraph::centr_degree(graph = rcpp_pkgs_dg)$res <= SET_DEGREE_THRESHOLD
]
)
)
# 焼きなまし法でコミュニティ抽出
rcpp_com <- igraph::spinglass.community(graph = rcpp_pkgs_dg)
rcpp_membership <- igraph::membership(communities = rcpp_com)
# HITSアルゴリズムのHUB値を算出
rcpp_dg_hub_score <- igraph::hub_score(graph = rcpp_pkgs_dg)$vector
# ネットワーク分析の結果をJOIN
rcpp_members <- dplyr::left_join(
x = dplyr::data_frame(
pkgname = names(x = rcpp_membership),
membership = as.integer(x = rcpp_membership)
) %>%
dplyr::mutate(
type = dplyr::case_when(
is.element(el = .$pkgname, set = depends_reverse_pkgs$Depends) ~ "Depends",
is.element(el = .$pkgname, set = depends_reverse_pkgs$Imports) ~ "Imports",
is.element(el = .$pkgname, set = depends_reverse_pkgs$LinkingTo) ~ "LinkingTo",
is.element(el = .$pkgname, set = depends_reverse_pkgs$Suggests) ~ "Suggests",
TRUE ~ ""
)
),
y = dplyr::data_frame(
pkgname = names(x = rcpp_dg_hub_score),
hub_score = as.numeric(x = rcpp_dg_hub_score)
),
by = c("pkgname" = "pkgname")
) %>%
dplyr::arrange(dplyr::desc(x = hub_score))
# Reverse dependenciesを基にグラフ構築
# ターゲットとなる{Rcpp}は対象となる全パッケージを参照しており、HUB値が高い
DT::datatable(
data = rcpp_members %>%
dplyr::mutate(
membership = as.factor(x = membership),
type = as.factor(x = type)
),
rownames = FALSE, filter = "top"
)
# 集計
rcpp_members %>%
dplyr::group_by(membership) %>%
dplyr::summarize(
memmber_cnt =n(),
mean_hub_score = mean(hub_score)
) %>%
knitr::kable(format = "markdown")
membership | memmber_cnt | mean_hub_score |
---|---|---|
1 | 3 | 0.0006937 |
2 | 258 | 0.0039030 |
3 | 6 | 0.0006108 |
4 | 6 | 0.0005895 |
5 | 10 | 0.0006221 |
6 | 16 | 0.0014286 |
7 | 70 | 0.0010892 |
8 | 6 | 0.0005223 |
9 | 12 | 0.0008648 |
10 | 3 | 0.0004625 |
11 | 13 | 0.0016364 |
12 | 41 | 0.0010966 |
13 | 15 | 0.0008164 |
14 | 173 | 0.0012901 |
15 | 4 | 0.0005345 |
16 | 31 | 0.0011771 |
17 | 3 | 0.0004823 |
18 | 59 | 0.0012348 |
{igraph}のplot
では対象が多すぎて可視化できなかったので{visNetwork}を用いて可視化(ネットワーク分析の結果を踏まえて可視化)
# {igraph}オブジェクトを{visNetwork}オブジェクトに変換
# ここで対象となるすべてのパッケージと依存関係があるRcppを取り除いておく
rcpp_network <- visNetwork::toVisNetworkData(
igraph = rcpp_pkgs_dg %>%
igraph::delete_vertices(v = c("Rcpp")),
idToLabel = TRUE
)
# 可視化用にコミュニティとHUB値をノードオブジェクトに付与
rcpp_network$nodes <- dplyr::left_join(
x = rcpp_network$nodes %>%
# Rcpp以外と依存関係がないパッケージをネットワークから取り除く
# rcpp_networkの作成でRcppの頂点を取り除いたことで孤立点となっている頂点が対象
dplyr::filter(
is.element(el = .$id, set = c(rcpp_network$edges$from, rcpp_network$edges$to))
),
y = rcpp_members %>%
dplyr::select(pkgname, group = membership, value = hub_score),
by = c("id" = "pkgname")
)
# ネットワーク可視化用にエッジの属性値を設定
rcpp_network$edges$arrows <- "middle"
rcpp_network$edges$smooth <- TRUE
rcpp_network$edges$shadow <- FALSE
rcpp_network$edges$title <- rcpp_network$edges$type
# label属性を与えておくと依存関係の種類がプロットされるが、煩雑になったので今回はコメントアウト
# rcpp_network$edges$label <- rcpp_network$edges$type
# color属性も上記と同様な理由でコメントアウト
# edge_type_palette <- leaflet::colorFactor(palette = "Dark2", domain = rcpp_network$edges$type)
# rcpp_network$edges$color <- edge_type_palette(x = rcpp_network$edges$type)
# 可視化
visNetwork::visNetwork(
nodes = rcpp_network$nodes, edges = rcpp_network$edges,
width = 900, height = 900
) %>%
visNetwork::visOptions(
highlightNearest = TRUE,
selectedBy = list(variable = "group")
)
rcpp_pkgs_intro_cand <- rcpp_members %>%
dplyr::filter(
pkgname != SET_TARGET_PACKAGE &
# HUB値の平均値を閾値に用いる
hub_score > mean(x = rcpp_members$hub_score)
) %>%
dplyr::group_by(membership) %>%
dplyr::mutate(member_cnt = n()) %>%
dplyr::top_n(n = SET_COMMUNITY_TOP_N, wt = hub_score) %>%
dplyr::arrange(membership, dplyr::desc(x = hub_score))
rcpp_pkgs_intro_cand %>%
knitr::kable(format = "markdown")
pkgname | membership | type | hub_score | member_cnt |
---|---|---|---|---|
geiger | 3 | Imports | 0.0036647 | 1 |
pROC | 4 | Imports | 0.0035368 | 1 |
RcppParallel | 6 | Suggests | 0.0190512 | 2 |
RSpectra | 6 | Imports | 0.0030412 | 2 |
RcppEigen | 7 | Imports | 0.0454681 | 5 |
lme4 | 7 | LinkingTo | 0.0112952 | 5 |
rstan | 7 | Imports | 0.0060563 | 5 |
minqa | 7 | Imports | 0.0035721 | 5 |
Rmixmod | 7 | Depends | 0.0032758 | 5 |
forecast | 8 | Imports | 0.0024432 | 1 |
bigmemory | 9 | Imports | 0.0051938 | 1 |
TAM | 11 | Imports | 0.0038349 | 5 |
sirt | 11 | Imports | 0.0038294 | 5 |
miceadds | 11 | Imports | 0.0030765 | 5 |
CDM | 11 | Imports | 0.0023015 | 5 |
mirt | 11 | Imports | 0.0023007 | 5 |
devtools | 12 | Suggests | 0.0095628 | 7 |
roxygen2 | 12 | Imports | 0.0094429 | 7 |
raster | 12 | Imports | 0.0094213 | 7 |
pander | 12 | Imports | 0.0042658 | 7 |
htmltools | 12 | Imports | 0.0034781 | 7 |
inline | 13 | Suggests | 0.0079045 | 1 |
RcppArmadillo | 14 | Imports | 0.1946658 | 4 |
RcppProgress | 14 | Imports | 0.0113162 | 4 |
mice | 14 | Depends | 0.0030460 | 4 |
gRbase | 14 | Imports | 0.0023738 | 4 |
prodlim | 15 | Imports | 0.0021381 | 1 |
dplyr | 16 | Imports | 0.0229406 | 4 |
tidyr | 16 | Imports | 0.0063965 | 4 |
readr | 16 | Imports | 0.0028615 | 4 |
tibble | 16 | Imports | 0.0027780 | 4 |
plyr | 18 | Imports | 0.0301552 | 3 |
reshape2 | 18 | Imports | 0.0251029 | 3 |
scales | 18 | Imports | 0.0143476 | 3 |
plotDepGraph <- function (intro_cand_pkgs, random_seed = 71) {
rcpp_pkgs_intro_cand_graph <- miniCRAN::makeDepGraph(
pkg = intro_cand_pkgs,
suggests = TRUE, enhances = TRUE, availPkgs = pdb
)
# ターゲットノードを赤に
igraph::V(graph = rcpp_pkgs_intro_cand_graph)$color[
igraph::vertex_attr(
graph = rcpp_pkgs_intro_cand_graph, name = "name"
) == SET_TARGET_PACKAGE
] <- "red"
# 候補パッケージを橙に
igraph::V(graph = rcpp_pkgs_intro_cand_graph)$color[
is.element(
el = igraph::vertex_attr(graph = rcpp_pkgs_intro_cand_graph, name = "name"),
set = intro_cand_pkgs
)
] <- "orange"
return(
visNetwork::visIgraph(
igraph = rcpp_pkgs_intro_cand_graph,
idToLabel = TRUE, smooth = FALSE, physics = TRUE, randomSeed = random_seed
) %>%
# visNetwork::visHierarchicalLayout(direction = "LR") %>%
visNetwork::visOptions(
highlightNearest = list(
enabled = TRUE, algorithm = "hierarchical"
),
width = 900, height = 500
)
)
}
rcpp_pkgs_intro_cand_plot <- lapply(
X = rcpp_pkgs_intro_cand$pkgname,
FUN = plotDepGraph
)
# リストに格納するとPlotで表示できなくなるので、力技で一部表示
rcpp_pkgs_intro_cand_plot[[1]]
rcpp_pkgs_intro_cand_plot[[2]]
rcpp_pkgs_intro_cand_plot[[3]]
パッケージの依存関係からなるグラフにネットワーク分析を用いて、{Rcpp}が支える代表的なパッケージを選別しました。これにより、パッケージをグルーピングして紹介ができると思います。
しかしながら、今回のアプローチでは有名なパッケージばかりが出てきてしまい、{Rcpp}ならではのパッケージの選定ができているとは言い難い結果でした。コミュニティ抽出の方法を変えたり、スコアリング方法を変えたりなど、ネットワーク分析の勉強が必要になりそうです。
また、ネットワーク分析を行うために{igraph}を用いました。2015年6月に1系メジャーリリースがされ、変数名がドット区切りから変更されたり、チェイン演算子が使えるようになるなど、今後の活用の幅が広がることが期待できます。
今回は「{igraph}オブジェクトを{visNetwork}オブジェクトに変換」でRcppを取り除いておりますが、そのままで可視化するとRcppにすべてエッジが貼られます。可視化をするとかなりブラウザが重くなりますが、{Rcpp}を中心にネットワークが形成され、パッケージを支えている感がとても出ます。
作成手順は下記に示しますが、とても重くなるのでここでは可視化はしません。興味がある方は下記のリンクをご参照ください(要注意。ブラウザがフリーズする)。
{Rcpp}が支えるパッケージ
(下記のような可視化されたネットワークをインタラクティブに触れます)
# include {Rcpp}
rcpp_network <- visNetwork::toVisNetworkData(
igraph = rcpp_pkgs_dg,
idToLabel = TRUE
)
# 以下は同じ
rcpp_network$nodes <- dplyr::left_join(
x = rcpp_network$nodes,
y = rcpp_members %>%
dplyr::select(pkgname, group = membership, value = hub_score),
by = c("id" = "pkgname")
)
rcpp_network$edges$arrows <- "middle"
rcpp_network$edges$smooth <- TRUE
rcpp_network$edges$shadow <- FALSE
rcpp_network$edges$title <- rcpp_network$edges$type
visNetwork::visNetwork(
nodes = rcpp_network$nodes, edges = rcpp_network$edges,
width = 900, height = 1200
) %>%
visNetwork::visOptions(
highlightNearest = TRUE,
selectedBy = list(variable = "group")
)
library(devtools)
devtools::session_info()
Session info --------------------------------------------------------------
setting value
version R version 3.3.1 (2016-06-21)
system x86_64, darwin13.4.0
ui X11
language (EN)
collate ja_JP.UTF-8
tz Asia/Tokyo
date 2016-08-14
Packages ------------------------------------------------------------------
package * version date source
assertthat 0.1 2013-12-06 CRAN (R 3.3.1)
DBI 0.4-1 2016-05-08 CRAN (R 3.3.1)
devtools * 1.12.0 2016-06-24 CRAN (R 3.3.0)
digest 0.6.9 2016-01-08 CRAN (R 3.3.0)
dplyr * 0.5.0 2016-06-24 CRAN (R 3.3.1)
DT 0.1 2015-06-09 CRAN (R 3.3.1)
evaluate 0.9 2016-04-29 CRAN (R 3.3.1)
formatR 1.4 2016-05-09 CRAN (R 3.3.1)
highr 0.6 2016-05-09 CRAN (R 3.3.1)
htmltools 0.3.5 2016-03-21 CRAN (R 3.3.1)
htmlwidgets 0.6 2016-02-25 CRAN (R 3.3.1)
httr 1.2.1 2016-07-03 CRAN (R 3.3.0)
igraph * 1.0.1 2015-06-26 CRAN (R 3.3.0)
jsonlite 1.0 2016-07-01 CRAN (R 3.3.0)
knitr * 1.13 2016-05-09 CRAN (R 3.3.1)
lazyeval 0.2.0 2016-06-12 CRAN (R 3.3.1)
magrittr 1.5 2014-11-22 CRAN (R 3.3.1)
memoise 1.0.0 2016-01-29 CRAN (R 3.3.0)
miniCRAN * 0.2.5 2016-04-13 CRAN (R 3.3.1)
R6 2.1.2 2016-01-26 CRAN (R 3.3.0)
Rcpp 0.12.5 2016-05-14 CRAN (R 3.3.1)
rmarkdown 1.0 2016-07-08 CRAN (R 3.3.1)
stringi 1.1.1 2016-05-27 CRAN (R 3.3.1)
stringr 1.0.0 2015-04-30 CRAN (R 3.3.1)
tibble 1.1 2016-07-04 CRAN (R 3.3.1)
visNetwork * 1.0.1 2016-06-20 CRAN (R 3.3.0)
withr 1.0.2 2016-06-20 CRAN (R 3.3.0)
XML 3.98-1.4 2016-03-01 CRAN (R 3.3.1)
yaml 2.1.13 2014-06-12 CRAN (R 3.3.1)