cucumber flesh

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

💮Moves + Rで行う行動データの可視化

私の趣味の一つにお気に入りユーザーのネットストーキングがあります。ネットストーキングをしている、というのを公言するとウケが良くないことは経験上明らかなので、ひとまず自分をストーキングしてみたい(というのを今年の目標の一つにしています)。今回は、Movesというスマートフォン向けの行動記録アプリケーションのウェブAPIを利用した自分ストーキングをRを使ってやってみたいと思います。

❓ Movesとは

moves-app.com

Activity Diary of Your Life

をキャッチコピーとしていているように、一度ユーザー登録、ログの開始をしておくと自動的に自分の行動を記録してくれるアプリケーションでAndroidおよびiPhoneで利用可能となっています(参考: 【Android】完全自動行動記録アプリ「Moves」が待望のリリース!さっそく使ってみた)。

MovesではウェブAPIが提供されていて、第三者が開発したアプリも充実しているのですが、R用のパッケージが見つかりません(Pythonはあるのに...)。APIさえ利用できるなら、Rでもあれこれできるはずだ、といういつもの気持ちでやってみましょう。また、APIを使わずとも自分のデータは取得できるのでそちらも使ってみたいと思います。

🚶 Moves APIを利用する

準備

いくつかの作業が必要です。流れとしては

  1. Movesで新しいアプリケーションを作成し、Client IDClient secretを取得
  2. ブラウザで "https://api.moves-app.com/oauth/v1/authorize?response_type=code&client_id=&scope=location%20activity" にアクセス

    • 表示されるPINコードをスマートフォンで入力、データの利用を許可
    • リダイレクト先のURL"<redirect_uri>?code="から""の部分をコピー
  3. httr::POST()でアクセストークンを取得

という感じになります。これらは一度実行しておけば、アクセストークンの有効期間が過ぎるまではやる必要がなくなります。リフレッシュトークンも取得できるのでそれをメモしておいて、期限が近づいてきたら再度アクセストークンを有効にするのが良いのではないでしょうか。

まずはAPIを叩くために{httr}パッケージを読み込みます。

library(httr)

作成したアプリケーション固有のClient IDとClient secretを用意しておきましょう。

ci <- "<Client ID>"
cs <- "<Client secret>"

ブラウザで "https://api.moves-app.com/oauth/v1/authorize?response_type=code&client_id=g2XylBJ2IHmkN64cfCvyGt5oCgy8p6Qb&scope=location%20activity" にアクセスします。

BROWSE(paste0("https://api.moves-app.com/oauth/v1/authorize?response_type=code&client_id=", 
    ci, "&scope=location%20activity"))
ac <- "<authorizationcode>"
get.token <- POST("https://api.moves-app.com/oauth/v1/access_token?", 
    body = list(grant_type = "authorization_code", 
        code = ac, client_id = ci, client_secret = cs), 
    encode = "form") %>% content()
access.token <- get.token$access_token

Moves APIの利用には、リクエストヘッダーかリクエストURLにアクセストークンを含める必要があるので、ヘッダーにアクセストークンの値を渡しておく。

http.header <- add_headers(Authorization = paste("Bearer", 
    access.token))

APIの操作

再度必要なパッケージを読み込んでおく。

library(purrr)
library(ggplot2)
library(formattable)

Moves APIでは取得対象のデータに対してエンドポイントが与えられているので、いくつかのエンドポイントを叩いてみます。まずはユーザー情報から。

# Profile
# ユーザーを特定できそうな一部の結果を改変している
GET("https://api.moves-app.com/api/1.1/user/profile", 
    config = http.header) %>% content()
## $userId
## [1] XXXXXXXXXXXXXXX
## 
## $profile
## $profile$firstDate
## [1] "XXXXXXXX"
## 
## $profile$currentTimeZone
## $profile$currentTimeZone$id
## [1] "Asia/Tokyo"
## 
## $profile$currentTimeZone$offset
## [1] 32400
## 
## 
## $profile$localization
## $profile$localization$language
## [1] "ja-JP"
## 
## $profile$localization$locale
## [1] "ja_JP"
## 
## $profile$localization$firstWeekDay
## [1] 1
## 
## $profile$localization$metric
## [1] FALSE
## 
## 
## $profile$caloriesAvailable
## [1] TRUE
## 
## $profile$platform
## [1] "ios"

ある特定の日の記録を取得して、Movesが定める運動(移動手段を含める)の種類に応じた時間を図にしてみます。こういうこと簡単にできるのはRの強みではないでしょうか。

# Summaries
summary.sigle.date <- GET("https://api.moves-app.com/api/1.1/user/summary/daily/20160212", 
    config = http.header) %>% content()
summary.sigle.date[[1]]$summary %>% map_df(~.[c("group", 
    "duration")]) %>% ggplot(., aes(group, 
    duration, fill = group)) + geom_bar(stat = "identity")

f:id:u_ribo:20160216072204p:plain

# Summaries その2
# pastDaysパラメータの指定により31日前まで遡れるが、記録が少ないので7日間にする
summary.past.date <- GET("https://api.moves-app.com/api/1.1/user/summary/daily?pastDays=7", 
    config = http.header) %>% content()
df.group.summary <- summary.past.date %>% 
    at_depth(1, map_if, is_list, map_df, 
        ~.[c("group", "duration", "distance")]) %>% 
    map(c("summary")) %>% dplyr::bind_rows()
df.group.summary %>% dplyr::filter(group == 
    "walking") %>% dplyr::add_rownames(var = "Day") %>% 
    dplyr::select(-group) %>% dplyr::rename(`duration (sec.)` = duration, 
    `distance (m)` = distance) %>% formattable(list(`duration (sec.)` = color_bar("tomato"), 
    `distance (m)` = color_tile("white", 
        "olivedrab")))
Day duration (sec.) distance (m)
1 16069 18576
2 212 235
3 3703 3951
4 824 915
うわっ...私の運動量、少なすぎ...?

🌏 Leaflet上へのマッピング

{leaflet}パッケージを使えば、地図上へのマッピングも簡単です。APIデータの加工が結構面倒だったので、ここはダウンロードしてきたデータを使うことにしました(今後の課題)。

library(leaflet)

geojson <- readLines("~/Downloads/moves_export/geojson/daily/storyline/storyline_yyyyyMMdd.geojson", 
    warn = FALSE) %>% paste(collapse = "\n")
leaflet() %>% addTiles() %>% setView(lng = 139.53, 
    lat = 35.6, zoom = 10) %>% addGeoJSON(geojson, 
    fill = FALSE)

📚 参考

💻 実行環境

package version source
formattable 0.1.5 CRAN (R 3.2.2)
ggplot2 2.0.0 CRAN (R 3.2.3)
httr 1.1.0.9000 Github (hadley/httr@7261a52)
leaflet 1.0.0 CRAN (R 3.2.0)
magrittr 1.5 Github (smbache/magrittr@00a1fe3)
purrr 0.2.1 CRAN (R 3.2.3)
remoji 0.1.0 Github (richfitz/remoji@dc00779)

🍵 所感

  • 自分ストーキングでも十分に楽しめたので、ストーキング癖のある皆様におかれましてもMovesアプリによる行動の記録とRによる可視化を行ってみることをお勧めです
  • 各種のエンドポイントデータを統合したstorylineからうまくデータを整形すれば、API経由でleafletへの可視化ができるはずなのだけど、前処理の壁が厚かったのでここは課題