ノート4.2 コサイン類似度って何?

(注意)本作のデータは全て2021年1月19日から20日にかけて取得されたものです。


 ――――――――――――――――


「ねぇ、タケル君。こっちの服とこっちの服、どっちが良いと思う?」


 俺――研究所主任研究員マッドサイエンティスト草薙くさなぎタケルが研究室に入っていくと、スマホでネットショッピングをしていた研究助手アシスタントとう景子けいこが近づいてきた。


「そうだなぁ。こっちの方が春らしくていいんじゃないか?」

「やっぱりそう思う? でも、こっちもお薦めされてて迷ってるんだよなー」

「お薦め?」

「そう。ネットでお買い物をしてたらさ、あなたに興味がありそうな商品がありますって表示されるじゃない」

「あぁ、なるほど。商品推薦――レコメンデーションか」

「これって、一体どんな仕組みになってるんだろうね?」

「方法論は色々ある。エキスパートシステムベースの古典的な推論だったり、行列分解だったり」

「カクヨムにも『関連小説』ってのがあるよね」

「うん。流石にそっちの仕組みは謎だけどな」

「そっかー」

「と言うことで、仕組みが分からないなら自分で作っちゃえと思い立ったのだよ」

「え、本気で言ってる?」

「本気と書いてマジ」

「じゃぁ、今日は小説推薦の話をするのかしら」

「それをするにはあまりに準備不足だ。まずは、どんな小説同士が似ているかについて調べる必要がある。今回注目するのは『タグ』だ」

「タグかー。『書き手』の人が好きに8個設定出来るのよね」

「その通りだ。以前の研究ノートで調査したように、タグは8割以上の小説に付いている。つまり、小説が似ているかどうかを調べるにはうってつけの素材なんだ」

「元々、小説を分類するための機能だもんね。自分の作品はこんなものですよってアピールしてるわけだし」

「そうだな。そして、今回使うテクニックはコサイン類似度だ」

「ゴーサイン、ルイージだ!」

「赤い人に変わって、緑の人がステージに突入していくのかな?

 コサイン類似度るいじどとは、2つのベクトル a と b があったとき、a と b の成す角のコサインで定義される。今後の研究ノートでひたすらこれが出てくるから、ここで是非覚えて欲しい」

「いや、覚えてと言っても難しいよー……。タケル君が何を言ってるのかさっぱり分からなかったわ。お願いだからもうちょっと易しい説明にならない?」

「ベクトルは何か分かる?」

「高校生のときに習った記憶はあるんだけど、すっかり忘れちゃった。それに私文系だったし」

「ベクトルくらいは文系理系関係なく習ってると思うが……まぁ、ここは重要なところだし、基礎から復習することにしよう」

「低年齢の『読み手』――例えば、中学生にも分かるように説明してね」

「努力するよ。

 ベクトルとは、簡単に言ってしまうと数字を並べたものだ。例えば、こんな風に表すことが出来る」


 ――――――――――――――――

 ベクトル

 ――――――――――――――――

 a = (a₁, a₂, a₃, a₄) 例:a = (0, 1, 2, 3)

 b = (b₁, b₂, b₃, b₄) 例:b = (0.4, 0.5, 0.6, 0.7)

 ――――――――――――――――


「なんか、こんな感じの書き方に見覚えがあるわ」

「だろうな。a や b をベクトル、a₁ や b₄ 等をベクトルの要素、ベクトルが持つ要素の個数をサイズとか次元と言ったりする。つまり、上の例だと a と b は両方とも4次元だな。

 さて、普通の数字で足し算やかけ算が出来るように、ベクトルも様々な計算が出来る。今回使うのは、ベクトルのとベクトル同士のだ。それぞれ、こんな感じで計算出来る」


 ――――――――――――――――

 ベクトルの大きさ

 ――――――――――――――――

 |a| = √(a₁² + a₂² + a₃² + a₄²) 例:|a| = √(0² + 1² + 2² + 3²) ≒ 3.741

 ――――――――――――――――


 ――――――――――――――――

 内積

 ――――――――――――――――

 a ドット b = (a₁, a₂, a₃, a₄) ドット (b₁, b₂, b₃, b₄) = a₁×b₁ + a₂×b₂ + a₃×b₃ + a₄×b₄

 例:a ドット b = (0, 1, 2, 3) ドット (0.4, 0.5, 0.6, 0.7)

      = 0×0.4 + 1×0.5 + 2×0.6 + 3×0.7 = 3.8

 ――――――――――――――――


