『入門ソーシャルデータ』第4章を読む(1)

今週金曜日(2012/2/10)、こちらのイベントでプレゼンを担当します。

『入門 ソーシャルデータ』

このイベントは、オライリーの『入門ソーシャルデータ』を参加者同士で一章ずつ担当して読み進めていこう、という連続勉強会で、この日ではそのうちの第4章を担当することになっています。

それに先立って、事前にこの章をひと通り読み進めてみましたので、その過程を書き留めていきます。参考になれば幸いです。書いてみたら長くなったので2回に分けます。これはその1回目。

まず、この本では記載されているソースはすべてpythonという言語で書かれていますので、python環境もOSなどにあわせて用意しておきましょう。なるべくバージョンは新しいほうがいいと思います。ちなみに僕の環境は以下のとおり。

  • OSX Lion 10.7.2
  • python 2.7.1 (OSXでのpythonのバージョン切り替えについてはこちらに記載)
  • Eclipse Herios SR2 + PyDev など(コマンドラインでやる人は必要ないでしょう)

(追記:pythonのバージョンは、本にあわせて2.7系がベターでしょう。@iwaimさんご指摘ありがとうございます)

おっと、この章を読み進めるには、とりあえず以下のpythonライブラリも必要となってきます。とにかく用意しましょう。

  • twitter (これがなければ始まらない。この本の5ページにインストール方法の記載あり)
  • cPickle(シリアル化ライブラリ)

そして最初に、この章でなに取り扱うのかを確認しておきましょう。ここでは、本の91ページにあるように、

  • (twitterで)フォローしている/されているユーザーは何人いるか
  • フォローしているけれどもされていないユーザーは誰か
  • フォローされているけれどもしていないユーザーは誰か
  • ネットワークのなかでフォロー関係のもっとも多いユーザー、少ないユーザーは誰か
  • 「相互フォロー」(フォローし合っている関係)している相手は誰か
  • 自分のフォロワー全員と彼らのフォロワー全員から考えて、自分がリツイートしたときにどのような影響があるか

ということを取り扱います。

ちなみに、これ以前の1〜3章については、今回の勉強会の主催者の方が設置してくださっているGoogleグループ「集合知の会」に、各回のプレゼン資料が掲載されていますので、参考にしてみてはいかがでしょうか。

それでは、章立てに従って見ていきましょう。

4.1 RESTfulとOAuthを着込んだAPI

ここでは、twitterのAPIはRESTfulでもあること、twitterアカウントの情報を得る際には、twitterのいわゆるアカウント名(=screen_name)のほかに、アカウントごとに固有な整数(=user_id)を利用することもできる、ということが書かれてます。

そして、ユーザー認証が必要なtwitterのAPIを利用するには、OAuthを利用する必要がある、として次に進みます。

4.1.1 君が私のパスワードを知っているはずがない

ここでは、twitterというよりも、OAuth自体の説明ですね。様々なウェブサービスはその認証機能としてOAuth 2.0を採用し始めており、twitterも2010年夏からOAuth1.0aを採用しています(2.0はまだの様子)。

OAuth自体のことを理解するためには、この章を読む他にも、下記のようなページを読み進めるのもいいと思います。

要は、本にあるとおり、「一言で言えば、OAuthは、ユーザー名とパスワードを共有せずに、あるアプリケーションが格納したデータに別のアプリケーションからアクセスできるようにするために、そのアプリケーションに権限を認める手段を提供する」もの。そしてその手段を、ユーザー認証として利用している場合もある、ということですかね。

たとえば、今回の勉強会の告知に利用されているatndさんも、OAuthを利用してユーザー認証をしている、といっていいものだと思います。

4.2 無駄がなく必要最小限なデータ収集マシン

さて、話はtwitterに戻ります。今回の『入門ソーシャルデータ』を読み進める上でありがたいのは、掲載されているソースのなかで(〜.py)とファイル名が付いているものに関しては、著者のgithubでまんま公開されていること。コピペで動作確認できるわけですね。

さっそく例4-2のソース(friends_followers__get_friends.py)をコピペして実行…と思ったら、いきなり本のソースとちょっと違ってるやんけ! githubのこのソースの履歴を見ると、“Fixed a minor bug in reporting output, Mostly style tweaks”とあって、consumer key と consumer secret を引数として渡すようになっていました。ふむふむ。

ここで、本にも記載がありますが、これ以降のソースを実行するには、twitterの開発者用サイトに行って、「新しいアプリケーションを作成する」ことで、この consumer key と consumer secret を取得する必要があります。もちろん、twitter アカウントも必須。

この画面ですね。

ここで、Nameは独自のものを指定する必要があるみたいです(ここではなにも考えずに”socialdata_hosono”としました)。無事アプリケーションを作ると、consumer key と consumer secret が発行されました。

