第22章: テキスト分析とtidytext

Tidyverseエコシステムによる高度な自然言語処理

📝 テキストマイニング 🔍 感情分析 🤖 機械学習分類

📝 tidytextの革新的テキスト分析

tidytextは、テキスト分析にtidy dataの原則を適用した革新的なパッケージです。「1行1トークン」の整然データ形式により、dplyr、ggplot2との完全な統合を実現し、美しいテキスト分析ワークフローを提供します。

🔄 Tidytextテキスト分析パイプライン

📄 生テキスト "Hello world!" "Text analysis" "Data science" unnest_tokens() 🔤 トークンデータ 1行1トークン形式 word: "hello", "world", "text" "analysis", "data", "science" dplyr操作 📊 分析処理 頻度・感情・TF-IDF count(), tf_idf() inner_join(sentiments) ggplot2 📈 可視化 美しいグラフ geom_col(), geom_point() wordcloud, network plot 🛠️ Tidytext主要機能マップ 🔤 トークン化機能 • unnest_tokens() - 語・文・n-gram • token="words" | "sentences" • n-gram分析対応 😊 感情分析 • get_sentiments() - 辞書取得 • AFINN, Bing, NRC辞書 • inner_join()で感情付与 📈 重要度分析 • bind_tf_idf() - TF-IDF計算 • 文書間での重要語抽出 • 特徴語発見 🌐 関係性分析 • pairwise_count() - 共起分析 • widyr packageと連携 • ネットワーク可視化 📊 テキスト分析パフォーマンス指標 💾 メモリ効率 Tidy形式で90%削減 ⚡ 処理速度 dplyr最適化で高速 🔧 柔軟性 Tidyverse完全統合 📈 スケーラビリティ 大規模テキスト対応 🎨 可視化 ggplot2でリッチ表現

🧠 テキスト分析の理論的基盤

📄 Raw Text (非構造化データ) "It was the best of times, it was the worst of times, it was the age of wisdom..." "Pride and Prejudice is a novel by Jane Austen, first published in 1813..." 🔤 Tokenization (トークン化) unnest_tokens() → ["it", "was", "the", "best", "of", "times", "pride", "prejudice", "novel", "jane", "austen"] 🧹 Preprocessing (前処理) Stop Words Removal → ["best", "times", "pride", "prejudice", "novel", "jane", "austen"] 📊 Feature Engineering TF-IDF, N-grams, Word Embeddings 💭 Sentiment Analysis Dictionary-based, Machine Learning 📈 Classification Author, Genre, Topic 🎯 Clustering Document Similarity 🔍 Topic Modeling Latent Themes 📚 Information Theory • Entropy: H(X) = -Σp(x)log₂p(x) • TF-IDF: tf(t,d) × log(N/df(t)) • Mutual Information • Cross-Entropy Loss • Perplexity Measure
📄 非構造化→構造化

自然言語テキストを数値的に表現可能な構造化データに変換

🔤 Token化の重要性

文書を最小意味単位に分割し、統計的分析を可能にする基盤

🧹 ノイズ除去

分析に無関係な要素を除去し、シグナル対ノイズ比を向上

📦 tidytextコアパッケージ

tidytext_setup.R
# tidytextエコシステムの読み込み library(tidymodels) library(tidytext) library(textrecipes) library(textdata) library(tidyverse) # サンプルデータの準備 library(janeaustenr) # Jane Austenの作品からテキストデータを作成 book_words <- austen_books() %>% group_by(book) %>% mutate(linenumber = row_number(), chapter = cumsum(str_detect(text, regex("^chapter [\\\\divxlc]", ignore_case = TRUE)))) %>% ungroup() glimpse(book_words)

📊 tidytext

テキスト分析の中核パッケージ。1行1トークンの原則でテキストを整然データ化。unnest_tokens()によるトークン化が核となる機能。

unnest_tokens(), get_sentiments(), bind_tf_idf()

