本文へスキップ
BecomeCoder

RAGコース · 第3章 ベクトルと検索 · レッスン10

コサイン類似度で「近さ」を測る

ブラウザで完結

導入

文章をベクトルに変換できたら、次はベクトル同士がどれだけ「似ているか」を数値化します。定番の指標がコサイン類似度です。1に近いほどよく似ていて、0に近いほど無関係です。

説明

import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.feature_extraction.text import TfidfVectorizer

docs = [
    "I love machine learning and data science",
    "Deep learning is a part of machine learning",
    "The weather today is sunny and warm",
]
vec = TfidfVectorizer().fit(docs)
mat = vec.transform(docs)

query = "machine learning"
q = vec.transform([query])
scores = cosine_similarity(q, mat)[0]

for doc, s in zip(docs, scores):
    print(f"{s:.3f}  {doc}")

vec.transform([query]) で、質問文 querydocs と同じ語彙・同じ基準でベクトルに変換します。cosine_similarity(q, mat) は、質問ベクトル q と各文書ベクトル mat向きの近さを計算します。結果を見ると、"machine learning" という語を含む1文目・2文目のスコアが高く、天気の話をしている3文目は低くなっているはずです。これがまさに検索の基本動作――質問に近い文書ほどスコアが高くなる――です。

コサイン類似度が「向き」だけを見て「長さ」を無視する指標だという点も重要です。長い文書ほど単語数が多くなりますが、ベクトルの長さで割って正規化するので、文書が長いか短いかにあまり影響されずに比較できます。

やってみよう

query"weather""data science" に変えて実行し直し、スコアの順位がどう入れ替わるか確かめてみましょう。

演習

scores の中で最もスコアが高い文書を、np.argmax を使って特定し、その文書(docs[インデックス])を print で表示してください。

ヒント1を見る

np.argmax(scores) は、配列の中で最大値を持つ要素の**インデックス(添字)**を返します。

ヒント2を見る

print(docs[np.argmax(scores)]) のように、そのインデックスで docs から文書を取り出します。

実際に動かしてみよう

下のエディタにPythonを書いて「実行」を押すと、scikit-learn(TF-IDF)とnumpyで本物の「検索」をその場で動かせます。RAGの検索フェーズ――文書のチャンク分割・ベクトル化・類似度計算・並べ替え――が実際に動きます。scikit-learn を使う回は初回の読み込みに数十秒かかることがあります。検索デモのサンプル文書は英語です(TF-IDFの既定トークナイザが日本語を分割できないため。日本語検索の対処は読み物で解説します)。LLMの生成や本物の埋め込みAPIは、APIキーが要るため読み物の回でコードを示します。

Python — ライブラリ付きで実行(Pyodide)

numpy / pandas / matplotlib が使える本物のPython(Pyodide)を読み込みます。初回のみ読み込みに少し時間がかかります(以降はブラウザにキャッシュされます)。
スクロールして表示された時点でも自動で読み込まれます。