「言葉で説明すると、ベクトルの大きさはそれぞれの要素を2乗して、全部足して、それの平方根を取る。内積は、2つのベクトルの要素同士を前から順番にかけ算して、全部足し合わせればいいだけだ」

「順番は関係あるの?」

「関係ある。1番目同士なら1番目同士、2番目同士なら2番目同士と、必ず同じ順番同士でかけ算するのが約束事だ。

 さて、これでコサイン類似度を計算する準備が整った。ベクトルの大きさとベクトル同士の内積を使って、コサイン類似度は次のように計算するぞ」


 ――――――――――――――――

 コサイン類似度 sim (Cosine similarity)

 ――――――――――――――――

 sim(a, b) = a ドット b / (|a|×|b|)

 ――――――――――――――――


「単に内積の値をベクトルの大きさで割るだけね。意外に簡単だったわ。それで、これにはどんな意味があるの?」

「さっきは説明しなかったけど、ベクトルは大きさの他に向きを表すことが出来るという特徴を持っている。そしてサイン類似度は、2つのベクトルが向いている方向が近いかどうかを表しているんだ」

「似たものに興味を持っていたら、向く方向が同じになるってことかしら?」

「その通りだ。ここで重要なのは、コサイン類似度が必ず-1 以上 1 以下の値しか取らないと言うこと。そして、1 に近ければ近いほどベクトル a と b の類似度が高く、-1 になればなるほど類似度が低いと解釈出来るんだ!」

「ふーん、なんか不思議……」

「なんか反応が薄いな」

「いや、まだ漠然としててイメージが沸かないの」

「なるほど。それじゃぁ、今日のメインテーマであるタグ同士の類似度を計算してみよう。今回は下の例で考えるぞ」


 ――――――――――――――――

 例:4作品に付いているタグ

 ――――――――――――――――

 小説 1:恋愛、学園、日常

 小説 2:魔法、異世界、学園

 小説 3:短編、恋愛、学園、コメディ

 小説 4:現代、恋愛、青春、日常

 ――――――――――――――――

 タグ:9種類

 ――――――――――――――――

 恋愛、学園、日常、魔法、異世界、短編、コメディ、現代、青春

 ――――――――――――――――


「まぁ、普通にありそうなタグの組合せね。ここからどうするの?」

「小説のタグをベクトルとして数値化する」

「はい、ストップ。タケル君、タグって言葉だよ? 全然数字じゃないわよ? 早くも詰んだ!」

「慌てない慌てない。ちゃんとやれば出来るから。今から考えるのはタグの『出現頻度』だ」

「出現頻度?」

「つまり、そのタグが小説に使われた回数だ。もし、2つのタグに関連があるなら、一緒に出てくる回数も多くなっているはずで、今回はこの性質を利用してコサイン類似度を計算していく」

「なるほど。確かに、何かしらのグループが出来そうね」

「タグをベクトル化するためには、2段階のステップを踏む。まずは、小説に付けられたタグの頻度をベクトル化しよう。

 1段階目のベクトル化では、全ての小説に対してタグの種類と同じ次元のベクトルを準備して、ベクトルの要素はその小説に付けられたタグの個数にするんだ。例だとタグが9種類あるから、9次元のベクトルと言うことになる。

 まぁ、例を見た方が分かるだろう。こんな感じだ」

「んー? どれどれ……」


 ――――――――――――――――

 タグのベクトル化(1段階目)

 ――――――――――――――――

    恋愛 学園 日常 魔法 異世界 短編 コメディ 現代 青春

 小説 1 = (1, 1, 1, 0,  0,  0,  0,   0,  0)

 小説 2 = (0, 1, 0, 1,  1,  0,  0,   0,  0)

 小説 3 = (1, 1, 0, 0,  0,  1,  1,   0,  0)

 小説 4 = (1, 0, 1, 0,  0,  0,  0,   1,  1)

 ――――――――――――――――