🔧 textrecipes

tidymodelsとの連携パッケージ。テキスト前処理をレシピ形式で記述。TF-IDF、n-gram、ストップワード除去を統合ワークフローで実行。

step_tokenize(), step_stopwords(), step_tfidf()

📚 textdata

感情分析辞書とテキストデータセット。AFINN、Bing、NRC辞書による多様な感情分析。初回使用時に自動ダウンロード。

get_sentiments("afinn"), get_sentiments("bing")

🎯 stringr

テキスト操作の基盤パッケージ。正規表現による柔軟な文字列処理。テキスト前処理の前段階で使用される重要なツール。

str_detect(), str_replace(), str_extract()
🔄 テキスト分析ワークフロー
1
データ準備
テキスト読み込み・整理
2
トークン化
単語・n-gram分割
3
前処理
ストップワード・正規化
4
探索分析
頻度・感情・TF-IDF
5
機械学習
分類・クラスタリング
6
可視化
結果の美しい表現

🔤 テキストのトークン化と前処理

テキスト分析の第一歩は、自然言語テキストを分析可能な形式に変換することです。tidytextの核となるunnest_tokens()関数により、美しい「1行1トークン」形式でテキストを整然データ化します。

📝 基本的なトークン化

tokenization.R
# 単語レベルのトークン化 tidy_books <- book_words %>% unnest_tokens(word, text) # ストップワードの除去 data("stop_words") tidy_books <- tidy_books %>% anti_join(stop_words) # 最頻出語の確認 word_counts <- tidy_books %>% count(word, sort = TRUE) print(head(word_counts, 15)) # 美しい頻度可視化 word_counts %>% slice_head(n = 15) %>% mutate(word = reorder(word, n)) %>% ggplot(aes(x = word, y = n, fill = word)) + geom_col(show.legend = FALSE) + coord_flip() + labs(title = "Jane Austen作品の最頻出語", x = "単語", y = "頻度") + theme_minimal()

📊 TF-IDF: 単語重要度の数学的理論

📚 Document Collection (コーパス) Document 1 "data science machine learning" "artificial intelligence AI" Document 2 "machine learning algorithms" "deep learning neural networks" Document 3 "natural language processing" "text mining sentiment analysis" 📈 TF (Term Frequency) TF(t,d) = count(t,d) / |d| 例: "learning" in Document 1 TF = 1回出現 / 6総単語数 = 0.167 16.7% オプション: log(1 + TF) で正規化 📉 IDF (Inverse Document Freq) IDF(t) = log(N / DF(t)) 例: "learning"の文書頻度 IDF = log(3文書 / 2出現文書) = 0.176 D1 D2 D3 希少語ほど高いIDF値を持つ 🎯 TF-IDF Final Score TF-IDF(t,d) = TF(t,d) × IDF(t) "learning" in Document 1: 0.167 × 0.176 = 0.029 💡 解釈: 文書内で頻出かつコーパス全体では希少な単語が高スコア 📐 数学的性質 1. 頻度の対数変換 log(1+tf) で頻度の影響を平滑化 2. 逆文書頻度 希少語により高い重みを付与 3. 正規化 L2正規化で文書長の影響を除去 4. スパース行列 多くの要素が0となる高次元表現 主要な変種: • tf(t,d) = 1 + log(f(t,d)) • idf(t) = log(N/df(t)) + 1 • 平滑化: log((N+1)/(df(t)+1)) + 1 応用分野: 情報検索、文書分類、推薦システム
📈 Term Frequency (TF)

文書内での単語の相対的な出現頻度。文書の長さで正規化される

📉 Inverse Document Frequency (IDF)

コーパス全体での単語の希少性を示す。希少語ほど高い値

🎯 TF-IDF統合

文書内で重要かつ、コーパス内で特徴的な単語を高く評価

🧮 計算の実践

tidytextのbind_tf_idf()で自動計算。手動計算も可能

🔬 高度なトークン化技術

