本記事では、R言語を使用した自然言語処理の実践的な手法として、TF-IDFと類似度行列を用いた文書分類について解説します。この手法は、任意のテキストが既存のどの文書カテゴリに最も類似しているかを判断するために使用できます。
1. データ準備
まず、分析対象のデータを読み込みます。ここではCSVファイルからデータをインポートし、必要な前処理を行います。
library(tidyverse)
library(data.table)
# データ読み込みと前処理
fread("classification_corpus_raw.csv", encoding = "UTF-8") %>%
as_tibble() %>%
mutate(doc_id = row_number()) -> document_data
2. TF-IDFの計算
次に、テキストデータを単語に分割し、TF-IDF値を計算します。TF-IDFは、単語の重要度を評価するための指標です。
# 形態素解析ライブラリの読み込み
library(RMeCab)
# テキストの分割とTF-IDF計算
document_data %>%
mutate(tokens = map(title, function(x) unlist(RMeCabC(x)))) %>%
select(doc_id, tokens) %>%
unnest() %>%
count(doc_id, tokens) %>%
bind_tf_idf(term = tokens, document = doc_id, n = n) -> tfidf_matrix
# ユニークな単語数を確認
unique_words <- tfidf_matrix %>% distinct(tokens)
cat("ユニークな単語数:", nrow(unique_words), "\n")
ここでは、文書-単語行列を明示的に作成する代わりに、tidyなデータ構造を維持したまま処理を進めます。これにより、メモリ効率を向上させることができます。
# 後で使用するためにIDとTF-IDF値を保存
tfidf_matrix %>%
select(doc_id, tf_idf) -> similarity_data
3. 文書類似度の計算
ここでは、与えられたテキストと既存文書間の類似度を計算する関数を作成します。類似度は、共通の単語とそのTF-IDF値に基づいて計算されます。
まず、テスト用の文字列「データサイエンス学部」を使用して、類似文書を検索してみましょう。
test_text <- "データサイエンス学部"
# テストテキストのトークン化
test_tokens <- unlist(RMeCabC(test_text)) %>%
enframe() %>%
transmute(tokens = value)
# 類似度計算
similarity_data %>%
inner_join(test_tokens, by = "tokens") %>%
group_by(doc_id) %>%
summarise(similarity_score = sum(tf_idf)) %>%
arrange(desc(similarity_score)) %>%
head(5) %>%
inner_join(document_data, by = "doc_id") -> similar_docs
# 結果の表示
similar_docs
この結果から、「データサイエンス学部」に最も類似した文書が正しく特定されていることがわかります。2番目に類似した文書は「データサイエンス研究所」であり、「データサイエンス」という重要な単語を共有しているため高い類似度を示しています。
4. 文書分類関数の実装
上記の処理を一般化し、任意のテキストに対して最も類似した文書を返す関数を実装します。
classify_document <- function(input_text) {
# 入力テキストのトークン化
input_tokens <- unlist(RMeCabC(input_text)) %>%
enframe() %>%
transmute(tokens = value)
# 類似度計算
similarity_data %>%
inner_join(input_tokens, by = "tokens") %>%
group_by(doc_id) %>%
summarise(similarity_score = sum(tf_idf)) %>%
arrange(desc(similarity_score)) %>%
head(3) %>%
inner_join(document_data, by = "doc_id") -> result
# 結果の整形
if (nrow(result) == 0) {
return(NA_character_)
} else {
return(str_c(result$title, collapse = ","))
}
}
この関数は、入力テキストに類似した文書が見つからない場合はNAを返し、見つかった場合は類似度が高い順に最大3つの文書タイトルをカンマ区切りで返します。
実際に関数を試してみましょう。
# 存在しない単語を含むテキスト
classify_document("存在しない単語")
# [1] NA
# 関連する単語を含むテキスト
classify_document("データサイエンス")
# [1] "データサイエンス研究所,データサイエンス学部,データサイエンスセンター"
このように、TF-IDFと類似度行列を用いたシンプルな手法でも、効果的な文書分類が実現できます。特に計算リソースが限られている環境や、迅速なプロトタイプ作成が必要な場合に有効なアプローチです。