「どう? 分かった?」

「なるほど。小説 1 には恋愛、学園、日常のタグが付いているから、それぞれ 1 番目、2 番目、そして3 番目のベクトルの要素が 1 になってるのか。それ以外のタグは付けられてないから全部 0 っと。あっさりベクトル化出来ちゃった……」

「そう言うこと。もちろん他も全部同じ法則で 0 か 1 になってる」

「じゃぁ、これを使ってコサイン類似度を――」

「ちょっと待った!」

「え、何?」

「今のベクトルは小説に注目したものだ。まだタグのベクトル化になってない」

「あ、本当だ」

「と言うことで、2 段階目は 1 段階目のベクトルを使ってタグのベクトル化を行う。

 まず、あるタグに注目して、そのタグが付いている小説だけを集めるんだ。ケイコちゃん、書き出してくれない?」

「分かったわ」


 ――――――――――――――――

 恋愛タグが付いている小説だけをピックアップ

 ――――――――――――――――

    恋愛 学園 日常 魔法 異世界 短編 コメディ 現代 青春

 小説 1 = (1, 1, 1, 0,  0,  0,  0,   0,  0)

 小説 3 = (1, 1, 0, 0,  0,  1,  1,   0,  0)

 小説 4 = (1, 0, 1, 0,  0,  0,  0,   1,  1)

 ――――――――――――――――


「――こんな感じかな?」

「完璧だ」

「これはどういう意味があるのかしら」

「これらのベクトルは、恋愛タグと共に現れているタグが集まっている。つまり、恋愛タグと関係のあるタグとみなせるんだ」

「なるほど!」

「と言うことで、これを全部足し算して『注目しているタグと共に現れた他のタグの頻度』をそのタグのベクトルとする。

 ちなみに、ベクトルの足し算は要素同士の足し算をすることね。元のベクトルと同じ次元のベクトルになるはずだ。ケイコちゃん、やってみて」

「要素同士を足し合わせればいいのね」


 ――――――――――――――――

 恋愛タグが付いている小説のベクトルを足し算して新しいベクトルを作成(2段階目)

 ――――――――――――――――

  恋愛 = 小説 1+小説 3 + 小説 4

    = (3, 2, 2, 0, 0, 1, 1, 1, 1)

 ――――――――――――――――


「これで合ってる?」

「正解だ。学園タグは『小説 1+小説 2 + 小説 3』、日常タグは『小説 2+小説 4』と言った具合に、他のタグも全てこのような計算を行う。そして、得られるのが次のようなベクトル達だ」


 ――――――――――――――――

 タグのベクトル化が完了

 ――――――――――――――――

 恋愛 = (3, 2, 2, 0, 0, 1, 1, 1, 1)

 学園 = (2, 3, 1, 1, 1, 1, 1, 0, 0)

 日常 = (2, 1, 2, 0, 0, 0, 0, 1, 1)

 魔法 = (0, 1, 0, 1, 1, 0, 0, 0, 0)

 異世界 = (0, 1, 0, 1, 1, 0, 0, 0, 0)

 短編 = (1, 1, 0, 0, 0, 1, 1, 0, 0)

 コメディ = (1, 1, 0, 0, 0, 1, 1, 0, 0)

 現代 = (1, 0, 1, 0, 0, 0, 0, 1, 1)

 青春 = (1, 0, 1, 0, 0, 0, 0, 1, 1)

 ――――――――――――――――


「おおお、タグが数字になった。ベクトルになったよ、タケル君!」

