読者です 読者をやめる 読者になる 読者になる

データサイエ「ソ」ティストは語る

データサイエンティストではない、パチもんのデータサイエ「ソ」ティストのブログ

RとFacebook Graph APIであのサイトのファン層を可視化する

執筆中のBGM


アイドルネッサンス「ベステンダンク」(MV)

サマリー

こういう図が作れます。 f:id:data_sciesotist:20160620224345p:plain

  • Facebook Graph APIを使うと、他人(他社)のFacebookページのファン数を国別に取得できる
  • Rから直接APIにアクセスしてJSONを取得し、パースしてデータフレームに格納する
  • 国名コードと首都の緯度・経度を記述したデータを照合して、プロットのための座標を取得する
  • 世界地図の首都の座標に、ファン数を示す丸をプロットする

Facebook Graph APIについて

いまさらこまごま話すものでもないが、Facebookにおけるオブジェクト(ページ、人、投稿、写真など、“すべて”)間の関係・情報を取得できるAPIが、Graph API

Graph APIを使うことで、例えば自分のFacebookアカウントをフォローしている人の情報などを取得できる。定期的なAPIへのアクセスには、きちんとプログラムを組んでアプリ登録して、アクセストークンをプログラムに埋め込まないといけないが、アドホックな分析、例えば今回のように特定のFacebookページのファン情報を取得し、それを可視化するというようなAPIの利用法であれば、Facebookが提供しているGraph APIエクスプローラーを使って、アクセストークンを取得すればよいだろう。

f:id:data_sciesotist:20160620230134p:plain

今回の用途では、Graph APIエクスプローラーの画面ではアクセストークンを控えておくだけでよい。

任意のFacebookページのIDを調べる

企業や有名人のFacebookページの情報を取得するためには、アクセストークンと合わせて、そのFacebookページのIDを知る必要がある。IDは、URLに含まれる文字列ではなく、数字だけからなる。といっても、調べ方は簡単で、http://findmyfbid.com/にアクセスし、IDを知りたいFacebookページのURLを貼り付ければよい。ここでは、(大して関心はないが、媚びて)AKB48メンバー(akb48.member)のページを例として使用する。

f:id:data_sciesotist:20160620231143p:plain f:id:data_sciesotist:20160620231237p:plain

IDまで48なのは偶然なのか。これも、得られたIDを控えておくだけでよい。

RからGraph APIにアクセスする

アクセストークンが有効期間内(だいたい1~2時間らしい)であれば、ブラウザからでも任意のプログラムからでもGraph APIにアクセスできるので、Rでアクセスし、任意のFacebookページのデータを取得する。

データの取得には、jsonliteパッケージを使う。また、その他地図を描画するためのパッケージなども使うので、ここで必要に応じて不足しているパッケージをインストールする。

install.packages("jsonlite")
install.packages("ggmap")
install.packages("maps")

準備ができたら、Graph APIにアクセスする。なお、今回は他人(他社)のページに関する情報のうち、特別な許可なく勝手に取得できる、page_fans_countryにアクセスする。

ということで、まずは以下のようなコードを実行する。

require(jsonlite)

fb<-fromJSON("https://graph.facebook.com/v2.6/564843926980748/insights/page_fans_country?period=lifetime&access_token=自分で取得したアクセストークン&pretty=0")
fb.fans<-t(fb$data$values[[1]][3,-ncol(fb$data$values[[1]])]) # ※1
fb.fans<-data.frame(rownames(fb.fans),fb.fans[,1]) # ※2
rownames(fb.fans)<-NULL
colnames(fb.fans)<-c("code","fans")

上記のコードを実行すると、以下のようなデータが得られる。

   code  fans
1    DE  1326
2    BD   461
3    NP   471
4    BE    NA
5    RU   353
6    HK 21570
7    TW 47630
8    JP 63045
9    NZ   493
10   FR  3800
...

上記コードの※1、※2あたりで、データの3行目(最新の日付分だけ)取り出したり、転置したり、列名をデータフレームの1列目にしたり、いろいろやっている。これでいちおう、国名コード別に、ファン登録をしているユーザーが何人いるかがわかった。

国名コードと首都の緯度・経度を対応させる

Graph APIから得られる国の情報は、(たぶん)ISO 3166-1の2文字で構成される国名コードである。このままでは、地図上にその位置をプロットすることはできない。そこで、国名コードとその国の都市の緯度・経度を対応付ける必要がある。とりあえず首都でいいだろう、ということで、「国名コード 緯度 経度」でググると、アマノ技研様が世界の首都の位置座標データを公開してくださっている。アンケートに答えるとダウンロードできる。「全項目空白・未入力でもダウンロードは可能」と書かれているが、せっかくなので協力してあげましょう。

f:id:data_sciesotist:20160620233611p:plain

ページを進めると、位置座標のCSVファイルをアーカイブしたzipファイルがダウンロードできる。アーカイブを展開して得られるh2704world.csvをRのワーキングディレクトリに配置する。このファイルと、先ほど作ったfb.fansデータフレームを結合する。

やり方は簡単で、CSVファイルを読み込んでmerge関数でマージするだけでよい(そのためにfb.fansの列名をcodeにしている)。

countries<-read.csv("h2704world.csv")
fb.fans<-merge(fb.fans,countries[,c("code","lat","lon")])

これで、国名コード、ファン数、緯度、経度の4列からなるデータフレームができる。

  code fans       lat       lon
1   AE  351  24.46667  54.36667
2   AR  899 -34.60372 -58.38159
3   AU 2771 -35.30824 149.12422
...

このデータを使い、地図上にファン数をマッピングする。地図の描画にはmapsパッケージを使う。ggmapなどもうちょっとイケてるパッケージを使いたかったが、世界地図を取得する方法がよくわからなかったので。さっそく、以下のコードを実行する。

require(maps)
map("world",fill=T,col="white",bg="lightblue",ylim=c(-60,110),mar=c(0,0,4,0))
points(fb.fans$lon,fb.fans$lat,cex=scale(fb.fans$fans)+3,col=2,pch=19)
text(0,100,"AKB48 Facebookページのファン分布",cex=1)
dev.off()

f:id:data_sciesotist:20160620224345p:plain

なぜか、日本語のページなのに、日本よりもインドネシアにファンがやたらと多い。JKT48の影響なのか。日本ではFacebookよりもGoogle+や個人のページ(あるのか知らないが)などに注目が集まっているからか。

なお、この例ではファン数をpoints関数の丸の大きさ(cex)で表現しているが、国ごとに差が大きすぎるため、scale関数で標準化し、とりあえず全部が正の値になるように3を足している。場合によっては、log関数なども使い、とにかく「ちょうどよい」くらいに調整する。

そのほかの例

以下、同様にいくつかの会社について調べてみた例。

ユニクロ

f:id:data_sciesotist:20160620222355p:plain

日本が圧倒的に多いが、アジア、ヨーロッパなどにもまんべんなくファンがいる様子。

某リサーチ会社

f:id:data_sciesotist:20160620235657p:plain

なぜかアフリカにファンがいる様子。

IBM

f:id:data_sciesotist:20160621000534p:plain

なぜかインドにファンがたくさんいる様子。

まとめ

こんな感じで、「国別ファン数」は、アクセス許可がいらず、任意の(企業、有名人)ページの情報が取得できる。その他の、都市別、性別などは取得できなかった。全部試したわけではないので、他にもアクセスできるエンドポイントがあるかもしれないが、いろいろ試していただければ。