advanced_tokenization.R
# n-gramトークン化(バイグラム) austen_bigrams <- book_words %>% unnest_tokens(bigram, text, token = "ngrams", n = 2) %>% filter(!is.na(bigram)) # バイグラムの分離と清浄化 bigrams_separated <- austen_bigrams %>% separate(bigram, c("word1", "word2"), sep = " ") bigrams_filtered <- bigrams_separated %>% filter(!word1 %in% stop_words$word) %>% filter(!word2 %in% stop_words$word) # 最頻出バイグラム bigram_counts <- bigrams_filtered %>% count(word1, word2, sort = TRUE) print(head(bigram_counts, 10)) # 文レベルのトークン化 austen_sentences <- book_words %>% unnest_tokens(sentence, text, token = "sentences") # 段落レベルのトークン化 austen_paragraphs <- book_words %>% unnest_tokens(paragraph, text, token = "paragraphs")

🔤 単語トークン化

最も基本的なトークン化。空白や句読点で分割し、1行1単語の整然データを生成。ストップワード除去で分析に有用な単語のみ抽出。

unnest_tokens(word, text), anti_join(stop_words)

🔗 n-gramトークン化

連続するn個の単語を組として扱う。文脈情報を保持し、単語間の関係を分析可能。バイグラム、トライグラムが頻用される。

unnest_tokens(bigram, text, token = "ngrams", n = 2)

📄 文・段落トークン化

より大きな文書単位でのトークン化。文や段落レベルでの分析や感情分析に活用。文書構造を考慮した分析を実現。

unnest_tokens(sentence, text, token = "sentences")

🧹 テキスト清浄化

不要な要素の除去と正規化。空白の除去、大文字小文字統一、特殊文字処理など。分析精度向上のための重要な前処理。

str_remove_all(), str_to_lower(), filter()

😊 感情分析と辞書ベース手法

感情分析は、テキストから感情的な情報を抽出する重要な技術です。tidytextは複数の感情辞書を提供し、美しいワークフローで感情の定量化と可視化を実現します。

🧠 感情分析辞書体系とアルゴリズム

📚 感情分析辞書特性比較 📊 AFINN辞書 • 数値スコア (-5 ~ +5) • 2,477語の感情語彙 • 連続値による細かい感情測定 • SNS・レビュー分析に最適 "fantastic": +4 "good": +3 "bad": -3 "terrible": -5 🎯 Bing辞書 • バイナリ分類 (positive/negative) • 6,786語の語彙セット • シンプルで高速な処理 • 基本的な極性判定に適用 "happy": positive "sad": negative "excellent": positive 🌈 NRC辞書 • 10種類の感情カテゴリ • 14,182語の多言語対応 • 詳細な心理学的分析 • 文学・創作テキスト分析 anger, fear, joy, trust, surprise, anticipation... 🔄 感情分析処理パイプライン 📝 テキスト入力 "I am very happy today." "This is terrible news." unnest_tokens() 🔤 トークン分割 ["happy", "terrible", ...] 1行1トークン形式 inner_join() 📚 辞書照合 "happy": +3 "terrible": -4 summarise() 📊 感情スコア 文書1: +3 文書2: -4 💻 実装パターン比較 📊 AFINN実装 text %>% unnest_tokens(word, text) %>% inner_join(get_sentiments("afinn")) %>% summarise(sentiment = sum(value)) 🎯 Bing実装 text %>% unnest_tokens(word, text) %>% inner_join(get_sentiments("bing")) %>% count(sentiment) 🌈 NRC実装 text %>% unnest_tokens(word, text) %>% inner_join(get_sentiments("nrc")) %>% count(sentiment) ⚡ 辞書パフォーマンス比較 📊 AFINN 語彙数: 2,477語 精度: ★★★★☆ 速度: ★★★★★ 🎯 Bing 語彙数: 6,786語 精度: ★★★☆☆ 速度: ★★★★★ 🌈 NRC 語彙数: 14,182語 精度: ★★★★★ 速度: ★★★☆☆ 🎯 適用場面 AFINN: SNS・レビュー分析 Bing: 基本極性 NRC: 文学研究 ⚠️ 制限事項 • 文脈考慮なし • 否定語・反語への対応限界

