0Pricing
R Academy · レッスン

R での感情分析

トークンを感情辞書と結合し、肯定的・否定的なトーンを測定します。

「R での感情分析」はCoddyKit上の無料R Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはR Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 R Academyコースには全4レッスンが含まれています。

感情分析の概要

感情分析は、テキストに感情的な極性を割り当てます。tidytextでは、個々の単語を感情辞書と照合し、スコアを集計します。組み込みの感情辞書として、AFINN(数値スコア)、Bing(肯定/否定)、NRC(感情カテゴリ)の3つを利用できます。

library(tidytext)

# Available sentiment lexicons
# AFINN: -5 to +5 numeric score
# Bing:  binary positive/negative
# NRC:   emotion categories (joy, fear, anger, ...)

# Preview AFINN
afinn_sample <- get_sentiments('afinn')
cat('AFINN rows:', nrow(afinn_sample), '\n')
cat('Score range:', range(afinn_sample$value), '\n')
print(head(afinn_sample, 5))

get_sentiments('afinn')

AFINN辞書は、2,477個の英単語に対して、−5(非常に否定的)から+5(非常に肯定的)までの整数スコアを割り当てます。Finn Årup Nielsenによって編纂され、ソーシャルメディアやレビューのテキストに適しています。

library(tidytext)
library(dplyr)

afinn <- get_sentiments('afinn')

# Most positive and most negative words
cat('Most positive words:\n')
print(afinn |> slice_max(value, n = 5))

cat('\nMost negative words:\n')
print(afinn |> slice_min(value, n = 5))

# Score distribution
cat('\nScore distribution:\n')
print(table(afinn$value))

get_sentiments('bing')

Bing辞書(Bing Liuら)は、6,786個の単語を肯定的または否定的のいずれかに分類します。AFINNより規模が大きく、単純な極性で十分な商品レビューや顧客フィードバックに適しています。

library(tidytext)
library(dplyr)

bing <- get_sentiments('bing')

cat('Bing lexicon size:', nrow(bing), '\n')
cat('Positive words:', sum(bing$sentiment == 'positive'), '\n')
cat('Negative words:', sum(bing$sentiment == 'negative'), '\n')

# Sample positive and negative words
cat('\nSample positive:', head(bing$word[bing$sentiment == 'positive'], 8), '\n')
cat('Sample negative:', head(bing$word[bing$sentiment == 'negative'], 8), '\n')

inner_join:単語のスコアリング

inner_join(tokens, afinn, by = 'word')は、AFINN辞書に含まれるトークンだけを残し、それらのスコアを付加します。辞書にない単語は暗黙的に除外されます。これは、既知の感情語に焦点を絞れるという長所である一方、制限でもあります。

library(tidytext)
library(dplyr)

reviews <- tibble::tibble(
  review_id = 1:3,
  text = c(
    'The product is excellent and outstanding quality',
    'Terrible experience, broken and disappointing',
    'Good value but slow delivery, acceptable overall'
  )
)

scored <- reviews |>
  unnest_tokens(word, text) |>
  inner_join(get_sentiments('afinn'), by = 'word')

cat('Scored words:\n')
print(scored[, c('review_id', 'word', 'value')])

文書ごとのネット感情

group_by(document) |> summarise(sentiment = sum(value))を使って文書ごとにAFINNスコアを合計すると、ネット感情スコアを取得できます。合計が正なら全体としてポジティブな感情、負ならネガティブな感情を示します。

library(tidytext)
library(dplyr)

reviews <- tibble::tibble(
  review_id = 1:5,
  text = c(
    'excellent outstanding perfect love best amazing',
    'terrible broken horrible awful waste money',
    'good acceptable okay decent average',
    'brilliant fantastic outstanding love recommend',
    'poor bad disappointing slow useless'
  )
)

net_sentiment <- reviews |>
  unnest_tokens(word, text) |>
  inner_join(get_sentiments('afinn'), by = 'word') |>
  group_by(review_id) |>
  summarise(
    sentiment  = sum(value),
    word_count = n()
  ) |>
  mutate(polarity = ifelse(sentiment > 0, 'positive', 'negative'))

print(net_sentiment)

Bingによる感情分析:ポジティブとネガティブの数

