京橋のバイオインフォマティシャンの日常

南国のビーチパラソルの下で、Rプログラムを打ってる日常を求めて、、Daily Life of Bioinformatician in Kyobashi of Osaka

gtrendsRの使い方 と Googleトレンドの情報取得・可視化をやってみた件

はじめに

今回紹介する、gtrendsRは、Google Trendsの情報を取得・表示するためのパッケージである。

そもそも、Google Trendsは、Googleが提供する無料ツールで、Googleの検索エンジンでの検索クエリの人気動向を分析できる。現在、Google検索のシェアが、世界中で約90%とほぼ独占状態であることからも、このワードトレンドの重要度が分かる。

つまりは、市場調査の観点からも、どの国・地域で、どのような行動、ワードが、どういう時系列でトレンドになっているかを素早く把握できるのは良い。

この記事では、gtrendsRでGoogle検索のトレンドデータを取得して、plotlyによるインタラクティブな可視化などをやってみる。検索の実行例は、アメリカ株ネタにやや偏っているが、あしからず。

gtrendsRなどの関連パッケージのインストール

さっそく、gtrendsRなどの関連パッケージをインストールしてみる。

#パッケージ・インストール
pack <- c("gtrendsR", "plotly", "magrittr")
install.packages(pack[!(pack %in% unique(rownames(installed.packages())))])

#ロード
for(n in 1:length(pack)){ eval(parse(text = paste0("library(", pack[n], ")"))) }; rm("n", "pack")

gtrendsの使い方

次に、gtrends関数の使い方をまとめてみた。 この関数では、keyword、geo、timeの引数設定をよく使うことになる。

#gtrendsの使い方
gtrends( keyword , geo , time = "today+5-y", gprop = "web" )

#引数について
#keyword: Google Trends query キーワードである文字ベクトル。複数のキーワード入力も可。
#geo: queryの地理的な地域を示す文字ベクトル。世界中の場合には、"all"を指定する。
#また上記の国コードなどを使用することで、複数の国・地域を指定できる。
#time: queryの期間を指定する文字列。以下を参照のこと。
#"now 1-H" 最後の1時間
#"now 4-H" 最後の4時間
#"now 1-d" 最後の1日
#"now 7-d" 過去7日間
#"today 1-m" 過去30日間
#"today 3-m" 過去90日
#"today 12-m" 過去12ヶ月
#"today+5-y" 過去5年間(デフォルト)
#"all" Google Trends の開始時(2004 年)から
#"Y-m-d Y-m-d" 2つの日付の間で指定(例:「2010-01-01 2010-04-03」)
#gprop: トレンドクエリを収集する Google product を定義する文字列。「web」(デフォ)のままで良いと思う。

代表的な国コード

また、gtrendsRで使う、国コード(country_code)・地域コード(sub_code)は、countriesというデータに格納されている。

代表的な国コードには、日本(JP)、アメリカ(US)、カナダ(CA)、イギリス(GB)などがある。 また、地域コードだと、東京(JP-13)、大阪(JP-27)、ニューヨーク(US-NY)、カリフォルニア(US-CA)などがある。

実際のcountriesからの取り出し方を、以下に記した。

#国コード(country_code)・地域コード(sub_code)の取得
data("countries")
head(countries)
#  country_code sub_code        name
#1           AF     <NA> AFGHANISTAN
#2           AF   AF-BDS  BADAKHSHAN
#3           AF   AF-BDG     BADGHIS
#4           AF   AF-BGL     BAGHLAN
#5           AF   AF-BAL       BALKH
#6           AF   AF-BAM      BAMIAN

#アメリカUSの州・都市
head(countries[grepl("^US-", countries$sub_code),])
#     country_code sub_code       name
#3796           US    US-AL    ALABAMA
#3797           US    US-AK     ALASKA
#3798           US    US-AZ    ARIZONA
#3799           US    US-AR   ARKANSAS
#3800           US    US-CA CALIFORNIA
#3801           US    US-CO   COLORADO

#日本JPの都道府県
head(countries[grepl("^JP-", countries$sub_code),])
#     country_code sub_code         name
#2038           JP    JP-23 AITI [AICHI]
#2039           JP    JP-05        AKITA
#2040           JP    JP-02       AOMORI
#2041           JP    JP-38        EHIME
#2042           JP    JP-21  GIHU [GIFU]
#2043           JP    JP-10        GUNMA

