まだ厨二病

RとPyhtonを使ったデータ分析・統計解析らへんの話題をしていくだけ

⭐️GitHub API(JSON)を叩いて学ぶRでのリスト操作とストーキング事情(2015年版)

R Advent Calendar 2015の二日目です。

昨日は表形式のデータをR上で扱いやすく、さらに可視化やモデリングの関数との相性が良いtidy形式なデータフレームについての話をしました。昨日が表形式なら、今日はRでのデータ形式として主要なもう一つの形式、リスト形式のオブジェクトを扱ってみたいと思います

私はGitHubが(進捗的な意味で)好きで、見つけたR関係のパッケージには割りと星をつけています(2015-12-01の時点で725のリポジトリ数)。GitHubには既存のRパッケージでなく、これからCRANに登録されるであろう原石のようなパッケージがあったりします。そういうものを見つけてはストーキングの対象に加えているわけです。

自分がスターをつけたリポジトリの情報は、以下のようなURLでGitHubAPIを叩けば得ることができます。

https://api.github.com/users/uribo/starred

JSONフォーマットとして格納されています。表形式では無いデータですので、Rではリストとして扱われます。

表形式でないデータの操作については、今週末のJapan.R 2015でうさぎさんこと@sinhrks さんが講演してださるのですが、それはそれとして、私は私で浅はかな知識の限りであれこれやりたいと思います。

なお今回の内容は

GitHub API | rlist Tutorial

このページにある情報でほとんどのことができてしまいます。他にもリストの扱いを容易にするための関数の使い方についてまとまっているので、どうぞご参考ください。

🎯 GitHub APIからR上にデータを取り込む

今回使用するパッケージを読み込みます。

library(rlist)
library(magrittr)
library(formattable)

GitHub APIで取得できる情報が100リポジトリごとに提供されているので、今回は8つ分のページを用意します。

# api ref. https://developer.github.com/v3/activity/starring/
# 更新があったリポジトリの順番、100リポジトリごと
max_page <- 8
api_url <- "https://api.github.com/users/uribo/starred?per_page=%d&sort=updated&page=%d" %>%
  sprintf(100, 1:max_page)
api_url
## [1] "https://api.github.com/users/uribo/starred?per_page=100&sort=updated&page=1"
## [2] "https://api.github.com/users/uribo/starred?per_page=100&sort=updated&page=2"
## [3] "https://api.github.com/users/uribo/starred?per_page=100&sort=updated&page=3"
## [4] "https://api.github.com/users/uribo/starred?per_page=100&sort=updated&page=4"
## [5] "https://api.github.com/users/uribo/starred?per_page=100&sort=updated&page=5"
## [6] "https://api.github.com/users/uribo/starred?per_page=100&sort=updated&page=6"
## [7] "https://api.github.com/users/uribo/starred?per_page=100&sort=updated&page=7"
## [8] "https://api.github.com/users/uribo/starred?per_page=100&sort=updated&page=8"

このような配列を用意して、R上にJSONファイルを読み込ませます。使用するのは {rlist}パッケージです。{rlist}のおさらいとして、まずは1ページ分の情報を取得しましょう。

repo <- "https://api.github.com/users/uribo/starred?per_page=1&sort=updated&page=1" %>% 
  list.load("json") %>% 
  list.ungroup()

repo %>% {
  print(list.names(.))
  list.count(.)
}
##  [1] "id"                "name"              "full_name"        
##  [4] "owner"             "private"           "html_url"         
##  [7] "description"       "fork"              "url"              
## [10] "forks_url"         "keys_url"          "collaborators_url"
## [13] "teams_url"         "hooks_url"         "issue_events_url" 
## [16] "events_url"        "assignees_url"     "branches_url"     
## [19] "tags_url"          "blobs_url"         "git_tags_url"     
## [22] "git_refs_url"      "trees_url"         "statuses_url"     
## [25] "languages_url"     "stargazers_url"    "contributors_url" 
## [28] "subscribers_url"   "subscription_url"  "commits_url"      
## [31] "git_commits_url"   "comments_url"      "issue_comment_url"
## [34] "contents_url"      "compare_url"       "merges_url"       
## [37] "archive_url"       "downloads_url"     "issues_url"       
## [40] "pulls_url"         "milestones_url"    "notifications_url"
## [43] "labels_url"        "releases_url"      "created_at"       
## [46] "updated_at"        "pushed_at"         "git_url"          
## [49] "ssh_url"           "clone_url"         "svn_url"          
## [52] "homepage"          "size"              "stargazers_count" 
## [55] "watchers_count"    "language"          "has_issues"       
## [58] "has_downloads"     "has_wiki"          "has_pages"        
## [61] "forks_count"       "mirror_url"        "open_issues_count"
## [64] "forks"             "open_issues"       "watchers"         
## [67] "default_branch"

## [1] 67

取得した情報は次のような配列になっています。ownerの中にさらに情報がネストされています。

  • id
  • name
  • full_name
  • ...
  • owner
    • login
    • id
    • avatar_url
    • ...
    • site_admin
  • ...
  • default_branch

先ほど用意したURLを渡して、Rに取り組みましょう。list.load()を使います。

repos <- api_url %>% 
  list.load(type = "json") %>% 
  list.ungroup()

🔨 リストの操作