「な? ちゃんとやれば出来るんだよ。

 さー、皆さんお待ちかね。タグのベクトル化が完了したので、ようやくコサイン類似度の計算だ。後は定義通りに計算して行くだけなので、計算過程は省略しよう。

 恋愛タグと他のタグのコサイン類似度を計算すると、こんな結果になる」


 ――――――――――――――――

 恋愛タグのコサイン類似度 sim

 ――――――――――――――――

 sim(恋愛, 恋愛) = 1.00

 sim(恋愛, 学園) = 0.8229512

 sim(恋愛, 日常) = 0.921132373

 sim(恋愛, 魔法) = 0.251976315

 sim(恋愛, 異世界) = 0.251976315

 sim(恋愛, 短編) = 0.763762616

 sim(恋愛, コメディ) = 0.763762616

 sim(恋愛, 現代) = 0.763762616

 sim(恋愛, 青春) = 0.763762616

 ――――――――――――――――


「おー、なんかそれっぽい値になってる!」

「でしょ?」

「自分自身の類似度を計算したらちゃんと 1 になるのね」

「まぁ、数学的にそう言う定義になってるからな。こんな感じで全ての組合せについてコサイン類似度を計算すると、下のような表を作ることが出来るぞ」


 ――――――――――――――――――――――――――――――

 コサイン類似度の行列

 ――――――――――――――――――――――――――――――

      恋愛 学園  日常  魔法 異世界 短編 コメディ 現代 青春

 ――――――――――――――――――――――――――――――

 恋愛   1.00 0.82 0.92 0.25 0.25 0.76 0.76 0.76 0.76

 学園   0.82 1.00 0.64 0.68 0.68 0.82 0.82 0.35 0.35

 日常   0.92 0.64 1.00 0.17 0.17 0.45 0.45 0.90 0.90

 魔法   0.25 0.68 0.17 1.00 1.00 0.29 0.29 0.00 0.00

 異世界  0.25 0.68 0.17 1.00 1.00 0.29 0.29 0.00 0.00

 短編   0.76 0.82 0.45 0.29 0.29 1.00 1.00 0.25 0.25

 コメディ 0.76 0.82 0.45 0.29 0.29 1.00 1.00 0.25 0.25

 現代   0.76 0.35 0.90 0.00 0.00 0.25 0.25 1.00 1.00

 青春   0.76 0.35 0.90 0.00 0.00 0.25 0.25 1.00 1.00

 ――――――――――――――――――――――――――――――


「すごーい!」

「ちなみ、コサイン類似度の行列はベクトルの次元の正方対称行列になる。この例だと 9×9 次元だ。そして対称だから、行から見ても列から見ても同じ解釈になるよ。

 この例だと、恋愛に最も近いタグは 0.92 の日常ということになる。最も遠いのは 0.25 の魔法と異世界。一方、異世界に1番違いタグは学園ということを示しているぞ」

「でも、これはあくまで例よね。実際のデータで同じ事を計算したんでしょ?」

「うん」

「その結果を教えてよ」

「分かった。まずはタグの基本情報から見てみよう。これは研究ノート1.13からの再掲だ」


 ――――――――――――――――

 統計情報:タグとセルフレイティング(2021年1月20日)

 ――――――――――――――――

 タグもしくはセルフレイティングが付いている作品:181,583作品

 種類:114,413種類 + セルフレイティング3種類

 ――――――――――――――――

 研究ノート1.13『ノート1.13 215,590作品って、どんなタグとセルフレイティングがついてるの?』

https://kakuyomu.jp/works/1177354055450204744/episodes/16816452218428395547

 ――――――――――――――――


「ん? ベクトルの要素の数――次元数だっけ――は、ベクトルの種類だったわよね」

「そうだな」

「つまり……114,416次元ってこと?」

「そうだ! ――と言いたいところだが、流石に計算機パソコンの能力に限界があった。愚直に11万次元で計算を始めたところ、5日経っても未だに結果が出力されてこない」

「それはそうでしょう! いくらなんでも11万次元は無茶よっ」

「と言うことで多少次元を削減した。出現頻度が 9 回未満のタグを破棄したら、タグの数はこうなった」


 ――――――――――――――――

 統計情報:出現頻度が 9 回未満のタグを破棄

 ――――――――――――――――

 タグもしくはセルフレイティングが付いている作品:183,022作品

 種類:6,757種類(セルフレイティング込み+作品ジャンル)

 ――――――――――――――――