これを、試しに自分のtwitterアカウントのscreen_name (HOSONO_Junya)と一緒にさっきのソースの引数として渡して再実行! コンソールには以下のような画面で止まって、

Hi there! We're gonna get you all set up to use MiningTheSocialWeb.
In the web browser window that opens please choose to Allow access.
Copy the PIN number that appears on the next page and paste or type it here:
Opening: http://api.twitter.com/oauth/authorize?oauth_token=(文字列)
Please enter the PIN:

それとは別にブラウザが開き、よく見かける下の画面が出てきました。

なるほど、twitterさんに、

  • タイムラインのツイートを見る。
  • フォローしている人を見る。

この2つの機能を、socialdata_hosono というアプリケーションに使わせてやっていいですか?という問い合わせが発生したわけですね。許可するためにアカウント名とパスワードを入力すると、PINが発行されました。

コンソールに戻ってこれを入力すると、

Fetched 833 ids for HOSONO_Junya
[124190170, 342836805, 5373072, 384222380, 137886908, 24066081,
167287360, 313359626, 308796953, 338254966, 165748489, 14491664,
3776671, 14655252, 41823348, 14357291, …

と表示されました! 833というのは、僕のtwitterアカウントの「フォローしている数」ですので、フォローしている人たちのuser_idのリスト(pythonでいうところのリスト)が得られたことになります(この本内やtwitterの公式ドキュメント内でのfriendsというのは自分がフォローしている人、という意味ですね)。

(ちなみに、上の表示の”Fetched〜”の部分だけ標準エラー出力に書き出しているあたりがちょっと親切ですねw)

なお、本に記載もありますが、ソース内で使っている /friends/ids API は一度の呼び出しで5000のIDを返すそうです。このソースではそのたびに”Fetched〜”の行を出しつつループする、という形になっており、上限を10000としています。そして、こうしたAPIの呼び出しには回数制限があり、350回/時とのこと。同様の記載が、以下のサイトにもありました。

なので、大量のフォロワーを持つアカウントを対象にこうしたAPIを利用する場合にはそれなりの準備をしなければならない、ということですね。

4.2.1 リファクタリングのための非常に短い幕間

ということもあって、そのあたりの準備を著者はあらかじめしてくれています。偉い!ここではOAuthを用いたログイン部分と、よく使われるAPIをモジュール化&公開してくれています。

これを使えば、ソース内で自分のやりたいことに集中できるというわけですね。ソースが短くなっていることがわかると思います。ありがたく使わせていただきましょう。上記リンクからダウンロードして、自分のソースと同じフォルダに置いておけばいいでしょう。ファイル名もそのままにしておくのがベターですね。

例4-3(friends_followers__get_friends_refactored.py)は、例4-2をこの2つのモジュールを用いて書き換えただけのものです。こちらもgithub版のソースは本からちょっと修正されていて、引数としてフォロー数の上限も引数で渡すようになっています。

ソースを見て、「…引数がアカウント名とフォロー数上限の2つだけ?はて?」と思いつつ実行したら、案の定エラーが。tracebackが吐かれて、

twitter.api.TwitterHTTPError: Twitter sent status 401 for URL:
oauth/request_token using parameters: (oauth_consumer_key=
&oauth_nonce=(数字)&oauth_signature_method=HMAC-SHA1&oauth_timestamp=
(数字)&oauth_version=1.0&oauth_signature=(文字列))
 details: Failed to validate oauth signature and token

とのこと。要はOAuthに失敗しましたよと。ソースを見ると、

# You may need to setup your OAuth settings in twitter__login.py

とあるので(書籍版にも書いてありますね)、twitter__login.pyの最初の部分に customer key と customer secret を直書きして再実行、再びPINが発行されて、無事friendsが取得できました。

もちろん、このライブラリを使ったとしても、API制限自体が消えるわけではないので、大量のデータを取り扱う場合にはそれなりの時間を使える時にしたほうがいいでしょう。

4.2.2 Redis:データ構造サーバ

この節では、APIを用いて得られるようになったtwitterの各種データを取り扱うために、Redisというデータベースの導入をする、としています。その心は、大量なデータを取り扱うため、ともう一つ、集合演算を使いたいため、ということらしいです。

僕はRedisを今回初めて知ったのですが、この本の3章でもでてきたCouchDBなど同じく、KVS (Key-Value Stored)なデータベースとのこと。要はハッシュデータのようなものを取り扱うのに長けているといったものでしょうか(詳しい人コメントお願いします)。

なにはともあれ、Redisをインストールしましょう。公式サイトのダウンロードページにインストールの指示があり、これに従って簡単にインストールできました。そしてコマンドラインからサーバを起動して専用クライアントから操作できること、までの説明が公式サイトにあります。

次に、このRedisをpythonから利用するためのライブラリも、sudo easy_install redis であっさりインストール完了。

本の101ページの一番下のソースは、”screen_name1$friends_ids”というキーに対して、pythonのリスト内包表記を用いて、1,2,3…と順繰りに追加(sadd)していってそれを表示(smember)する、というだけのことですね。保管されるデータは、

  • キー:”screen_name$friends_ids”
  • 値:set([‘1′,’2’,’3’…])

という一組になります。

4.2.3 初歩的な集合演算

さて、ここでは、そもそもなぜ集合演算を使うのか、ということを確認しています。例4-2のソースにあるように、この章で取り扱う twitter API で得られるデータは、フォロワーの一覧などその多くはデータが複数集まったもの=集合、です。そしてそれらに対して集合演算を用いることで、意味のある情報を得ようというわけですね。例として、

Friends = {Abe, Bob}, Followers = {Bob, Carol}

というtwitterユーザーに対して、

演算 結果 コメント
和集合:Friends ∪ Followers Abe,Bob,Carol あるユーザーのネットワーク全体
積集合:Friends ∩ Followers Bob あるユーザーの相互フォローの相手
差集合1:Friends – Followers Abe あるユーザーがフォローしているものの、相手はそのユーザーをフォローしていないという相手
差集合2:Followers – Friends Carol あるユーザーをフォローしているものの、ユーザーの方からはフォローしていない相手

というような情報が得られるわけですね。これらが、記事の最初に書いたこの章で取り扱おうとしていた情報そのもの(の一部)であることがわかると思います。

そしてこの本では、pythonの(リストではなく)set型を用いてソース内で集合を取り扱っています。

4.2.4 フォローしている/されている関係を測るマシン

この節の例4-4は、先の例4-2のソースに対して取得したデータをRedisに格納し、そこから上のような集合演算をして結果を表示するものです。これを実行すると、

HOSONO_Junya is following 833
HOSONO_Junya is being followed by 612
548 of 833 are not following HOSONO_Junya back
327 of 612 are not being followed back by HOSONO_Junya
HOSONO_Junya has 285 mutual friends

と表示されました。上から、フォロー数(Friends)、フォロワー数(Followers)、フォロー返ししてくれていない数(上の表での差集合1)、フォロー返ししていない数(差集合2)、相互フォロー数(積集合)となります。激しくフォロー返しされていないのがわかりますね…orz

なお、この例4-4のソースを理解する上でキーとなるのは、

  • “functools.partial” というのが何をしているのか
  • Redisに格納されるデータがどんな感じか

ということでしょう。

まず”functools.partial”ですが、うーん、これは正直自分でも正確に理解できているかどうかわかりませんが、ざっくり言うと「特定の関数を一部分だけ修正して新しい関数を作り出している」ということでしょう。専門用語では「部分適用」というらしいです。それをこの本では「ラッパー」という言葉で表現している、と。そしてここでは、

  • 元の関数=_getFriendsOrFollowersUsingFunc (twitter__utilライブラリ内)
  • それを元に新しく作られる関数=getFriends と getFollowers

がそれに該当します。要は、関数が2つほしいけど中でやってることはほとんど同じだからその部分だけ先に作って最後に呼び出し部分を変えるだけで対応しようぜ(コード再利用のためにね)、ということでしょうかね。

このfunctools自体に関しては、以下のページなどを精読すると理解が深まるかもしれません。

はっきり言ってこの部分を正確に理解すること自体は、「この本のこの章を読み進めていく」という目的においてはそんなに重要ではないと思います。「へー、そんなこともできるだね」程度でいいと思います。本筋とは関係のない箇所でつまずいてそこで止まってしまうのはもったいないですから。もちろん、理解できることに越したことはありませんが。

どうも、CやJavaといった一般的な「手続き型プログラミング言語」を経験した人がpythonをやる上でとっつきづらく思える部分に、こうした「関数型プログラミング言語」的な要素がそこかしこに出てくるからなのかもしれません。リスト内包表記しかり、lambda式しかり、そしてこのfunctoolsしかり。以下のページにそのあたりのことがちょっと書かれていました。

閑話休題。つぎは、Redisに格納されるデータがどんな感じか、ですね。これは、ソースの最後に以下のようなprint文を入れて実行すればわかりますね。

print r.smembers(getRedisIdByScreenName(screen_name,'friend_ids'))

また、getRedisIdByScreenName関数の中身などから、Redis内には、上で作った2つの関数を実行することで、

  • キー:”screen_name$(引数で指定したscreen_name)$friend_ids”
  • 値:set([(フォローしている人たちのuser_id)])

と、

  • キー:”screen_name$(引数で指定したscreen_name)$follower_ids”
  • 値:set([(フォロワーたちのuser_id)])

という2つのデータが格納されます。Redisのクライアントのkeysコマンドなどからも確認できるでしょう。そして、次にこの2つのデータの値に対してRedisの機能である集合演算をかけている、というわけですね。

そして、これまでは取得するデータはたいていuser_idの集合のみでしたが、次の例4-5では、特定のuser_idのtwitterアカウント自体の各種ユーザー情報を取得しています。これもgithubからソース(friends_followers__get_user_info.py)をコピペしてくるだけで実行できます。結果はJSON形式になります。これを実行すると、

  • キー:”screen_name$(引数で指定したscreen_name)$info.json”
  • 値:引数で指定したscreen_nameのユーザー情報(JSON形式)
と、
  • キー:”user_id$(引数で指定したscreen_nameに該当するuser_id)$info.json”
  • 値:引数で指定したscreen_nameのユーザー情報(JSON形式)

いう2つのデータがRedis内に作られます。これは、あとからscreen_nameとuser_idのどちらからでも素早くユーザー情報を取得できるようにするため、でしょうね。

4.2.5 共通してフォローしている/されているユーザーからの類似度の計算

この節では、複数名のユーザーを指定して、その人たちが共通してフォローしている人たち/共通してフォローされている人たち、を見つけます。異なるユーザーのフォロー/フォロワー間で集合関数を使うことで見つけることになります。

これまでどおり例4-7(friends_followers__friends_followers_in_common.py)をコピペしてくるわけですが、その実行の際には、対象とするユーザーのフォロー/フォロワーのデータをあらかじめRedis内に入れておかなければなりません。具体的に言うと、例4-4を対象ユーザーで実行しておけばOKです。先ほどの部分適用して作られた関数がRedis内にデータを格納してくれますから。そうしないと、データが無いので単に0件と返ってくるだけです。

4.2.6 影響力の計測

twitterの機能のなかで特徴的なもののひとつに、リツイートがあげられます。気に入った他人のツイートを自分のフォロワーに「転送」する機能ですよね。これによって、ある特定のツイートが連鎖的にリツイートされると、短期間で爆発的に広まることになります。そしてフォロワーの多いユーザーにリツイートされると、より広く伝播されて大きな影響を生み出すことができる、というわけです。

この節では、そうした影響力をフォロワー数によって測ってみよう、というものです。例4-8(friends_followers__crawl.py)は、ある特定のユーザーからスタートして、そのフォロー/フォロワーの情報をすべて取得&Redisに格納し、そしてそれら一人ひとりに対してまたフォロー/フォロワーの情報をすべて取得&Redisに格納し、そして…と、繰り返していきます。

なので、これを実行すると、Redis内のデータが一気に増大します。何階層まで探索するかは引数のdepthで指定できますが、僕のアカウントでdepth=1(直接のフォロー/フォロワーだけ)で実行したら、一分ほどで終了して、Redis内に2322件のデータがあらたに登録されました。

…うっかりdepth=10とかで実行すると、はっきり言ってどういう事態になるかわかりません。たぶんAPI制限に引っかかりながらも制限がリセットされる一時間おきにちょっとずつ進んでいって、メモリとHDDをRedisデータが喰い潰していく、という感じでしょうか。だからこそ、このソースでは一度のフォロー数などの探索での上限数を設けています。なんにせよ、ちょっと気をつけて実行しましょう。

しかしこのソースでは、あくまでデータを取得&格納しただけで、影響力としてはさっぱりわかりません。そこで次の例4-9(friends_followers__calculate_avg_influence_of_followers.py)では、対象ユーザーのフォロワーのなかでフォロワー数の多いトップ10と、全フォロワーの平均フォロワー数を計算しています。なお、このソースではPrettyTableというライブラリが指定されているので、素直にeasy_installしましょう。

同じく僕のアカウントで行ったところ、以下のように結果になりました。

The top 10 followers from the sample:
 +----------------+---------+
 | Date | Count |
 +----------------+---------+
 | hatoyamayukio | 608,303 |
 | shuzo_matsuoka | 258,605 |
 | 38sun3 | 250,422 |
 | ktamiya | 240,826 |
 | LIVESTRONG | 203,574 |
 | tsuda | 196,778 |
 | sasakitoshinao | 145,352 |
 | myen | 137,497 |
 | wakita_tamaki | 70,913 |
 | asao_keiichiro | 68,583 |
 +----------------+---------+
The average number of followers for HOSONO_Junya's followers: 6,856

トップは鳩山由紀夫元首相か…あんまり最近見かけないようなw

次回に続く。

さて、長かった4.2章もこれで終わりです。ずいぶん長くなったので、続きは別エントリーにします。できれば明日中には更新します。

『入門ソーシャルデータ』第4章を読む(1)” への2件のフィードバック

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中