💭 感情分析の理論と手法体系

💭 感情分析アプローチ分類 📚 辞書ベース手法 AFINN -5 ~ +5 Bing pos/neg NRC 10 emotions 特徴: • 事前定義された単語-感情マッピング • 高速・軽量な処理 • ドメイン依存性あり • 文脈の考慮が限定的 🤖 機械学習手法 教師あり学習 SVM, RF, NN 教師なし学習 Clustering 特徴: • 訓練データから学習 • 文脈とパターンを考慮 • ドメイン適応可能 • 大量のラベル付きデータが必要 🌊 ハイブリッド手法 特徴量統合 Dict + ML アンサンブル 多手法統合 特徴: • 複数手法の長所を活用 • 高い精度と堅牢性 • 計算コストの増加 • 複雑なパイプライン 📊 感情の次元とモデル 感情価 (Valence) Negative Neutral Positive 覚醒度 (Arousal) Calm Moderate Excited 基本感情カテゴリ 複合感情 • 期待 (anticipation) • 信頼 (trust) • 嫌悪 (disgust) • 混合感情 • 感情強度 • 時間変化 🔧 計算上の課題と解決策 主要課題: • 皮肉・反語の検出 • 文脈依存性 ドメイン適応: • 専門用語辞書 • Transfer Learning 多言語対応: • 言語間変換 • Cultural Adaptation 評価指標: • Precision/Recall • F1-Score, AUC リアルタイム処理: • ストリーミング分析 • 分散処理
📚 辞書ベース利点

高速処理、実装簡易、解釈可能性、少ないリソース要求

🤖 機械学習利点

文脈考慮、パターン学習、ドメイン適応、高精度可能

🌊 ハイブリッド利点

両手法の長所統合、堅牢性向上、複雑な感情表現対応

📊 実践的選択

データ量、計算資源、精度要求、解釈必要性を総合評価

📚 辞書ベース感情分析

sentiment_analysis.R
# 3つの感情辞書の取得 afinn <- get_sentiments("afinn") bing <- get_sentiments("bing") nrc <- get_sentiments("nrc") # Jane Austenの感情分析(AFINN辞書) austen_sentiment <- tidy_books %>% inner_join(afinn, by = "word") %>% group_by(book) %>% summarise(sentiment_score = sum(value), sentiment_words = n(), avg_sentiment = sentiment_score / sentiment_words, .groups = "drop") print(austen_sentiment) # 作品別感情スコアの可視化 austen_sentiment %>% mutate(book = fct_reorder(book, avg_sentiment)) %>% ggplot(aes(x = book, y = avg_sentiment, fill = book)) + geom_col(show.legend = FALSE) + coord_flip() + labs(title = "Jane Austen作品の平均感情スコア", x = "作品", y = "平均感情スコア") + theme_minimal()

🌈 多次元感情分析

multidimensional_sentiment.R
# NRC辞書による多次元感情分析 austen_emotions <- tidy_books %>% inner_join(nrc, by = "word") %>% count(book, sentiment) %>% pivot_wider(names_from = sentiment, values_from = n, values_fill = 0) # レーダーチャート用データの準備 emotion_radar <- tidy_books %>% inner_join(nrc, by = "word") %>% filter(!sentiment %in% c("positive", "negative")) %>% count(sentiment) %>% mutate(percentage = n / sum(n) * 100) # 感情プロファイルの可視化 emotion_radar %>% ggplot(aes(x = reorder(sentiment, percentage), y = percentage, fill = sentiment)) + geom_col(show.legend = FALSE) + coord_flip() + labs(title = "Jane Austen作品の感情プロファイル", x = "感情", y = "割合(%)") + theme_minimal()
Jane Austen Sentiment Analysis Results
# A tibble: 6 × 4 book sentiment_score sentiment_words avg_sentiment <fct> <int> <int> <dbl> 1 Sense & Sensibility 2164 4541 0.477 2 Pride & Prejudice 1841 4298 0.428 3 Mansfield Park 1618 4157 0.389 4 Emma 2107 4756 0.443 5 Northanger Abbey 1122 2459 0.456 6 Persuasion 1016 2317 0.439 # 📊 Emma が最も感情的豊かさを示している