#その他の取得例
#アメリカのカリフォルニア
head(countries[grepl("US", countries$country_code) & grepl("CALIFORNIA", countries$name),])
#       country_code sub_code            name
#3800             US    US-CA      CALIFORNIA
#102327           US    US-MD      CALIFORNIA
#102328           US    US-MO      CALIFORNIA
#102329           US    US-PA      CALIFORNIA
#102330           US    US-CA CALIFORNIA CITY

#ニューヨーク
head(countries[grepl("New York", countries$name),])
#       country_code sub_code         name
#122761           US    US-NY New York, NY

#東京
head(countries[grepl("TOKYO", countries$name),])
#      country_code sub_code             name
#2077            JP    JP-13    TOKYO [TOKYO]
#79623           JP    JP-13    ARIAKE, TOKYO
#79697           JP    JP-13    CHUO-KU/TOKYO
#79806           JP    JP-13    FUTAMI, TOKYO
#79831           JP    JP-13      HABU, TOKYO
#79869           JP    JP-13 HANEDA APT/TOKYO

#大阪
head(countries[grepl("OSAKA", countries$name),])
#      country_code sub_code               name
#2069            JP    JP-27      OSAKA [OSAKA]
#79702           JP    JP-27       DAITO, OSAKA
#79914           JP    JP-27      HIGASHI-OSAKA
#79915           JP    JP-27  HIGASHIOSAKA CITY
#80114           JP    JP-27       IZUMI, OSAKA
#80358           JP    JP-27 KONOHANA-KU, OSAKA

gtrendsのシンプルな実行例

keywordやgeoについて条件を変えて、トレンド検索を実行してみた。

実行例(1)NASDAQのトレンドを国別で12ヶ月分取得して、折れ線プロットを描く

まずは、NASDAQ(ナスダック)のトレンドを、カナダ(CA)と米国(US)、日本(JP)で12ヶ月分取得して、gtrendsRの折れ線プロットをしてみた。

#実行例(1)
res01 <- gtrendsR::gtrends(keyword = c("NASDAQ"), geo = c("US", "CA", "JP"),
                           gprop="web", time = "today 12-m")
plot(res01)
#quartz.save(file = paste0("./Graph_01.png"), type = "png", dpi=150); dev.off()

実行例(2)NASDAQ銘柄のトレンドを、米国(US)で12ヶ月分取得して、折れ線プロットを描く

次に、NASDAQ、TSLA(テスラ)、PLTR(パランティア)、ZM(ズーム), ARKKのトレンドを、米国(US)で12ヶ月分取得して、gtrendsRの折れ線プロットをしてみた。

#実行例(2)
res02 <- gtrendsR::gtrends(keyword = c("NASDAQ", "TSLA", "PLTR", "ZM", "ARKK"), geo = c("US"),
                         gprop="web", time = "today 12-m")
plot(res02)
#quartz.save(file = paste0("./Graph_02.png"), type = "png", dpi=150); dev.off()

TSLAの人気はやはりすごい。

ただ、ここで、Googleトレンドの検索指数は、対象期間内のピークを100とした相対値である。

そのため、取得期間や検索語の組み合わせで、上図の通り、検索指数が変わってくるので、その点は注意する必要である。

あと、同時に検索できるキーワード数は、5つまでのようだ*1

実行例(3)market crashやmarket highとかのキーワード検索

続いて、market crashやmarket highとかのキーワードで検索してみると。。

#実行例(3)
res03 <- gtrendsR::gtrends(keyword = c("market crash", "stock crash", "stock high"), geo = c("US"),
                         gprop="web", time = "2021-01-01 2021-03-25")
plot(res03)
#quartz.save(file = paste0("./Graph_03.png"), type = "png", dpi=150); dev.off()

「stock high」は少し先に反応しているようにも見える。

また、「market high」でも検索してみた(省略)が、それはあまり使わないワードみたい。。。

実行例(4)最近のロビンフット(米国株の人気銘柄)のトレンド

さらに、最近のrobinhoodのトレンドはどうだったのかと思い、それも検索してみた。

#実行例(4)
res04 <- gtrendsR::gtrends(keyword = c("robinhood"), geo = c("US"),
                         gprop="web", time = "2021-01-01 2021-03-25")
