
次元の呪いをマッチングアプリで実験したら、無関係な質問1問で最良の相手が31位まで埋もれた(hit@1は100%→23%)
前回、次元の呪いを実測した記事では、 の中に一様分布させた点同士の距離が、次元数を上げるほどどんどん均されていく(最大距離/最小距離の比が82倍から1.21倍まで潰れる)ことを確認した。あの記事を書きながら、noteで見かけた「マッチングアプリで質問項目を増やすほど、実は良い相手を見つけにくくなっているのでは」という趣旨の投稿をふと思い出した。プロフィールの質問を増やせば増やすほど相性の良い人が見つかりやすくなる、というのは直感的には正しそうに聞こえるが、これも「次元の呪い」の一種だとしたら、むしろ逆の効果があってもおかしくない。今回はこれをシミュレーションで確かめてみる。
実験に使ったコードの全文はGitHubに置いています。
実験設計: 「本当の相性」は3次元、それ以外は全部ノイズ
マッチングアプリの候補者プールを模して、N=300人の候補者と、相手を探す側のユーザー(以下「自分」)を1人用意する。距離を測るのは常に「自分と各候補者の間」で、300人の中から自分に一番近い人を探す、という設定だ。ここでの前提はこうだ。
- 本当に相性を決めているのは、k=3次元の「価値観」(例えば「人生で何を優先するか」「対人距離の取り方」「将来設計への価値観」のような、根本的に相性に効くもの)だけだとする
- アプリはそれとは別に、d個の「雑多な質問」(朝型か夜型か、犬派か猫派か、といった、実際には相性そのものには寄与しない質問)を追加で聞いてくる
- 価値観・雑多な質問とも、自分も各候補者も の一様分布から独立に値を持つ
「本当の最良マッチ」は、価値観3次元だけでのユークリッド距離が自分に一番近い候補者と定義する。一方「アプリが実際に薦める最良マッチ」は、価値観+雑多な質問の全部の次元を素朴に合算した距離が一番近い候補者、とする。多くのマッチングアプリの相性診断が実際にやっていそうな、「回答した質問の一致度をまとめて距離やスコアにする」というやり方の単純化だ。
true_dist = np.linalg.norm(cand_signal - query_signal, axis=1) # 価値観3次元だけ
full_dist = np.linalg.norm(full_cand - full_query, axis=1) # 価値観+雑多な質問 全部
best_true_idx = np.argmin(true_dist) # 本当の最良マッチ
order = np.argsort(full_dist) # アプリの推薦順
rank_of_best_true = np.where(order == best_true_idx)[0][0] + 1 # 本当の最良マッチが何位に埋もれるか
雑多な質問の数 を 0, 1, 2, 3, 5, 8, 12, 20, 35, 60, 100, 200 と振り、各設定で300試行繰り返して、本当の最良マッチがアプリの推薦順で何位になるか(rank)、ちょうど1位に推薦できるか(hit@1)、トップ10には入るか(hit@10)を平均した。1試行というのは、自分と候補者プール300人を丸ごと新しく引き直すことを指す。つまり「たまたまこのプールでは運が悪かった」だけの結果にならないよう、300通りの別々の状況で平均を取っている。候補者数の300と試行回数の300が同じ数字なのはただの偶然で、両者に関係はない。
結果: 雑多な質問1問で、1位が31位に転落した
(雑多な質問なし、価値観3次元だけで判断)のときは当然、本当の最良マッチは常に1位(hit@1=100%)になる。ところが、そこにたった1問だけ雑多な質問を足すと、状況は一変する。