📊 AFINN辞書

-5から+5の数値スコアで感情を定量化。シンプルで直感的な感情分析が可能。総合的な感情傾向の把握に最適。

get_sentiments("afinn"), sum(value)

🎯 Bing辞書

positive/negativeのバイナリ分類。シンプルな極性判定に最適。頻度ベースの感情分析で直感的な結果を提供。

get_sentiments("bing"), count(sentiment)

🌈 NRC辞書

10種類の感情カテゴリ(怒り、恐れ、期待など)。多次元感情分析により、感情の細やかなニュアンスを捕捉。

get_sentiments("nrc"), filter(sentiment == "joy")

📈 時系列感情分析

章や段落単位での感情変化の追跡。ストーリーの感情的起伏を可視化し、物語構造の分析を支援。

group_by(chapter), summarise(sentiment_score)

🤖 機械学習によるテキスト分類

textrecipesパッケージにより、テキスト前処理を tidymodels ワークフローに統合できます。TF-IDF変換からハイパーパラメータチューニングまで、美しい一貫したワークフローでテキスト分類を実現します。

📋 textrecipesによる前処理パイプライン

text_classification.R
# テキスト分類のためのサンプルデータ作成 book_classification <- book_words %>% filter(str_length(text) > 50) %>% select(book, text) %>% slice_sample(n = 2000) %>% mutate(book = factor(book)) # データ分割 set.seed(123) book_split <- initial_split(book_classification, prop = 0.8, strata = book) book_train <- training(book_split) book_test <- testing(book_split) # テキスト前処理レシピ text_recipe <- recipe(book ~ text, data = book_train) %>% step_tokenize(text) %>% step_stopwords(text) %>% step_tokenfilter(text, max_tokens = 1000) %>% step_tfidf(text) %>% step_normalize(all_numeric_predictors()) # 前処理の確認 text_recipe %>% prep() %>% bake(new_data = NULL) %>% glimpse()

🎯 複数モデルの訓練と評価

text_models.R
# 複数の分類モデルを定義 rf_spec <- rand_forest(trees = 500) %>% set_engine("ranger") %>% set_mode("classification") svm_spec <- svm_linear() %>% set_engine("LiblineaR") %>% set_mode("classification") nb_spec <- naive_Bayes() %>% set_engine("naivebayes") %>% set_mode("classification") # ワークフローセットによる効率的な比較 text_workflows <- workflow_set( preproc = list(text = text_recipe), models = list(rf = rf_spec, svm = svm_spec, nb = nb_spec) ) # クロスバリデーション book_folds <- vfold_cv(book_train, v = 5, strata = book) # 並列処理で全モデルを評価 text_results <- text_workflows %>% workflow_map( resamples = book_folds, metrics = metric_set(accuracy, roc_auc, f_meas), verbose = TRUE ) # 結果の比較 text_results %>% rank_results() %>% filter(.metric == "accuracy") %>% select(model, .config, mean, rank)
Text Classification Model Comparison
# A tibble: 3 × 4 model .config mean rank <chr> <chr> <dbl> <int> 1 svm Preprocessor1_Model1 0.834 1 2 rf Preprocessor1_Model1 0.798 2 3 nb Preprocessor1_Model1 0.756 3 # 🏆 SVM が最高の分類精度を達成!

📝 step_tokenize()