plot(res04)
#quartz.save(file = paste0("./Graph_04.png"), type = "png", dpi=150); dev.off()

やっぱり、ゲームストップ事件のあたりで、一時期サチってたのかもね。

plotlyを使った可視化の実行

これくらい遊んだところで、plotlyを使った可視化も実行してみた。

#トレンドデータの取り出し
res04 %>%
  .$interest_over_time -> res04.i 
head(res04.i)
#        date hits   keyword geo                  time gprop category
#1 2021-01-01    2 robinhood  US 2021-01-01 2021-03-25   web        0
#2 2021-01-02    4 robinhood  US 2021-01-01 2021-03-25   web        0
#3 2021-01-03    4 robinhood  US 2021-01-01 2021-03-25   web        0
#4 2021-01-04    5 robinhood  US 2021-01-01 2021-03-25   web        0
#5 2021-01-05    5 robinhood  US 2021-01-01 2021-03-25   web        0
#6 2021-01-06    4 robinhood  US 2021-01-01 2021-03-25   web        0

#グラフ作成
fig <- plotly::plot_ly() 
fig <- fig %>% add_trace(x=res04.i$date, y = res04.i$hits, 
                         name = 'robinhood', mode = 'lines') 
fig <- fig %>% layout(yaxis = list( title = "Search index"))
fig

#保存
#fig %>% htmltools::save_html(file="Graph_05.html")

まとめ

簡単に、トレンド解析できるのは大変良い。

ただ、検索語をどれにするかとか、適切にキーワードを選択できるかは悩みどころかも。

補足

r-bloggersをもとに改変版コードを作ってみた

r-bloggersでの実行コードが為になったので、その記事をもとに改変版コードを作成して実行してみた。

#install.packages("gtrendsR")
library(gtrendsR)
#install.packages("tidyverse")
library(tidyverse)
#install.packages("ggthemes")
library(ggthemes)

gtrends(keyword = "robinhood",
        geo = "US",
        time = "today 12-m") -> results

results %>% summary()
#                    Length Class      Mode
#interest_over_time  7      data.frame list
#interest_by_country 0      -none-     NULL
#interest_by_region  5      data.frame list
#interest_by_dma     5      data.frame list
#interest_by_city    5      data.frame list
#related_topics      6      data.frame list
#related_queries     6      data.frame list

results %>% 
  .$interest_over_time %>%
  glimpse()
#Rows: 52
#Columns: 7
#$ date     <dttm> 2020-03-29, 2020-04-05, 2020-04-12, 2020-04-19, 2020-…
#$ hits     <int> 7, 7, 9, 8, 9, 8, 8, 8, 6, 9, 12, 13, 8, 7, 8, 8, 7, 7…
#$ keyword  <chr> "robinhood", "robinhood", "robinhood", "robinhood", "r…
#$ geo      <chr> "US", "US", "US", "US", "US", "US", "US", "US", "US", …
#$ time     <chr> "today 12-m", "today 12-m", "today 12-m", "today 12-m"…
#$ gprop    <chr> "web", "web", "web", "web", "web", "web", "web", "web"…
#$ category <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …

results %>%
  .$interest_over_time %>%
  ggplot(aes(x = date, y = hits)) +
  geom_line(colour = "darkblue", size = 1) +
  facet_wrap(~keyword) +
  ggthemes::theme_economist()
#quartz.save(file = paste0("./Graph_robinhood.png"), type = "png", dpi=150); dev.off()

やっぱ、2月は、robinhoodバブルだったのかもね。

参考資料

https://cran.r-project.org/web/packages/gtrendsR/gtrendsR.pdf

www.r-bloggers.com

*1:length(keyword) <= 5 is not TRUE

R/Slack APIの諸設定、slackrの使い方、及びGoogle scholarで検索された新着論文情報を知らせるTips

はじめに : R版Slack API

RのSlack APIであるslackrパッケージの使い方について、いろいろとまとめてみた*1

APIの諸設定、基本的なslackrの使い方に加えて、新着論文情報をRからチャネルに送信するプログラムも実装してみた。

まずは、Salck API設定の手順からはじめよう。

Salck API設定の手順

1. Slackのワークスペースに、任意のチャネルを作る。(必要なら)

2. Slack アプリを新規作成する