「それでも7千種類……。しかも、何故か関わってる作品数が増えてるじゃない! なんで?」

「あぁ、言い忘れてた。タグを調べたときにジャンルと同じ名前のタグがいっぱいあることが分かったから、作品のジャンル44種類もタグ扱いにして組み込んでみたんだ」

「44種類? そんなにジャンルないんじゃ――」

「2次創作の作品が結構あるんだよ」

「あ、なるほど……」

「と言うことで、6,757種類のタグでコサイン類似度の計算を行った。8時間48分42秒4928かけた計算結果をご覧あれ!」

「9時間!?」


 ―――――――――――――――――――――――――――――――――――

 コサイン類似度の行列(出現頻度が 9 回以上のタグ)

 ―――――――――――――――――――――――――――――――――――

           異フ 異 魔 剣魔 異転 ハフ 異移 現主 異召……

 ―――――――――――――――――――――――――――――――――――

 異世界ファンタジー 1.00 0.84 0.82 0.82 0.81 0.80 0.80 0.80 0.80

 異世界       0.84 1.00 0.74 0.71 0.63 0.68 0.64 0.67 0.66

 魔法        0.82 0.74 1.00 0.64 0.71 0.70 0.70 0.67 0.68

 剣と魔法      0.82 0.71 0.64 1.00 0.67 0.72 0.68 0.72 0.66

 異世界転生     0.81 0.63 0.71 0.67 1.00 0.64 0.66 0.62 0.65

 ハイファンタジー  0.80 0.68 0.70 0.72 0.64 1.00 0.65 0.71 0.63

 異世界転移     0.80 0.64 0.70 0.68 0.66 0.65 1.00 0.64 0.68

 現地主人公     0.80 0.67 0.67 0.72 0.62 0.71 0.64 1.00 0.64

 異世界召喚     0.80 0.66 0.68 0.66 0.65 0.63 0.68 0.64 1.00


 ……


 四行四連詩    0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00

 美型詩      0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00

 20の質問     0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00

 東芝       0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00

 カクヨム作者への 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00

 10の質問

 ―――――――――――――――――――――――――――――――――――

 ごくごくごく(中略)ごく一部の結果(※6,757×6,757次元)

 ―――――――――――――――――――――――――――――――――――


「はい無理! 入りきるわけない!」

「あったり前じゃない! 6,757×6,757次元の行列をどうやって書こうと思ってたわけ!?」

「だよねー」

「タケル君、たまーに抜けてるところある……。まぁ、そこが可愛いんだけど」

「ん? 何か言った?」

「いいえ、別に」




「とりあえず、相当研究ノートのページを使ったので今回はここまでだな」

「そうね。私も結構疲れたわ」

「次回は、実際に得られたコサイン類似度行列を使って色々な考察を行っていくぞ」

「分かったわ。タケル君、次回までに『サイズ大きすぎる問題』の解決法を考えてきなさいよ?」

「出来るかなー……」

「やるったらやる! タケル君なら出来る!」

「は、はいーっ」



 ――――――――――――――――

 今日の研究ノートまとめ

 ――――――――――――――――

 ・コサイン類似度の計算方法を紹介

 ・コサイン類似度は今後頻出するので是非覚えて欲しい

 ・滅茶苦茶時間をかけて計算したのに結果を紹介しきれないーっ!!

 ――――――――――――――――

  • Twitterで共有
  • Facebookで共有
  • はてなブックマークでブックマーク

作者を応援しよう!

ハートをクリックで、簡単に応援の気持ちを伝えられます。(ログインが必要です)

応援したユーザー

応援すると応援コメントも書けます

新規登録で充実の読書を

マイページ
読書の状況から作品を自動で分類して簡単に管理できる
小説の未読話数がひと目でわかり前回の続きから読める
フォローしたユーザーの活動を追える
通知
小説の更新や作者の新作の情報を受け取れる
閲覧履歴
以前読んだ小説が一覧で見つけやすい
新規ユーザー登録無料

アカウントをお持ちの方はログイン

カクヨムで可能な読書体験をくわしく知る