textrecipesの基本関数。テキストを単語に分割し、tidymodelsワークフローに統合。複数のトークン化方式をサポート。

step_tokenize(text, token = "words")

🧹 step_stopwords()

ストップワードの自動除去。多言語対応で、カスタム辞書の追加も可能。テキスト分析の精度向上に重要な前処理。

step_stopwords(text, language = "en", custom_stopwords)

🔢 step_tfidf()

TF-IDF変換による単語重要度の計算。文書内頻度と逆文書頻度を統合し、特徴的な単語を強調した数値化を実現。

step_tfidf(text, norm = "l2", sublinear_tf = TRUE)

⚡ workflow_set()

複数の前処理・モデル組み合わせを効率的に比較。ワークフローセットにより、大規模な実験を統一的に管理・実行可能。

workflow_set(preproc, models), workflow_map()

🌐 高度なテキスト分析技術

tidytextの真の力は、基本的な感情分析を超えた高度な分析技術にあります。ネットワーク分析、n-gram分析、ワードクラウドなど、複雑なテキスト構造の可視化と分析を実現します。

🛠️ 高度テキスト分析技術エコシステム

🌐 テキスト分析高度技術マップ 🕸️ ネットワーク分析 love happy joy peace life library(widyr) words %>% pairwise_count(word, document) %>% filter(n >= 10) %>% graph_from_data_frame() 🔗 N-gram分析 1-gram "love", "peace" 2-gram "data science" 3-gram "natural language processing" N-gram抽出プロセス 原文: "I love data science very much" 2-gram: "I love", "love data", "data science", "science very", "very much" 3-gram: "I love data", "love data science", "data science very", "science very much" unnest_tokens(bigram, text, token = "ngrams", n = 2) %>% separate(bigram, c("word1", "word2"), sep = " ") %>% count(word1, word2, sort = TRUE) ☁️ ワードクラウド data analysis science R text machine learning model tidyverse algorithm visualization mining sentiment library(wordcloud) words %>% count(word) %>% with(wordcloud(word, n, max.words = 100)) 🔄 統合テキスト分析ワークフロー 📚 テキストデータ • 文書コレクション • メタデータ付き • 前処理済み 🔤 前処理 • unnest_tokens() • ストップワード除去 • 正規化・標準化 🎯 分析選択 • 感情分析 • TF-IDF重要度 • n-gram抽出 📊 可視化 • ネットワーク図 • ワードクラウド • 統計グラフ 🔀 分析手法の選択指針 🕸️ ネットワーク分析 適用場面: • 単語間の関係性分析 • 概念の共起パターン • コミュニティ検出 🔗 N-gram分析 適用場面: • 文脈情報の保持 • フレーズ抽出 • 言語パターン発見 ☁️ ワードクラウド 適用場面: • 概要把握・探索 • プレゼンテーション • 直感的理解促進 ⚡ パフォーマンス 計算複雑度: • ネットワーク: O(n²) • N-gram: O(n) • ワードクラウド: O(n log n) 💡 実践的な実装ヒント 🎯 効果的な分析戦略 1. 探索段階:ワードクラウドで全体把握 → 感情分析で傾向確認 2. 詳細分析:n-gram分析で文脈抽出 → TF-IDF で重要語特定 3. 関係性分析:ネットワーク分析で概念間の関係発見 → クラスタリング 4. 可視化最適化:対象読者に応じて表現方法を選択(学術 vs プレゼンテーション) 5. 統合レポート:複数手法の結果を統合して包括的洞察を提供

第22章の重要ポイント

実践的アドバイス

tidytextの真の価値は、テキスト分析を整然データの原則に基づいて実行できることです。従来の複雑で非直感的なテキスト処理とは異なり、dplyr、ggplot2との完全な統合により、探索から機械学習まで一貫した美しいワークフローを実現できます。textrecipesとの連携により、テキスト分析もtidymodelsの恩恵を受けられ、再現性と拡張性の高い分析が可能になります。