Bing辞書を使うと、文書ごとにポジティブな単語とネガティブな単語の数を比較できます。ネット極性スコアにはsentiment = positive_n - negative_nを計算するか、両方の数をグループ化した棒グラフとして描画すると構成を確認できます。

library(tidytext)
library(dplyr)

corpus <- tibble::tibble(
  chapter = 1:4,
  text = c(
    'the hero was brave courageous strong and victorious in battle',
    'disaster struck terrible losses failure defeat mourning grief',
    'love joy happiness beautiful peaceful wonderful morning',
    'evil darkness corrupt wicked terrible pain suffering fear'
  )
)

bing_sentiment <- corpus |>
  unnest_tokens(word, text) |>
  inner_join(get_sentiments('bing'), by = 'word') |>
  count(chapter, sentiment) |>
  tidyr::pivot_wider(names_from = sentiment, values_from = n, values_fill = 0) |>
  mutate(net = positive - negative)

print(bing_sentiment)

章またはセクションごとの感情

物語の展開に沿って感情を追跡するには、章ごと、または移動ウィンドウごとにネット感情を計算します。これにより、感情の構造である起承転結やクライマックス、解決を明らかにできます。展開を可視化するには、ggplot2のgeom_line()またはgeom_bar()を使用します。

library(tidytext)
library(dplyr)
library(ggplot2)

# Simulate a 10-chapter story arc
set.seed(42)
chapters <- tibble::tibble(
  chapter = 1:10,
  text    = c(
    'peaceful beautiful joy love happy wonderful',
    'good friends happy carefree enjoyable fun',
    'worried anxious trouble fear uncertain dark',
    'danger terrible threat awful pain suffering',
    'fear horror disaster terrible devastation loss',
    'fight battle struggle hard difficult challenge',
    'hope courage determination brave strong resist',
    'triumph victory success celebrate joy love',
    'relief peace gratitude wonderful blessed happy',
    'love joy peace beautiful grateful wonderful'
  )
)

arc <- chapters |>
  unnest_tokens(word, text) |>
  inner_join(get_sentiments('afinn'), by = 'word') |>
  group_by(chapter) |>
  summarise(net_sentiment = sum(value))

ggplot(arc, aes(chapter, net_sentiment)) +
  geom_line(color = 'steelblue', linewidth = 1.2) +
  geom_hline(yintercept = 0, linetype = 'dashed') +
  labs(x = 'Chapter', y = 'Net Sentiment', title = 'Story Sentiment Arc') +
  theme_minimal()

NRC辞書:感情カテゴリ

NRC辞書(Saif Mohammad と Peter Turney)は、13,901語を8種類の感情(anger、anticipation、disgust、fear、joy、sadness、surprise、trust)と、positive/negativeに分類します。filter(sentiment == 'joy')を使うと、感情で絞り込めます。

library(tidytext)
library(dplyr)

nrc <- get_sentiments('nrc')
cat('NRC size:', nrow(nrc), '\n')
cat('Emotions:', paste(unique(nrc$sentiment), collapse = ', '), '\n')

# Words associated with 'joy'
joy_words <- nrc |> filter(sentiment == 'joy')
cat('\nJoy words:', nrow(joy_words), '\n')
cat('Sample:', head(joy_words$word, 10), '\n')

# Count words per emotion
nrc |>
  count(sentiment, sort = TRUE) |>
  print()

コーパスへのNRCの適用

トークン化したテキストとNRCを結合し、それぞれの感情を個別にスコアリングします。count(doc_id, sentiment)を使って文書と感情ごとに集計すると、各文書でどの感情が支配的かを確認できます。

library(tidytext)
library(dplyr)

docs <- tibble::tibble(
  doc_id = c(1, 1, 2, 2, 3, 3),
  text   = c(
    'wonderful joyful happy love peace',
    'excited surprise anticipation trust',
    'fear anger terrible hate disgust',
    'dark horrible awful suffering pain',
    'curious wonder discovery learning',
    'hope trust anticipation future growth'
  )
)

nrc_scores <- docs |>
  unnest_tokens(word, text) |>
  inner_join(get_sentiments('nrc'), by = 'word') |>
  filter(!sentiment %in% c('positive', 'negative')) |>  # keep only emotions
  count(doc_id, sentiment, sort = TRUE)

