← Tech Blog 一覧へ
2026年7月3日
TF-IDF
TF-IDFAIPythonLLM

まず初めに、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()
手軽に使える一方で、この手法だけでは以下の点がデメリットになりうる。
・単語の順序を考慮できない。
・同義語や略語を区別できない。
・文章の長さに影響を受ける。※長い文章であればあるほど有利になる
・誤字脱字を希少語としてスコアリングしてしまう。
