Agroxis
← Tech Blog 一覧へ
2026年7月3日

TF-IDF

TF-IDFAIPythonLLM
TF-IDF

まず初めに、TF-IDFについて簡単に説明します。

1.TF(Term Frequency:単語頻度)

特定の文書内で、ある単語が出現する頻度を表します。計算方法はいくつかありますが、最も基本的な方法は以下の通り。

TF = (対象単語の出現回数) / (文書内の総単語数)

文書:「私たちが目指すものは、データとAIの力で人と可能性をつなぎ、世界に新しい価値を生む。データと誠実に向き合い、最も信頼されるプラットフォームを目指します。」

上記文章があった場合、以下を求める。

1.”データ”という単語の出現回数:2回

2.総単語数:19単語

3.TF=2/19=0.95

※TFの値は0<TF<1

値が大きければ大きいほど、文書においてその単語が重要であることを指す。

2.IDF(Inverse Document Frequency:逆文書頻度)

IDFは文書集合全体で、その単語がどれだけ珍しいかを表します。計算式は以下の通り。

IDF = log(全文書数 / その単語を含む文書数)

文章10個のうち、”データ”という単語を含む文書が4つあった場合

1.IDF=log(10/4)=log(2.5)=0.40

値が大きければ大きいほど、文書全体においてその単語が珍しい単語であることを指す。

TF-IDF = TF × IDF

上記計算方法で単語の重要度を測ることができる。

Sample Python Code

import math
import numpy as np
from collections import Counter

class TFIDFCalculator:
    def __init__(self, tf_scheme='raw', idf_scheme='standard', normalization='l2'):
        """
        TF-IDF計算器
        
        Parameters:
        - tf_scheme: 'raw', 'log', 'double_norm'
        - idf_scheme: 'standard', 'smooth', 'max'
        - normalization: 'l1', 'l2', 'max', None
        """
        self.tf_scheme = tf_scheme
        self.idf_scheme = idf_scheme
        self.normalization = normalization
        
    def calculate_tf(self, text, tf_max=None):
        """異なるTF計算手法"""
        words = text.split()
        word_count = len(words)
        word_freq = Counter(words)
        
        if self.tf_scheme == 'raw':
            # 生の頻度を文書長で正規化
            tf_dict = {word: freq / word_count for word, freq in word_freq.items()}
        elif self.tf_scheme == 'log':
            # 対数正規化
            tf_dict = {word: 1 + math.log(freq) for word, freq in word_freq.items()}
        elif self.tf_scheme == 'double_norm':
            # 二重正規化(最大頻度との比)
            max_freq = max(word_freq.values())
            tf_dict = {word: 0.5 + 0.5 * (freq / max_freq) for word, freq in word_freq.items()}
        
        return tf_dict
    
    def calculate_idf(self, documents):
        """異なるIDF計算手法"""
        N = len(documents)
        idf_dict = {}
        all_words = set(word for doc in documents for word in doc.split())
        
        for word in all_words:
            df = sum(1 for doc in documents if word in doc.split())
            
            if self.idf_scheme == 'standard':
                idf_dict[word] = math.log(N / df)
            elif self.idf_scheme == 'smooth':
                # スムージング付き
                idf_dict[word] = math.log(N / (1 + df)) + 1
            elif self.idf_scheme == 'max':
                # 最大値正規化
                max_df = max(sum(1 for doc in documents if w in doc.split()) for w in all_words)
                idf_dict[word] = math.log(max_df / df)
        
        return idf_dict
    
    def normalize_vector(self, tfidf_dict):
        """ベクトル正規化"""
        if self.normalization is None:
            return tfidf_dict
        
        values = list(tfidf_dict.values())
        
        if self.normalization == 'l1':
            norm = sum(abs(v) for v in values)
        elif self.normalization == 'l2':
            norm = math.sqrt(sum(v**2 for v in values))
        elif self.normalization == 'max':
            norm = max(values)
        
        if norm == 0:
            return tfidf_dict
        
        return {word: score / norm for word, score in tfidf_dict.items()}
    
    def calculate_tfidf(self, documents):
        """TF-IDFを計算"""
        idf_dict = self.calculate_idf(documents)
        tfidf_documents = []
        
        for doc in documents:
            tf_dict = self.calculate_tf(doc)
            tfidf_dict = {word: tf * idf_dict[word] for word, tf in tf_dict.items()}
            tfidf_dict = self.normalize_vector(tfidf_dict)
            tfidf_documents.append(tfidf_dict)
        
        return tfidf_documents

# 使用例
calculator = TFIDFCalculator(tf_scheme='log', idf_scheme='smooth', normalization='l2')
tfidf_results = calculator.calculate_tfidf(documents)

# 結果比較
print("高度な実装での結果:")
for i, doc_tfidf in enumerate(tfidf_results):
    print(f"文書{i+1}のTF-IDF上位3語:")
    for word, score in sorted(doc_tfidf.items(), key=lambda x: x[1], reverse=True)[:3]:
        print(f"  {word}: {score:.4f}")
    print()

手軽に使える一方で、この手法だけでは以下の点がデメリットになりうる。

・単語の順序を考慮できない。

・同義語や略語を区別できない。

・文章の長さに影響を受ける。※長い文章であればあるほど有利になる

・誤字脱字を希少語としてスコアリングしてしまう。