Rからは以下の関数実行で、Slack APIのサイトに飛べる。

browseURL("https://api.slack.com/apps/new")

ここで、任意のApp Nameを記入して、Development Slack Workspaceを選択する*2

3. Incomming WebhooksをActiveにする

はじめに、Incomming Webhooks の設定に進む。

デフォルトでは、その設定はOFFになっている。

その設定を、ONにする。

次に、Add New Webhook to Workspaceをクリックする

次の画面で、対象となるチャネルを選択して、許可する。

そうすると、Webhook URLが作成される。

ただ、この後のBot Token Scopesを設定して、reinstallすると、新たなWebhook URLが作成されるっぽいので、ひとまずはスルーしておく。

4. Bot User OAuth Tokenの取得、OAuth & Permissionsの設定

次に、サイドバーで、OAuth & Permissionsをクリックする。

ここで、上部に表示される、Bot User OAuth Token は後ほど使用するので、コピーして、保存しておく。

続いて、Bot Token Scopesを設定する。

ここには、incoming-webhookのみが追加されているので、「Add an OAuth Scope」でScopeを追加する。

まずは、以下の項目あたりを追加して、様子をみるのが良い。

  • channels:read

  • chat:write

  • chat:write.customize

  • chat:write.public

  • users:read

  • files:read

  • files:write

  • groups:read

  • groups:write

  • im:read

  • im:write

  • channels:history

上記が選択できたら、reinstallして、次の画面で、対象となるチャネルを選択して、許可する。

そうしたら、Incomming Webhooksの設定に戻って、新しく生成されたWebhook URLを取得しておく。

Sample curl requestのコードの最後部分が最新のWebhook URLなので、それをコピーしておく。

5. Slack アプリをチャネルに招待する【これが重要!】

どうも、以下の設定は必須みたい。

Known Issues

Depending on your scopes, slackr could quietly fail (i.e. not throw an error, but also not post anything to your channel). If this happens, try explicitly adding the app you’re trying to have slackr post as to the channel you want in your Slack workspace with /invite @your_app_name or make sure you have chat:write.public enabled.

日本語への機械翻訳: 既知の問題

スコープによっては、slackrが静かに失敗することがあります(エラーをスローせず、チャンネルに何もポストしないなど)。この問題が発生した場合は、Slackrに投稿させようとしているアプリをSlackのワークスペースに/invite @your_app_nameで明示的にチャンネルに追加するか、chat:write.publicを有効にしてください。

これは、chat:write.publicを有効にするだけでは解決しない。

やることは、対象チャネルで、「/invite @App Name」を入力して、作成したSlack アプリをチャネルに加える。

以下は、「@r-slack」を追加したときの例である。

送信すれば、「@r-slack」がチャネルに招待される。

6. RでのSlack APIの設定

ようやく、slackr側の設定を行う。

Rを起動して、まずは関連パッケージをインストール・ロードする。

#パッケージのインストール
library(devtools)
devtools::install_github("hrbrmstr/slackr", force = TRUE)
library(slackr)

7. slackr config ファイルの設定

ここでは、Rからホームディレクトリに、~/.slackrを作成する。

上記で、コピー・保存しておいたOAuth TokenやWebhook URLを使用する。

.slackrの基本フォーマットは以下の通りである。

#基本的なフォーマット
bot_user_oauth_token: Bot User OAuth Token
channel: #チャネル名
username: 上記のApp Name
incoming_webhook_url: https://hooks.slack.com/services/XXXXX/XXXXX/XXXXX

以下、R上から~/.slackrの作成を行う。tokenやチャネル名は、適時変更のこと。

また、~/.slackrを設定さえすれば、次回使用時からはslackr_setup()だけで完結する。

#Token & チャネル名 & Username の設定
OAuth_token <- "xoxb-XXXXXXX-XXXXXXX-XXXXXXX"
WebURL <- "https://hooks.slack.com/services/XXXXX/XXXXX/XXXXX"
Channel <- "チャネル名"
#チャネル名は、"Channel ID"でも可 
Username <- "slack-r"
#Usernameは任意でOK