リストについて操作を加えます。こういったリスト操作は {rlist}の得意とするところです。リスト版の {dplyr} という感じでしょうか。以下のような操作を行います。

  • list.filter() 絞り込み: 今回対象にしたいのはR言語で書かれたリポジトリなので、対象を絞り込みます
  • list.select() 選択: リストの要素が多いため、必要なものだけを使えるようにします
  • list.sort() 並び替え: リストの並びを入れ替えます
  • list.update() 新たな要素の追加: CRANに登録されているパッケージかどうかの真偽値を与えます
  • list.map() 抽出: リストから値を取り出します。ベクトル形式で帰り値を得たい時にはlist.mapv()とします
# CRANに登録されているパッケージ名のベクトルを作成しておきます
pkg_name <- available.packages() %>% data.frame() %$% Package %>% as.vector()

repos %<>% 
  list.filter(!fork, language == "R") %>% 
  list.select(name, owner = owner$login, description, stargazers_count, open_issues_count) %>% 
  list.sort(-stargazers_count) %>% 
  list.update(CRAN = ifelse(name %in% pkg_name, TRUE, FALSE))

279リポジトリが該当しました。

一覧表を作るために、リストの内容をデータフレームオブジェクトにしましょう。リストに格納されている各要素をlist.mapv()で取り出し、データフレームの変数として代入します。つけられている星の数が多い15のリポジトリだけを抽出します

df_gh_star <- data.frame(name   = list.mapv(repos, name) %>% list.take(15),
                         owner  = list.mapv(repos, owner) %>% list.take(15),
                         star   = list.mapv(repos, stargazers_count) %>% list.take(15),
                         issues = list.mapv(repos, open_issues_count) %>% list.take(15),
                         CRAN   = list.mapv(repos, CRAN) %>% list.take(15))

テーブルになったので、出力してみましょう。{rlist}と同じパッケージの開発者であるrenkun-kenの{formattable}を使います。

df_gh_star %>% formattable(
  list(owner  = formatter("span", 
                          style = x ~ ifelse(x == "hadley", style(color = "darkorchid", font.weight = "bold"), 
                                             ifelse(x == "rstudio", style(color = "royalblue", font.weight = "bold"), NA))),
       star   = color_tile("white", "greenyellow"),
       issues = color_bar("pink", 0.2),
       CRAN   = formatter("span", 
                          style = x ~ style(color = ifelse(x, "forestgreen", "tomato")), 
                          x ~ icontext(ifelse(x, "ok", "remove"), ifelse(x, "Yes", "No")))
))
name owner star issues CRAN
ggplot2 hadley 1556 20 Yes
shiny rstudio 1504 166 Yes
devtools hadley 1140 55 Yes
awesome-R qinwf 1024 12 No
dplyr hadley 986 169 Yes
slidify ramnathv 625 139 No
SparkR-pkg amplab-extras 547 21 No
ggvis rstudio 501 163 Yes
ggthemes jrnold 493 4 Yes
rvest hadley 449 20 Yes
CausalImpact google 424 2 No
rmarkdown rstudio 413 128 Yes
r-ninja yihui 410 6 No
DiagrammeR rich-iannone 401 30 Yes
ProjectTemplate johnmyleswhite 369 27 Yes

若干、starとissuesの数が実際の値とずれている気がしなくもないですが...まあよしとしましょう 😸

🎁 この開発者がすごい2015

去年もやっていたので、今年はGitHubでストーキングの対象になっているパッケージの開発者の方々についてこの場で公開してみたいと思います。年の瀬ですしお寿司。

有名なパッケージと、ストーキングの理由について簡単に書いておきます。敬称略。

  • @renkun-ken... 日本人のR利用者にも人気のある開発者の一人です。今回使わせていただいた{rlist}{formatrable}だけでなくパイプ処理を行う {pipeR}も有名です。
  • @hadley... 神なので。今年も {purrr}{multidplyr} といった新しいパッケージを世に出して信者たちに救いを与えたそうな。
  • @yutannihilation... 今年はこの人の年でした。{chartist}{estatapi}{qiitr}などのパッケージがあります。ブログもストーキングしていますが未だに名称を覚えられません(え。
  • @dichika... ジャパニーズシリパク。 {sinchokur}, {doudesuka}, {jaguchi}などのパッケージがあります。yeah::doudesuka()を.Rprofileに追加したら、knitの際に辛くなったのもいい思い出です。
  • @hoxo-m... {dplyrr} {lambdaR}など、世界のRパッケージ開発者に引けを取らないパッケージを開発されています。中でも{pforeach}が超便利で使っています。CRANにあげてくれよなー、頼むよー。
  • @kos59125 ... typoを指摘してくれる{DYM}や並び替えをよしなにしてくれる{naturalsort}など利用者の視点になって、あったら嬉しい、渋いパッケージを作ってくれています。{DYM}.Rprofileで設定しておくのがおすすめです。
  • @sinhrks... ggplot2の拡張パッケージである{ggfortify}が便利でよく使わせてもらっています。
  • @gaborcsardi... ユーティリティ系のパッケージを数多く開発されています。{seer}{gh}など。
  • @timelyportfolio... D3.js とRを連携させたパッケージを中心に開発をされています。 {svgPanZoom}{d3vennR} など。
  • @hrbrmstr... 師匠です。Rだけでなく、外部サービスと連携させたパッケージ、地図を作成するパッケージなどが豊富です。{slackr} {docxtractr}{ggalt}{lineworkmaps}などなど。

GitHub上のRパッケージをまとめる、通称gepuro task viewというのもあります。新たにRパッケージを探したい方はこちらが良いかもしれません。

紹介しきれませんでしたが、以下のパッケージもおすすめです。気になるものがありましたら、ぜひGitHubのページを見てください

というわけで、R Advent Calendar 明日は kaneshin さんです。よろしくお願いします。