R에서 감성 분석
토큰을 감성 사전과 조인해 긍정적 또는 부정적인 어조를 측정합니다.
R에서 감성 분석은(는) CoddyKit의 무료 R Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 R Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. R Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
감정 분석 개요
감정 분석은 텍스트에 감정의 방향과 강도를 부여합니다. tidytext 방식은 개별 단어를 감정 어휘 목록과 대조하고 점수를 집계합니다. 세 가지 내장 어휘 목록을 사용할 수 있습니다: AFINN(수치 점수), Bing(긍정/부정), NRC(감정 범주).
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)장 또는 절별 감정
서사 흐름에 따른 감정 변화를 추적하려면 장별 또는 이동 구간별 순감정을 계산합니다. 이를 통해 감정의 구조인 상승 전개, 절정, 결말을 확인할 수 있습니다. geom_line() 또는 geom_bar()와 함께 ggplot2를 사용해 서사 흐름을 시각화할 수 있습니다.
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가지 감정(분노, 기대, 혐오, 두려움, 기쁨, 슬픔, 놀람, 신뢰)과 긍정·부정 범주로 분류합니다. 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 또는 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')를 사용합니다. 토큰에 있지만 AFINN 어휘 목록에는 없는 단어에는 어떤 일이 일어날까요?
복습: 감정 분석
핵심 요점:
- 세 가지 주요 어휘 목록: AFINN(−5부터 +5까지의 점수), Bing(긍정/부정), NRC(8가지 감정)
get_sentiments('afinn')/'bing'/'nrc'는 어휘 목록을 티블로 가져옵니다.inner_join(tokens, lexicon, by = 'word')는 일치하는 단어에만 점수를 매기며, 일치하지 않는 단어는 제외됩니다.- 순감정 =
group_by(doc) |> summarise(sentiment = sum(value)) - Bing: 문서 또는 절별
positive - negative단어 수를 비교합니다. - NRC: 감정 이름으로 필터링하여 두려움, 기쁨, 분노 등을 분리합니다.
- 주요 한계: 어휘 목록 기반 방법은 부정 표현, 빈정거림, 분야별 속어를 처리하지 못합니다.
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/7 AI 튜터), CoddyKit PRO로 업그레이드하면 R Academy 강의 전체를 잠금 해제할 수 있습니다. R Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“R에서 감성 분석”에서 뭘 배우나요?
토큰을 감성 사전과 조인해 긍정적 또는 부정적인 어조를 측정합니다. 브라우저에서 직접 실행하는 실습 코드로 R Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
R Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 R Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.
“R에서 감성 분석” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 R Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 R Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.