雑多な質問0問 (計3次元): 平均順位 1.0± 0.0 hit@1=100.0% hit@10=100.0%
雑多な質問1問 (計4次元): 平均順位 30.8±45.3 hit@1= 23.0% hit@10= 51.3%
雑多な質問2問 (計5次元): 平均順位 49.4±55.7 hit@1= 13.0% hit@10= 33.7%
雑多な質問3問 (計6次元): 平均順位 56.5±65.1 hit@1= 9.7% hit@10= 32.0%
雑多な質問5問 (計8次元): 平均順位 65.5±66.4 hit@1= 6.0% hit@10= 25.3%
雑多な質問8問 (計11次元): 平均順位 84.2±70.4 hit@1= 2.3% hit@10= 13.7%
雑多な質問12問(計15次元): 平均順位 97.5±75.8 hit@1= 1.3% hit@10= 9.3%
雑多な質問20問(計23次元): 平均順位 98.1±79.5 hit@1= 2.3% hit@10= 13.7%
雑多な質問35問(計38次元): 平均順位112.2±82.0 hit@1= 1.3% hit@10= 8.7%
雑多な質問60問(計63次元): 平均順位127.0±83.6 hit@1= 1.0% hit@10= 7.0%
雑多な質問100問(計103次元):平均順位121.1±81.2 hit@1= 1.0% hit@10= 5.0%
雑多な質問200問(計203次元):平均順位145.9±87.3 hit@1= 1.0% hit@10= 5.0%
完全ランダム推薦の期待値: 平均順位150.5 hit@1= 0.3% hit@10= 3.3%
雑多な質問がたった1問増えただけで、本当の最良マッチの平均順位は1位から30.8位まで跳ね上がった。hit@1(ちょうど1位を当てられる確率)も100%から23%まで急落している。そこからさらに質問を増やしても状況は改善するどころか(後述する試行ばらつきの凸凹はありつつ)悪化を続け、200問まで増やすと平均順位は145.9位となり、完全ランダムに推薦した場合の期待順位(150.5位)とほとんど見分けがつかなくなった。

hit@10(トップ10に入れられる確率)で見ても、20問で13.7%、100問では5%まで落ち込み、ランダム推薦の基準線(3.3%)まであと一歩のところに来ている。「候補を絞り込むための質問を増やしている」つもりが、実際には候補を絞り込む能力そのものを壊していることになる。なお、グラフをよく見ると12問→20問でhit@10が9.3%→13.7%と一度持ち直したり、平均順位も60問→100問で127.0位→121.1位とわずかに下がったりする凸凹があるが、これは各設定を独立した300試行で測っていることによるサンプリングのばらつきで、傾向を覆すものではない(実際、hit@1に至ってはこの領域でずっと1〜2%台に張り付いている)。
順位の分布そのものを見る
平均値だけでなく、300試行それぞれで本当の最良マッチが何位になったか、その分布自体も見ておきたかった。

雑多な質問0問のときは全300試行が「1位」の1本の棒に完全に集中している。12問になると順位は300位までの全域に散らばるが、分布をよく見るとまだ明確に低順位側に偏っていて(平均97.5位。完全なくじ引きなら150.5位)、「価値観の近さ」の情報がかろうじて生き残っているのが分かる。それが60問では分布がかなり平らになり(平均127.0位)、200問では完全一様の場合の期待値(図の点線、1本あたり10試行)とほとんど見分けがつかなくなる(平均145.9位)。つまりアプリの「相性診断」は、雑多な質問が十数問でくじ引きに半分足を突っ込み、数百問でほぼ完全なくじ引きになってしまう。
なぜこんなに急激に壊れるのか
前回の記事の教訓と同じで、これは「本当に意味のある3次元のシグナル」が「無関係なd次元のノイズ」に埋もれる現象だ。距離を全次元まとめて計算すると、各次元は(重み付けしない限り)平等に距離へ寄与する。価値観3次元だけなら、本当に近い人ほど距離が小さくなるという関係がはっきり出るが、そこに無関係な次元を1つ混ぜると、その1次元での「たまたまの近さ/遠さ」が全体の距離を大きく揺さぶってしまう。次元が増えるほど、この「たまたまのブレ」が積み重なり、本当のシグナル(価値観3次元の差)は相対的にどんどん小さな寄与に埋もれていく。
言葉だけだと抽象的なので、雑多な質問1問()の300試行の中から、順位が平均に近かった1試行を選んで中身を具体的に見てみる。横軸が「価値観3次元だけの距離」(=本当の相性)、縦軸が「価値観3次元+雑多な質問1問の距離」(=アプリが見ている距離)で、300人の候補者を全員プロットした。