a <- paste0("
bot_user_oauth_token: ", OAuth_token, "
channel: ", Channel, "
username: ", Username, "
incoming_webhook_url: ", WebURL)

#作成
system(paste0("echo \"", a, "\" > ~/.slackr"))

#確認
system("cat ~/.slackr")

#削除 (必要なら)
#system("rm -rf ~/.slackr")

#slackr_setupの実行
slackr_setup()
#[1] "Successfully connected to Slack"

あと、オプション的な内容である。

#authentication & identity のチェック
auth_test()

#Slack usersの表示
slackr_users()

#Slack channelsの表示
slackr_channels()

#設定状況の確認
Sys.getenv("SLACK_CHANNEL")
Sys.getenv("SLACK_BOT_USER_OAUTH_TOKEN")

8. 簡単な投稿実行

次に、実際に、Slackrパッケージを使って見ていこう。

#メッセージ送信
slackr_msg("Test message")

#メッセージをR表現の結果 「```形式」 として送信
slackr_bot('Test message')

上記の出力結果

#Rスクリプトの実行結果の送信
slackr(summary(UKgas))

#Plot結果を送信する
plot(UKgas)
slackr_dev(channels="#test")
#OR
ggslackr(plot(UKgas))

#画像のアップロード: 任意の画像で試してください。
slackr_upload("./01.png")

#チャネルを指定して送信する場合
library(maps)
map('county')
slackr_dev(channels = "#test")

#その他
#チャネルからメッセージを削除する
#slackr_delete(count=1)

上記の出力結果(一部)

R/Slackrで、Google scholarで検索された新着論文情報を知らせる

応用例として、Google scholarで検索された論文情報を新着順に10件取得して、Slackのチャネルに投げるということをやってみる。

Rを用いたWebスクレイピングの詳細については、以下の記事を参考のこと。

skume.net

また、googleScholarSearchNewest関数については、下記の補足資料を参照のこと。

#パッケージとかの準備
if(!require("rvest")){install.packages("rvest")}; library(rvest)
if(!require("xml2")){install.packages("xml2")}; library(xml2)
if(!require("magrittr")){install.packages("magrittr")}; library(magrittr)
source("https://gist.githubusercontent.com/kumeS/ef4d750a191b847174b3b93a4b8391c9/raw/9281e95919903fa66f2c43b71b9ae2340404d8a8/googleSearch_function.R")

#検索語の準備 ex. electron microscopy
Query <- c("electron microscopy")

#Google Scholar 検索実行
d <- googleScholarSearchNewest(Query=Query)

#結果ベクトルの取得
res <- d$`electron microscopy`

res
#[1] "https://www.nature.com/articles/s41467-021-21709-z"                          
# [2] "https://pubs.acs.org/doi/abs/10.1021/acsmacrolett.1c00032"                   
# [3] "https://academic.oup.com/cdn/advance-article/doi/10.1093/cdn/nzab025/6174670"
# [4] "https://pubs.acs.org/doi/full/10.1021/acsnano.0c10065"                       
# [5] "https://pubs.acs.org/doi/abs/10.1021/acsnano.0c10065"                        
# [6] "https://www.sciencedirect.com/science/article/abs/pii/S2213138821001284"     
# [7] "https://link.springer.com/article/10.1140/epjp/s13360-021-01291-5"           
# [8] "https://pubs.acs.org/doi/abs/10.1021/acs.energyfuels.1c00167"                
# [9] "https://journals.sagepub.com/doi/abs/10.1177/0095244321996396"               
#[10] "https://www.sciencedirect.com/science/article/pii/S0269749121005315"  

#Slackへの出力
for(n in 1:length(res)){
slackr_msg(paste0("Search results No. ", n))
slackr_msg(res[n])
}

Slack上に、こんな感じで出力される

まとめ

ファイルのアップロードとか、スクリプトの情報共有とかは楽なのかもしれない。

今のところ、メッセージ送信とかレスポンスとかを、Rからすべてやるのはちょっとやり過ぎかもという所感である。

補足資料

googleScholarSearchNewest関数について

gist.github.com

参考資料

qiita.com

github.com

*1:Web上の日本語資料の2021版アップデート

*2:Slackにログインしておくとよいかも

【R・ビッグデータ解析の処方箋】Rで、10万ノードを超える大きなネットワーク図を描画するTips 〜 igraph::plot.igraphは使い物にならない件 〜

はじめに

Rでのネットワーク図の作成では、igraph packageがよく使われる。

ただ、igraphによるネットワーク図の描写は、1万ノードを超えたあたりから、結構な時間がかかる。

そのため、10万ノードを超えるような、大規模なネットワーク図の描画には、ちょっとしたコツがある。

今回、そんな大規模なネットワークの作成方法を取り上げ、実際の実行時間を検証してみた。

結論的には、igraph::plot.igraphを使うよりも、graphics::plot.defaultで描画する方が、10倍以上早くなる。

graphics::plot.defaultによるネットワーク図の作成例

まずは、Barabasi-Albertモデルで、サンプルのグラフ構造を作成する。

#パッケージ準備
library(igraph)

#サンプル・グラフの作成
#sample_pa: Barabasi-Albertモデルによるスケールフリー・グラフの生成関数
#BAモデルは、グラフを構築するためのシンプルな確率的アルゴリズムである。
pa <- igraph::sample_pa(n=10, power=1, m=1, directed=F)

pa
#IGRAPH fe31e44 U--- 10 9 -- Barabasi graph
#+ attr: name (g/c), power (g/n), m (g/n), zero.appeal (g/n),
#| algorithm (g/c)
#+ edges from fe31e44:
#[1] 1-- 2 2-- 3 2-- 4 2-- 5 1-- 6 3-- 7 1-- 8 5-- 9 7--10

#graphics::plot.defaultによる作図
system.time(graphics::plot.default(layout_with_fr(pa), pch=20, cex=2.5,
                       axes = F,  type = "p", xlab = NA, ylab = NA))
#quartz.save(file = paste0("./Graph_net_00.png"), type = "png", dpi = 150); dev.off()

うーん、この図だと、ネットワークのエッジがない。

そこで、線分を追加するsegments関数で、エッジの描画を行う。

関数として組むと、こんな感じである。

gist.github.com

このNetwork_plot関数で、pa を描画してみる。

#パッケージの準備 & 簡単な実行例
library(data.table)
library(magrittr)
source("https://gist.githubusercontent.com/kumeS/2c8204b1c8a78a16d00ec2eaed5a7ca5/raw/e67a5760d7fcfc3a9c8f62f729e407b2722f5bf2/Network_plot.R")

pa <- igraph::sample_pa(n=10, power=1, m=1, directed=F)
Network_plot(pa, Cex=2.5)
#quartz.save(file = paste0("./Graph_net_01.png"), type = "png", dpi = 150); dev.off()

見慣れた、ネットワーク図が得られる。

グラフのレイアウトは、layout_with_fr *1 を使用している。

グラフ・ノード数による描画時間の比較

それでは、次に、グラフのノード数を増やしていって、igraph::plot.igraphとgraphics::plot.defaultを使う場合とでの実行時間を比較してみる。

検証したスクリプトは、以下の通りである。

#####################
#10 nodes
#####################
#plot.igraphでの実行
pa <- sample_pa(n=10, power=1, m=1, directed=F)
system.time(plot.igraph(pa, vertex.size=10, vertex.label=NA))
#   ユーザ   システム       経過  
#     0.014      0.002      0.019 
#quartz.save(file = paste0("./Graph_01.png"), type = "png", dpi = 150); dev.off()

#Network_plotでの実行
system.time(Network_plot(pa, Cex=2.5))
#   ユーザ   システム       経過  
#     0.016      0.002      0.018 
#quartz.save(file = paste0("./Graph_02.png"), type = "png", dpi = 150); dev.off()

10 nodes by plot.igraph

10 nodes by Network_plot

#####################
#100 nodes
#####################
#plot.igraphでの実行
pa <- sample_pa(n=100, power=1, m=1, directed=F)
system.time(plot.igraph(pa, vertex.size=4, vertex.label=NA))
#   ユーザ   システム       経過  
#     0.023      0.003      0.026
#quartz.save(file = paste0("./Graph_03.png"), type = "png", dpi = 150); dev.off()

#Network_plotでの実行
system.time(Network_plot(pa, Cex=1.5))
#   ユーザ   システム       経過  
#     0.029      0.003      0.031
#quartz.save(file = paste0("./Graph_04.png"), type = "png", dpi = 150); dev.off()

100 nodes by plot.igraph

100 nodes by Network_plot

#####################
#1000 nodes
#####################
pa <- sample_pa(n=1000, power=1, m=1, directed=F)
system.time(plot(pa, vertex.size=2, vertex.label=NA))
#   ユーザ   システム       経過  
#     1.033      0.017      1.053 
#quartz.save(file = paste0("./Graph_05.png"), type = "png", dpi = 150); dev.off()

#Network_plotでの実行
system.time(Network_plot(pa, Cex=0.5))
#   ユーザ   システム       経過  
#     0.771      0.006      0.781 
#quartz.save(file = paste0("./Graph_06.png"), type = "png", dpi = 150); dev.off()

1000 nodes by plot.igraph

1000 nodes by Network_plot

#####################
#10000 nodes: 1万ノード
#####################
pa <- sample_pa(n=10000, power=1, m=1, directed=F)
system.time(plot(pa, vertex.size=1, vertex.label=NA))
#   ユーザ   システム       経過  
#    11.014      0.035     11.061
#quartz.save(file = paste0("./Graph_07.png"), type = "png", dpi = 150); dev.off()

#Network_plotでの実行
system.time(Network_plot(pa, Cex=0.2))
#   ユーザ   システム       経過  
#     0.873      0.005      0.881
#quartz.save(file = paste0("./Graph_08.png"), type = "png", dpi = 150); dev.off()

10000 nodes by plot.igraph

10000 nodes by Network_plot

#####################
#100000 nodes: 10万ノード
#####################
pa <- sample_pa(n=100000, power=1, m=1, directed=F)
system.time(plot(pa, vertex.size=0.5, vertex.label=NA))
#   ユーザ   システム       経過  
#   140.286      0.545    141.231
#quartz.save(file = paste0("./Graph_09.png"), type = "png", dpi = 150); dev.off()

#Network_plotでの実行
system.time(Network_plot(pa, Cex=0.03))
#   ユーザ   システム       経過  
#     9.381      0.021      9.423
#quartz.save(file = paste0("./Graph_10.png"), type = "png", dpi = 150); dev.off()

100000 nodes by plot.igraph

100000 nodes by Network_plot

#####################
#200000 nodes: 20万ノード
#####################
pa <- sample_pa(n=200000, power=1, m=1, directed=F)
system.time(plot(pa, vertex.size=0.5, vertex.label=NA))
#   ユーザ   システム       経過  
#   278.272      0.539    279.129
#quartz.save(file = paste0("./Graph_11.png"), type = "png", dpi = 150); dev.off()

#Network_plotでの実行
system.time(Network_plot(pa, Cex=0.01))
#   ユーザ   システム       経過  
#    20.613      0.037     20.700 
#quartz.save(file = paste0("./Graph_12.png"), type = "png", dpi = 150); dev.off()

200000 nodes by plot.igraph

200000 nodes by Network_plot

実行時間の可視化

実行時間を表で比較すると、1000や10000あたりから、すでに差が出てくる。

ノード数 igraph::plot.igraphでの実行時間 Network_plotでの実行時間
10 0.019 0.018
100 0.026 0.031
1000 1.053 0.781
10000 11.061 0.881
100000 141.231 9.423
200000 279.129 20.700

図としてプロットすると、こんな感じ。

tm <- data.frame(a=c(10, 100, 1000, 10000, 100000, 200000),
                 b=c(0.019,0.026,1.053,11.061,141.231,279.129),
                 c=c(0.018,0.031,0.781,0.881,9.423,20.700))
par(family="HiraKakuProN-W3", mgp=c(2.5, 1, 0), mai=c(0.75, 0.75, 0.5, 0.25))
plot(tm[,1], tm[,2], type="n", log="x", xlab="nodes", ylab="Time")
points(tm[,1], tm[,2], type="b", pch=16)
points(tm[,1], tm[,3], type="b", pch=21)
legend("topleft", legend=c("igraph::plot.igraphでの実行時間","Network_plotでの実行時間"), pch=c(16, 21), cex=1)
#quartz.save(file = paste0("./Graph_13.png"), type = "png", dpi = 150); dev.off()

まとめ

描画速度が歴然と違う、、、igraphオブジェクトは1万ノードくらいを扱うのが良いところかな。

大規模なネットワークを扱いたい人には、graphics::plot.defaultが基本型だろう。

参考資料

stackoverflow.com

*1:Fruchterman and ReingoldによるForce-Directed Layoutアルゴリズムを用いて、平面上に頂点を配置するレイアウト。