PythonでゼロからTF-IDFを実装して理解する:RAG・検索システムの基礎技術
出典: engchina

TF-IDF(Term Frequency-Inverse Document Frequency)は、検索エンジンやRAGシステムの根幹を支える技術です。本記事では、Pythonによるスクラッチ実装を通じて、なぜこのアルゴリズムがLLM時代の今も重要なのか、実装の仕組みと実践への応用を解説します。
RAG時代だからこそ知っておきたい基礎技術
LLMと組み合わせたRAG(Retrieval-Augmented Generation)が注目される今、情報検索の基礎技術への理解がより重要になっています。埋め込みベクトルやベクトルDBが主流になりつつある中で、**TF-IDF(Term Frequency-Inverse Document Frequency)**という古典的アルゴリズムは依然として多くの実用システムで活躍しています。
今回紹介するのは、このTF-IDFをPythonでゼロから実装したコード例です。ライブラリに頼らず自分で実装することで、検索アルゴリズムの本質的な仕組みを理解できます。
TF-IDFの仕組みと実装のポイント
TF-IDFは、文書中の単語の重要度を数値化する手法です。2つの指標を掛け合わせることで機能します:
TF(Term Frequency):単語の出現頻度
tf = word_count / total_words_in_document文書内でその単語が何回出現するかを示します。「ねこ」が2回出現する文書では、TFが高くなります。
IDF(Inverse Document Frequency):希少性の指標
idf = math.log(total_documents / documents_containing_word)全文書の中でその単語が珍しいほど、IDF値が高くなります。「公園」が全文書に登場すれば重要度は下がり、特定の文書にしか登場しない「ねこ」の価値が上がります。
スコアリングの実装
実装コードでは以下の流れで検索スコアを計算します:
1. 全文書から単語の出現回数をカウント(`Counter`を使用)
2. 各単語のIDF値を事前計算
3. クエリ内の各単語について、文書ごとにTF-IDFスコアを算出
4. スコアを合計して文書をランキング
このシンプルな計算式が、Googleの初期検索エンジンやElasticsearchのベースにもなっている技術です。
編集部の視点
ベクトル検索との使い分けが重要
TF-IDFは2024年以降、埋め込みベクトルによるセマンティック検索に押されがちですが、実は**両者は補完関係**にあります。
**TF-IDFが優れている場面:**
**ベクトル検索が優れている場面:**
実際の商用RAGシステムでは、**ハイブリッド検索**が主流になっています。TF-IDFで候補を絞り込み、ベクトル検索で再ランキングする手法は、精度とコストのバランスが優れています。
実装で学ぶメリット
ライブラリ(scikit-learnの`TfidfVectorizer`など)を使えば1行で済む処理を、あえてスクラッチ実装する価値は何でしょうか?
1. **ブラックボックスの中身が見える**:デバッグやチューニング時に本質的な問題を特定できる
2. **カスタマイズの自由度**:日本語特有の処理(助詞の扱い、複合語処理)を柔軟に追加可能
3. **教育効果**:チームメンバーへの技術移転がスムーズ
特に生成AIをプロダクトに組み込む際、「なぜこの文書が検索されたのか」を説明できることは信頼性の観点で重要です。
注意すべき限界
実装例のコードは教育目的として優れていますが、本番環境では以下の拡張が必要です:
今日から試せるアクション
1. 自分のデータで動かしてみる
# 自分のメモやドキュメントでテスト
documents = [
"昨日のミーティングで決まった仕様変更",
"来週のリリースに向けたタスク整理",
"バグ修正の優先順位リスト"
]
query = "リリース タスク"手元のテキストデータに置き換えて実行すると、検索の挙動を直感的に理解できます。
2. スコアリングの可視化
各単語のTF-IDF値を出力する処理を追加してみましょう:
for word in query_words:
print(f"{word}: IDF={idf_values[word]:.3f}")
for doc_id, doc in enumerate(documents):
tf = doc_counter[word] / sum(doc_counter.values())
print(f" Doc{doc_id}: TF={tf:.3f}, TF-IDF={tf * idf_values[word]:.3f}")どの単語がスコアに寄与しているか可視化できます。
3. RAGパイプラインの第一段階として組み込む
LangChainやLlamaIndexを使っている場合、カスタムRetrieverとしてTF-IDF検索を追加できます。ベクトル検索の前段フィルタとして使うと、API呼び出しコストを削減できます。
まとめ
TF-IDFは50年以上の歴史を持つ技術ですが、その原理は今日のAI検索システムにも脈々と受け継がれています。埋め込みベクトルが万能ではない今、基礎技術を理解し使い分けられるエンジニアの価値はむしろ高まっています。
まずはこのコードを実行し、自分のデータで試してみてください。検索の仕組みを体感することが、より高度なRAGシステム構築への第一歩になります。
この情報は @engchina さんの投稿を参考にしています。
出典: engchina