全部の点が対角線より上に乗っているのは、雑多な質問の分の距離が必ず上乗せされるからだ(たまたま答えが完全一致なら対角線上に残る)。緑の星が本当の最良マッチで、横軸では文句なしの1位——なのに、雑多な質問1問の答えがたまたま合わなかったせいで大きく上に持ち上げられ、縦軸(アプリが見ている距離)では、価値観はそこそこ程度でも雑多な質問がたまたま一致していたオレンジの30人に追い抜かれてしまった。その結果、この試行での本当の最良マッチのアプリ順位は31位。順位を壊しているのは候補者本人の何かではなく、たった1問分の「たまたま」だというのが、この図で見たかったことだ。
これは前回の記事で見た「距離が縮む」というより、「意味のある差と意味のない差が、区別できない形で混ざり合う」という言い方の方が近い。実際、雑多な質問がたった1つ、2つの段階で急激に劣化しているのが特徴的で、次元をたくさん積み増す前の、ごく序盤の数次元で被害の大半が出てしまっている。
正直に書いておくべきこと
いくつか単純化している点がある。まず、雑多な質問を完全に相性と無関係なノイズとして扱ったが、実際のマッチングアプリの質問は多かれ少なかれ相性と相関がある可能性が高い。今回はあくまで「本当に無関係な質問が紛れ込んだ場合の最悪ケース」を意図的に再現した実験だと捉えてほしい。
次に、距離の計算に重み付けを一切していない。現実のマッチングアルゴリズムがもう少し賢く、質問ごとの重要度を学習して重み付けしているなら、今回ほど劇的な崩壊は起きないかもしれない。ただし、その重み付け自体をデータから正しく学習するのもまた別の困難な問題で、「質問を増やせば増やすほど安全」という単純な話にはならない、という結論自体は変わらないはずだ。
また、価値観の次元数を3に固定して実験したが、これがもっと多い(例えば10次元)場合は、無関係な質問1問あたりの破壊力は今回よりは弱まると予想される。シグナル次元とノイズ次元の比率がどこまで崩壊を左右するかは、今回の設定だけでは分からない。
手を動かして意外だったこと
一番意外だったのは、劣化のほとんどが最初の数問で起きてしまうことだった。「質問を100問追加したら流石にまずいだろう」くらいの直感はあったが、実際には1問追加した時点でhit@1がすでに100%から23%まで落ちていて、200問まで増やしてもそこから先の劣化はもう緩やかだった。「少しくらいの追加質問なら大丈夫」という感覚は、この実験の結果を見る限り通用しない。
まとめ
- マッチングアプリを模したシミュレーションで、本当に相性を決める「価値観」をk=3次元、それとは無関係な「雑多な質問」をd次元として、N=300人の候補者プールから最良マッチを探す実験をした
- 雑多な質問が0問なら本当の最良マッチは常に1位(hit@1=100%)だが、たった1問追加しただけで平均順位は30.8位、hit@1は23%まで急落した
- 雑多な質問を200問まで増やすと、本当の最良マッチの平均順位は145.9位となり、完全ランダム推薦の期待順位(150.5位)とほぼ見分けがつかなくなった
- 順位の分布そのものも、雑多な質問が十数問で(低順位側への偏りをわずかに残しつつ)N=300のほぼ全域に散らばり、200問では完全な一様分布(くじ引き)とほとんど見分けがつかなくなる様子が確認できた
- 劣化の大半は最初の数問で起きており、「少しの追加質問なら大丈夫」という直感は今回の実験では支持されなかった
- 質問の重み付けをしていない・ノイズを完全な無関係と仮定しているなど、最悪ケースを意図的に再現した単純化はある
最後に少し私事を。この実験をしていて、自分が過去にした選択の基準のことを思い出した。何かを選ぶとき、比較のための項目(質問)をとにかくたくさん並べて、それぞれに点数をつけて合計する、という比較表を作ったことが何度かある。物件選びのときも、転職先を比べたときも、条件を思いつく限り書き出して、Excelで重み付けもせずに単純に合計していた。あのとき自分がやっていたのは、まさに今回シミュレーションした「雑多な質問を全部同じ重みで足し合わせる」というやり方そのものだったのだと、今回の数字を見て気づかされた。本当に自分の人生にとって効いてくる軸は、実はそのうちの2つか3つくらいしかなかったはずなのに、駅からの距離や築年数、周辺のコンビニの数といった、正直そこまで重要ではない項目まで同じ重みで足し合わせて、「総合点」で選んでいた。次に何かを本気で比較するときは、まず「本当に効いてくる軸は何個で、それは何か」を先に絞り込んでから、比較を始めようと思う。項目を増やすことは、情報を増やしているようで、実は判断そのものを薄めてしまっていることがある。
このブログでは、機械学習の仕組みを実際にコードで実装して確かめた実験をテーマ別に整理しています(拡散モデル・Transformer・強化学習・多様体学習・過学習など)。