cat('Emotion counts per document:\n')
print(nrc_scores)

ワードクラウドの概念

wordcloudは、出現回数に比例して文字の大きさを変え、単語の頻度を可視化します。wordcloudまたはwordcloud2パッケージを使うと、単語と頻度のデータフレームからワードクラウドを生成できます。Bing辞書で感情に応じて単語を色分けすれば、感情別のワードクラウドになります。

library(tidytext)
library(dplyr)

# Prepare word frequencies coloured by Bing sentiment
corpus_text <- tibble::tibble(
  text = c(
    'excellent performance amazing results love beautiful',
    'terrible failure poor broken horrible waste',
    'brilliant outstanding success happy wonderful joy',
    'awful disappointing bad slow useless frustrating'
  )
)

word_freq <- corpus_text |>
  unnest_tokens(word, text) |>
  count(word, sort = TRUE) |>
  left_join(get_sentiments('bing'), by = 'word') |>
  mutate(
    sentiment = replace(sentiment, is.na(sentiment), 'neutral'),
    colour    = case_when(
      sentiment == 'positive' ~ '#2196F3',
      sentiment == 'negative' ~ '#F44336',
      TRUE                    ~ '#9E9E9E'
    )
  )

print(word_freq)
# In practice: wordcloud2(word_freq[, c('word','n')], color = word_freq$colour)

辞書ベースの感情分析の限界

辞書ベースの感情分析には、既知の失敗パターンがあります。否定(「not good」がポジティブとしてスコアリングされる)、皮肉(「oh great, another bug」)、分野の不一致(スラングでは「sick」がポジティブな意味になる場合がある)、語彙にない単語などです。結果を解釈する際は、これらの制限を考慮してください。

library(tidytext)
library(dplyr)

# Negation problem
neg_examples <- tibble::tibble(
  text = c(
    'not good at all',   # negative, but 'good' scores +3
    'not bad',           # positive, but 'bad' scores -3
    'sick beats bro'     # slang positive, 'sick' is negative in AFINN
  )
)

scored <- neg_examples |>
  unnest_tokens(word, text) |>
  inner_join(get_sentiments('afinn'), by = 'word')

cat('Lexicon scores (naive - ignores negation):\n')
print(scored[, c('word', 'value')])
cat('\nNote: "not" is a stop word - the negation is lost!\n')

確認問題

感情のスコアリングにinner_join(tokens, afinn, by = 'word')を使用します。tokens内にある単語のうち、AFINN辞書に含まれていない単語はどうなりますか。

まとめ:感情分析

重要なポイント:

  • 主な辞書は3種類あります。AFINN(−5~+5のスコア)、Bing(ポジティブ/ネガティブ)、NRC(8種類の感情)です
  • get_sentiments('afinn')/'bing'/'nrc'は、辞書をtibbleとして取得します
  • inner_join(tokens, lexicon, by = 'word')は一致した単語だけをスコアリングし、一致しない単語は除外します
  • ネット感情 = group_by(doc) |> summarise(sentiment = sum(value))
  • Bingでは、文書またはセクションごとにpositive - negativeの単語数を比較します
  • NRCでは、感情名で絞り込むことで、fear、joy、angerなどを個別に取り出せます
  • 重要な制限:辞書ベースの手法では、否定、皮肉、分野固有のスラングを処理できません
library(tidytext)
library(dplyr)

tibble::tibble(text = 'excellent amazing love joy beautiful happy') |>
  unnest_tokens(word, text) |>
  inner_join(get_sentiments('afinn'), by = 'word') |>
  summarise(net_sentiment = sum(value)) |>
  print()

よくある質問

「R での感情分析」レッスンは無料ですか?

はい。「R での感情分析」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、R Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 R Academyコースには全4レッスンが含まれています。

「R での感情分析」で何を学びますか?

トークンを感情辞書と結合し、肯定的・否定的なトーンを測定します。 ブラウザで直接実行するハンズオンコードでR Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

R Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのR Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「R での感情分析」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このR Academyレッスンでコードを書いて実行できますか?

はい。すべてのR Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. トークン化とストップワードの除去
  2. TF-IDF と単語頻度分析
  3. R での感情分析
  4. LDA によるトピックモデリング
← R Academyに戻る