Netflixのあれ、どうなってるんだろうって話
Netflixとか開くと「あなたへのおすすめ」って出てくるじゃないですか。あれ、結構すごい精度で、どういう仕組みなんだろうって、ちょっと思って。まあ、いろいろあるんだけど、その中でも基本になる「協調フィルタリング」っていう考え方について、ちょっとメモ代わりにまとめてみる。自分用の思考整理みたいなもんです。
正直、ゼロからPythonで組んでいく…みたいな話も面白いんだけど、今回はもっとコンセプト寄り。根本のアイデアって、実はすごくシンプルなんだよね。
結論から言うと
「自分と好みが似てる人が好きなものは、自分もたぶん好きだろう」。…これだけ。本当に、根本はこれだけ。データの中から、自分と趣味嗜好の「双子」みたいな人を見つけ出して、その人が高く評価してるけど自分はまだ見てない作品を教えてもらう、っていう感じ。これを「協調」フィルタリングって呼んでるわけだね。なるほど。
じゃあ、具体的にどういうこと?
例えば、ここに3人のユーザーがいるとする。
- Aさん:『インセプション』、『マトリックス』、『インターステラー』が好き。典型的なSF好き。
- Bさん:Aさんと全く同じで、『インセプション』、『マトリックス』、『インターステラー』が好き。
- Cさん:『タイタニック』とか『きみに読む物語』みたいな、恋愛映画が好き。
ここに、新作SF映画の『メッセージ』が出てきたとする。で、Aさんがこれを見て「星5つ!」って高評価をつけた。そうなると、システムは「お、AさんとBさんは好みがそっくりだぞ」と知ってるから、まだ『メッセージ』を見てないBさんに対して「これ、たぶん好きですよ」って推薦できるわけ。逆に、Cさんには…まあ、推薦しないよね。好みのベクトルが全然違うから。
これが協調フィルタリングの心臓部。映画の内容(ジャンルとか監督とか)は一切見てなくて、ただ「誰が何を好きか」っていうユーザーの行動データだけで成り立ってるのが面白いところ。
どうやるの? 行列分解っていう考え方
理屈はわかったけど、じゃあコンピュータはどうやって「好みが似てる」って判断するのか。ここで出てくるのが「行列分解 [Matrix Factorization]」っていう、ちょっと数学っぽい話。
p>でも、大丈夫。要は、巨大なエクセルの表をイメージすればいい。縦軸に全ユーザー(例えば943人)、横軸に全映画(1682本)。そして、各セルにその人がつけた評価(1〜5点)が入ってる。…まあ、ほとんどのセルは空白だよね。だって、誰も全映画なんて見てないから。このスカスカの表を「疎な行列」って言ったりする。
協調フィルタリングのゴールは、この表の空白を、いい感じに予測して埋めること。
「潜在因子」っていう魔法のスパイス
空白を埋めるために、モデルは「潜在因子 [Latent Factors]」っていうのを勝手に学習する。これは人間が「この映画はSFで…」とか教えるんじゃなくて、データからモデルが「発見」する、映画やユーザーを特徴づけるための"隠れた"軸みたいなもの。
例えば、モデルが5個の潜在因子を学習したとする。そしたら、ある映画はこんなベクトルで表現されるかもしれない。
- 『ダイハード』: `[0.9, 0.8, -0.9, ...]` (因子1: アクション性が高い、因子2: 80年代っぽさ、因子3: ロマンス要素は低い…みたいな感じ。あくまでモデルが勝手に決めた軸だけど)
- 『タイタニック』: `[-0.8, -0.2, 0.9, ...]` (因子1: アクション性は低い、因子3: ロマンス要素は高い…とか)
で、同じようにユーザー側もベクトルを持つ。
- アクション映画好きのユーザー: `[0.85, 0.9, -0.7, ...]`
もうわかるよね。このユーザーのベクトルと『ダイハード』のベクトルは形がすごく似てる。逆に『タイタニック』とは全然違う。この「ベクトルの似てる度合い」を計算すれば、評価を予測できる。具体的には「内積」っていう計算をするんだけど、まあ、ここでは「似てるほど高い点数が出る計算方法」くらいに思っておけばOK。
基本モデルと、ちょっと賢いモデル
このベクトル計算だけで予測するモデルも作れる。でも、それだけだとちょっと足りない。世の中には、「そもそも評価が甘い人」とか「誰が見ても面白い傑作映画」ってのがあるからね。
そこで、さっきのベクトル計算に加えて「バイアス」っていう項を足すのが一般的。これもモデルが勝手に学習する。
- ユーザーバイアス: その人の評価の甘さ・辛さ。「いつも評価辛口な人」はマイナスのバイアスを持つ。
- 映画バイアス: その映画自体の人気度。「誰が見てもだいたい面白い映画」はプラスのバイアスを持つ。
予測式はこうなる: 予測評価 = (ユーザーベクトル × 映画ベクトルの内積) + ユーザーバイアス + 映画バイアス
このバイアスを入れるだけで、精度がぐっと上がることが多い。正直、かなり大事なポイント。
| モデルの種類 | 長所 | 短所とか注意点 |
|---|---|---|
| 基本モデル(内積だけ) | まあ、シンプルで分かりやすい。考え方の第一歩としてはOK。 | 人の評価のクセとか、映画自体の普遍的な人気を無視しちゃう。だから予測がちょっとズレがち。 |
| バイアス付きモデル | こっちの方が現実的。ユーザー個人の傾向と、アイテム自体の人気をちゃんと考慮できる。精度がだいぶ良くなる。 | パラメータが増えるから、学習が少しだけ大変になる。まあ、今のコンピュータなら大したことないけどね。 |
現実世界での使われ方:fastai と Mercari の例
こういうモデルを作る時、PyTorchみたいなフレームワークを直接使うのもいいけど、もっと楽に実装できるfastaiライブラリみたいなのもある。`collab_learner`っていう関数を一行呼ぶだけで、今話したバイアス付きのモデルが裏側で全部作られる。すごく便利。
でもね、こういう教科書的なアプローチがそのまま現実世界で使われるかというと、そうでもない。例えば、メルカリの技術ブログとか見ると、もっと複雑な課題に取り組んでるのがわかる。彼らの場合は、出品された瞬間の「リアルタイム性」が重要だったり、そもそもユーザーが評価(星)をつけない「Implicit Feedback(暗黙的フィードバック)」をどう扱うか、みたいな問題がある。海外の一般的なチュートリアル(fastaiとか)は主に評価(星)があるExplicit Feedbackを前提にしてるから、このへんは結構違う。メルカリでは、購入とか「いいね」っていう行動自体を「正解」として扱う必要があるんだよね。これは大きな違い。
もう一歩先へ:ニューラルネットワークを使う
さっきの「ベクトル計算+バイアス」っていうモデルは、すごく強力だけど、一種の線形モデル。つまり、ユーザーの好みと映画の特徴の「複雑な組み合わせ」は表現しきれないことがある。
そこで出てくるのが、もうちょい本格的なニューラルネットワークを使うアプローチ。
- ユーザーと映画のベクトル(潜在因子)を用意する。ここまでは一緒。
- その2つのベクトルを掛け算するんじゃなくて、単純に連結(concatenate)して、1本の長いベクトルにする。
- それを、普通のニューラルネットワークに突っ込む。
- 最終的に、評価点(1〜5)が1つ出力されるようにネットワークを設計する。
こうすると、モデルがユーザーと映画の間の、もっと非線形で複雑な関係性を捉えられるようになる。「SF好きだけど、90年代のちょっとチープなCGは苦手」みたいな、細かいニュアンスを学習できる可能性があるってこと。これもfastaiなら `use_nn=True` ってオプションをつけるだけで試せるから、すごい時代だよね。
でも、万能じゃないよね:コールドスタート問題
じゃあ協調フィルタリング最強かというと、もちろん弱点もある。一番有名なのが「コールドスタート問題」。
要するに、データがないと何もできないってこと。
- 新規ユーザー: 登録したばかりの人は、何の評価データもない。だから、誰と好みが似てるかなんて分かるわけがない。
- 新作映画: 公開されたばかりの映画は、誰も評価してない。だから、誰に推薦していいか分からない。
こういう時、協調フィルタリングは手も足も出ない。だから実際のサービスでは、別の方法と組み合わせることが多い。例えば、最初は国や年齢とかでざっくり人気なものを出したり、映画のジャンルとか俳優っていう「内容ベース」の推薦を使ったりして、データが溜まるのを待つ。なかなか泥臭い世界だ。
モデルの「中身」を覗いてみる
このモデルの面白いところは、学習が終わった後に「中身」を分析できること。例えば、さっき話した「映画バイアス」。これを全部取り出して、値が高い順に並べてみると…大体『ショーシャンクの空に』とか『ゴッドファーザー』みたいな、誰もが認める名作が上位に来る。逆に低いのは、誰も知らないようなB級映画だったりする。モデルがちゃんと「世間一般の評価」みたいなものを学習できてるって証拠だね。
p>あと、映画のベクトル(潜在因子)をPCAっていう次元削減手法で2次元に圧縮してプロットすると、似た映画が近くに集まったりする。アクション映画の塊、恋愛映画の塊…みたいな。こういうのを見ると、モデルがちゃんと映画の「何か」を捉えてるんだなって実感できて、個人的にはすごく好きな工程。結局のところ、データからパターンを見つけ出すっていう、機械学習の王道なんだよね。やってることは。でも、それが「好み」っていう曖昧なものを扱ってるのが、推薦システムの面白さなんだと思う。
ちなみに、あなたが「これは名作なのに、全然レコメンドされないな…」って思う映画、ありますか?もしあったら、教えてください。
