감성분석_final_project
20181501 경제학과 김보희
2021 6 14
library(stringr)
library(tidyverse)
library(tidytext)
library(tidyr)
library(wordcloud2)
library(tidyverse)
library(tidytext)
library(stringr)
library(janeaustenr)
library(rcartocolor)
library(wordcloud2)
library(forcats)
library(viridis)
library(KoNLP)
## Error in get(genname, envir = envir) :
## 객체 'testthat_print'를 찾을 수 없습니다
library(tmaptools)
library(shinyjs)
1. 미국 대통령 연설 텍스트 마이닝 및 감성분석
Data set
미국 대통령 연설문 데이터 및 Tokenization 방법은 제공됨
# get a list of the files in the input directory
files <- list.files("data/")
files[1]
## [1] "Bush_2001.txt"
dat <- lapply(1:length(files),function(k){
fileName <- paste0("data/", files[k], sep = "")
fileText<-read_tsv(fileName,col_names = "text")
fileText$president_name <- gsub("_.+",replacement = "",files[k])
# _ 뒤에 모든 문자들은(.) 다 삭제
fileText$year <- str_extract(string=files[k],pattern ="[0-9]+")
# 숫자가 하나 이상일 경우 추출
tokens <- fileText %>% unnest_tokens(word, text)
return(tokens)
})
dat %>% class()
## [1] "list"
dat %>% length()
## [1] 26
# data.frame 형태로
dat <- dat %>% bind_rows()
1-1. Word Frequency 시각화 및 해석
## 불용어 제거
dat <- dat %>%
anti_join(stop_words)
## 단어 빈도수 시각화
dat_text <- dat %>%
count(word, sort = TRUE) %>%
slice_max(n, n=15) %>% # 단어 빈도수 상위 15개만
mutate(word = reorder(word, n)) # word를 단어 빈도 수 대로 재정렬
ggplot(dat_text, aes(n, word, fill=word))+
geom_col()+
geom_text(aes(label=n), hjust=-.1)+
labs(y = NULL)+
theme_minimal()+
ggtitle("Word Frequency")+
guides(fill=F)
- 해석: 미국 대통령 연설문에서 많이 쓰인 단어 15개를 ggplot의 geom_col()을 이용해 시각화한 결과,
“people”이라는 단어를 연설문에서 가장 많이 사용하였고, 다음으론 “america”, “american” 등이 뒤를 이었다.
1.2. tf-idf score 시각화 및 해석
## tf-idf score 계산
dat_count <- dat %>%
anti_join(stop_words) %>% # 불용어 제거
count(president_name, word) %>%
arrange(president_name, desc(n))
dat_tf_idf <- dat_count %>%
bind_tf_idf(term = word, document = president_name, n = n) # tf_idf 계산
## 대통령별로 tf-idf 가 높은 단어 15개씩 자름
dat_tf_idf_vis <- dat_tf_idf %>%
group_by(president_name) %>%
slice_max(tf_idf, n = 15) %>%
ungroup()
# Word 순서가 Count의 내림차순으로 정렬되지 않는 문제를 reorder_within() 함수를 사용해 해결하였다.
# 참고: https://qiushi.rbind.io/post/reorder-varible-within-facets/
ggplot(dat_tf_idf_vis,
aes(x = tf_idf,
y = reorder_within(word, tf_idf, president_name),
fill = president_name)) +
geom_col(show.leg.end = FALSE) +
facet_wrap(~president_name, ncol=2, scale='free')+
# 각각의 y축의 scale이 달라짐
labs(x = "tf-idf", y = NULL)+
rcartocolor::scale_fill_carto_d(palette = "PurpOr")+
theme_minimal()+
guides(fill=F)+
scale_y_reordered()
- 해석: 미국 대통령 별로 tf_idf 값을 계산하여 각각 시각화한 결과 Bush 대통령은 연설문에서 상대적으로 “iraqis”라는 단어를 가장 많이 사용해 tf_idf 값이 가장 컸다. 여기서 “iraqis”는 이라크인을 말한다. Clinton 대통령은 연설문에서 상대적으로 “welfare”라는 단어를 가장 많이 사용해 tf_idf 값이 가장 컸다. Clinton 대통령이 복지를 많이 언급한 만큼 이 대통령의 정책의 방향을 알 수 있다. 다음으로 Obama 대통령이 연설문에서 상대적으로 “oil”이라는 단어를 가장 많이 사용해 tf_idf 값이 가장 컸다. Trump 대통령은 이라크, 연설문에서 상대적으로 “isis”라는 단어를 가장 많이 사용해 tf_idf 값이 가장 컸다. 이라크, 시리아 등 이슬람국 등을 말하며, 무장단체 테러조직을 말한다.
1.3 Wordcloud를 통한 많이 쓰이는 단어 시각화
dat_count <- dat_count %>% as.data.frame()
dat_count <- dat_count %>%
mutate(word=gsub("\\d+", "", word)) # 숫자 제거
wordcloud2(dat_count[2:3],
minSize=10,
size = 0.6,
fontFamily = "나눔바른고딕",
color = "random-light",
backgroundColor = "grey",
minRotation=0,
shape='circle')
- 해석: 워드클라우드 시각화 결과 “people”, “world”, “country”, “congress” 등의 단어가 많이 사용된 것을 볼 수 있다.
1.4 Sentiment Analysis
다양한 감성분석을 수행해 보시오. 어떤 부정적인 단어가 많이 나왔는지, 어떤 긍정적인 단어가 많이 나왔는지를 분석하고, 대통령별로 비교해 보시오.
또한, 대통령별이 아닌 연도별로 Sentiment score가 어떻게 변화하였는지도 시각화 해 보시오.
감성어 사전 읽어오기
bing <- get_sentiments("bing")
nrc <- get_sentiments("nrc")
affin <- get_sentiments("afinn")
head(bing)
## # A tibble: 6 x 2
## word sentiment
## <chr> <chr>
## 1 2-faces negative
## 2 abnormal negative
## 3 abolish negative
## 4 abominable negative
## 5 abominably negative
## 6 abominate negative
head(affin)
## # A tibble: 6 x 2
## word value
## <chr> <dbl>
## 1 abandon -2
## 2 abandoned -2
## 3 abandons -2
## 4 abducted -2
## 5 abduction -2
## 6 abductions -2
head(nrc)
## # A tibble: 6 x 2
## word sentiment
## <chr> <chr>
## 1 abacus trust
## 2 abandon fear
## 3 abandon negative
## 4 abandon sadness
## 5 abandoned anger
## 6 abandoned fear
(1) bing 감성어 사전 사용
## sentiment join
# 대통령별로 negative & positive 단어 사용빈도(n)
dat_bing_count <- dat %>%
anti_join(stop_words) %>%
inner_join(bing, by='word') %>%
count(president_name, word, sentiment)
# sentiment 변수를 spread하여 positive, negative 컬럼을 새로 생성
presi_bing_sentiment <- dat_bing_count %>%
spread(sentiment, n, fill=0) %>%
# sentiment score 생성
mutate(sentiment_score = positive - negative)
## negative words, 부정적인 단어 시각화
presi_bing_sentiment %>%
group_by(president_name) %>%
slice_max(negative, n=15) %>%
ungroup() %>%
ggplot(aes(x = negative,
y = reorder_within(word, negative, president_name),
fill = president_name)) +
geom_col(show.legend = FALSE) +
facet_wrap(~president_name, ncol = 2, scales = "free",
strip.position = "top") +
rcartocolor::scale_fill_carto_d(palette = "PurpOr")+
labs(x = "negative", y = NULL)+
scale_y_reordered()
# 해석: 대통령별로 연설문에서 사용한 부정적인 단어 빈도수를 시각화 하였는데, Bush 대통령의 경우 "terror"를 Clinton 대통령의 경우 "crime"을 Obama 대통령의 경우 "hard"를 Trump 대통령의 경우 "terrible"를 가장 많이 사용하였다.
## positive words, 긍정적인 단어 시각화
presi_bing_sentiment %>%
group_by(president_name) %>%
slice_max(positive, n=15) %>%
ungroup() %>%
ggplot(aes(x = positive,
y=reorder_within(word, positive, president_name),
fill = president_name)) +
geom_col(show.legend = FALSE) +
facet_wrap(~president_name, ncol = 2, scales = "free") +
rcartocolor::scale_fill_carto_d(palette = "PurpOr")+
labs(x = "positive", y = NULL)+
scale_y_reordered()
# 해석: 대통령별로 연설문에서 사용한 긍정적인 단어 빈도수를 시각화 하였는데, Bush 대통령의 경우 "freedom"을 Clinton 대통령의 경우 "support"를 Obama 대통령의 경우 "reform"을 Trump 대통령의 경우 "safe"를 가장 많이 사용하였다.
## 연도별로 sentiment score 시각화
dat %>%
inner_join(bing, by='word') %>%
anti_join(stop_words) %>%
count(president_name, year, sentiment) %>%
spread(sentiment, n, fill=0) %>%
# sentiment score 생성
mutate(sentiment_score = positive - negative) %>%
ggplot()+
geom_col(aes(x=year, y=sentiment_score, fill=president_name))+
rcartocolor::scale_fill_carto_d(palette = "PurpOr")
# 해석: 2003년에 sentiment score가 낮아 찾아본 결과 미국의 이라크 침공이 있었던 연도로 연설문에 부정적인 단어가 사용 돼 sentiment score가 낮은 것으로 추측할 수 있다.
(2) affin 감성어 사전 사용
affin 감성어 사전의 경우 bing 사전에 비해 갯수는 적지만 단어의 score가 명시되어 있어서, 긍정/부정의 강도를 표현하기가 더 용이함
## sentiment join
# 대통령별로 negative & positive 단어 사용빈도(n)
dat_affin_count <- dat %>%
inner_join(affin, by='word') %>%
anti_join(stop_words) %>%
count(president_name, word, value) %>%
mutate(sentiment=ifelse(value > 0, "positive", "negative"))
# sentiment 변수를 spread하여 positive, negative 컬럼을 새로 생성
presi_affin_sentiment <- dat_affin_count %>%
spread(sentiment, n, fill=0)
# sentiment score 생성
## negative words
presi_affin_sentiment %>%
group_by(president_name) %>%
slice_max(negative, n=15) %>%
ungroup() %>%
ggplot(aes(x = negative,
y = reorder_within(word, negative, president_name),
fill = president_name)) +
geom_col(show.legend = FALSE) +
facet_wrap(~president_name, ncol = 2, scales = "free",
strip.position = "top") +
rcartocolor::scale_fill_carto_d(palette = "PurpOr")+
labs(x = "negative", y = NULL)+
scale_y_reordered()
# 해석: 대통령별로 연설문에서 사용한 부정적인 단어 빈도수를 시각화 하였는데, Bush 대통령의 경우 "war"를 Clinton 대통령의 경우 "challenge"을 Obama 대통령의 경우 "hard"를 Trump 대통령의 경우 "terrible"를 가장 많이 사용하였다.
## positive words
presi_affin_sentiment %>%
group_by(president_name) %>%
slice_max(positive, n=15) %>%
ungroup() %>%
ggplot(aes(x = positive,
y=reorder_within(word, positive, president_name),
fill = president_name)) +
geom_col(show.legend = FALSE) +
facet_wrap(~president_name, ncol = 2, scales = "free") +
rcartocolor::scale_fill_carto_d(palette = "PurpOr")+
labs(x = "positive", y = NULL)+
scale_y_reordered()
# 해석: 대통령별로 연설문에서 사용한 긍정적인 단어 빈도수를 시각화 하였는데, Bush 대통령의 경우 "freedom"를 Clinton 대통령과 Obama 대통령의 경우 "care"를 Trump 대통령의 경우 "united"를 가장 많이 사용하였다.
### 연도별로 value의 합을 계산하여 sentiment_score로 정의
affin_year_sentiment_score <- dat %>%
inner_join(affin, by='word') %>%
anti_join(stop_words) %>%
group_by(president_name,year) %>%
# sentiment score 생성
summarise(sentiment_score=sum(value))
affin_year_sentiment_score %>%
ggplot()+
geom_col(aes(x=year, y=sentiment_score, fill=president_name))+
rcartocolor::scale_fill_carto_d(palette = "PurpOr")
# 해석: bing 감성어 사전을 사용했을 때와 마찬가지로 2003년의 sentiment score가 가장 낮다.
(3) nrc 감성어 사전 사용
## nrc 감성어 사전에서 긍정/부정만 추출
nrc_pn <- nrc %>% filter(sentiment %in% c("positive","negative"))
## sentiment join
# 대통령별로 negative & positive 단어 사용빈도(n)
dat_nrc_count <- dat %>%
inner_join(nrc_pn, by='word') %>%
anti_join(stop_words) %>%
count(president_name, word, sentiment)
# sentiment 변수를 spread하여 positive, negative 컬럼을 새로 생성
presi_nrc_sentiment <- dat_nrc_count %>%
spread(sentiment, n, fill=0) %>%
# sentiment score 생성
mutate(sentiment_score = positive - negative)
## negative words
presi_nrc_sentiment %>%
group_by(president_name) %>%
slice_max(negative, n=15) %>%
ungroup() %>%
ggplot(aes(x = negative,
y = reorder_within(word, negative, president_name),
fill = president_name)) +
geom_col(show.legend = FALSE) +
facet_wrap(~president_name, ncol = 2, scales = "free",
strip.position = "top") +
rcartocolor::scale_fill_carto_d(palette = "PurpOr")+
labs(x = "negative", y = NULL)+
scale_y_reordered()
# 해석: 대통령별로 연설문에서 사용한 부정적인 단어 빈도수를 시각화 하였는데, Bush, Clinton 대통령의 경우 "government"를 가장 많이 사용하였고, Obama, Trump 대통령의 경우 "tax"를 가장 많이 사용하였다.
## positive words
presi_nrc_sentiment %>%
group_by(president_name) %>%
slice_max(positive, n=15) %>%
ungroup() %>%
ggplot(aes(x = positive,
y=reorder_within(word, positive, president_name),
fill = president_name)) +
geom_col(show.legend = FALSE) +
facet_wrap(~president_name, ncol = 2, scales = "free") +
rcartocolor::scale_fill_carto_d(palette = "PurpOr")+
labs(x = "positive", y = NULL)+
scale_y_reordered()
# 해석: 대통령별로 연설문에서 사용한 긍정적인 단어 빈도수를 시각화 하였는데, Bush 대통령의 경우 "freedom"를 Clinton 대통령의 경우 "community"를 Obama 대통령의 경우 "job"을 Trump 대통령의 경우 "united"를 가장 많이 사용하였다.
## 연도별로 sentiment score 시각화
dat %>%
inner_join(nrc_pn, by='word') %>%
anti_join(stop_words) %>%
count(president_name, year, sentiment) %>%
spread(sentiment, n, fill=0) %>%
# sentiment score 생성
mutate(sentiment_score = positive - negative) %>%
ggplot()+
geom_col(aes(x=year, y=sentiment_score, fill=president_name))+
rcartocolor::scale_fill_carto_d(palette = "PurpOr")
# 해석: sentiment score가 모든 연도에서 양의 값을 가지지만 다른 감성어 사전과 마찬가지로 2003년의 sentiment score가 가장 낮다.
전체 연설문에서 많이 쓰인 긍적적인 단어와 부정적인 단어
# Bing 감성어 사전을 Join 한 후,
# 단어별, 긍정/부정별로 얼마나 많은 횟수만큼 사용됐는지 count
bing_word_counts <- dat %>%
inner_join(get_sentiments("bing")) %>%
anti_join(stop_words) %>%
count(word, sentiment, sort = TRUE)
bing_word_counts
## # A tibble: 1,365 x 3
## word sentiment n
## <chr> <chr> <int>
## 1 support positive 202
## 2 reform positive 170
## 3 freedom positive 124
## 4 peace positive 123
## 5 hard negative 119
## 6 protect positive 113
## 7 free positive 108
## 8 strong positive 106
## 9 lead positive 85
## 10 crime negative 79
## # ... with 1,355 more rows
# sentiment별(긍정/부정별), 가장 많이 사용된 단어 10개를 추출
# word를 단어빈도 기준으로 재정렬한 후,
# ggplot의 geom_col으로 시각화
bing_word_counts %>%
group_by(sentiment) %>%
top_n(n=10) %>% # 최고 10개
ungroup() %>%
mutate(word = reorder(word, n)) %>%
ggplot(aes(n, word, fill = sentiment)) +
geom_col(show.legend = FALSE) +
facet_wrap(~sentiment, scales = "free_y") +
labs(x = "Contribution to sentiment",
y = NULL)+
rcartocolor::scale_fill_carto_d(palette = "PurpOr")
# 해석: 전체 연설문에서 많이 사용된 부정적인 단어에는 "hard", "crime"," "terror" 등이 있고, 긍정적인 단어에는 "support", "reform", "freedom" 등이 있다.
## wordcloud2 라이브러리를 사용하여 시각화
# wordcloud용 데이터 생성
dat_wordcloud <- bing_word_counts %>%
mutate(col=ifelse(sentiment=="positive",
viridis_pal(option = "plasma")(6)[5],
viridis_pal(option = "plasma")(6)[2])) %>%
# 부정
select(word,n,col)
wordcloud2(dat_wordcloud,
color = dat_wordcloud$col,
backgroundColor = "black",
fontFamily = '나눔바른고딕',
minSize=10, minRotation=0,
shape = "circle",
size=0.6)
## 책별로 긍/부정 단어 시각화
# 책별로, 단어별로, 긍정/부정별로 단어수 count
# negative 단어는 음수로 표시
# 책별로, 감정별로 그룹해서 가장 많이 등장한 단어 10개씩 뽑기
pos_neg <- dat %>%
inner_join(get_sentiments("bing")) %>%
anti_join(stop_words) %>%
count(president_name, word, sentiment, sort = TRUE) %>%
mutate(n = ifelse(sentiment == "negative", -n, n)) %>%
group_by(president_name,sentiment) %>%
slice_max(abs(n), n = 10, with_ties = F)
# 시각화
ggplot(data=pos_neg, aes(x=n,
y=reorder_within(word, n, president_name),
fill = sentiment)) +
geom_col() +
labs(x = "Contribution to sentiment", y = NULL) +
facet_wrap(.~president_name, scales = "free") +
scale_y_reordered()
2. 네이버 영화에서 원하는 영화 4개를 선정하여 텍스트 마이닝 수행 (50점)
(1) 영화: “업”
### 영화 리뷰 가져오기
all_reviews_up <- NULL
url_up <- "https://movie.naver.com/movie/bi/mi/pointWriteFormList.nhn?code=52120&type=after&onlyActualPointYn=N&order=newest&page="
# 페이지 반목문으로 불러오기 page=1:240
for (i in 1:240) {
newr <- NULL
url <- paste(url_up, i, sep='')
txt <- readLines(url, encoding="UTF-8")
# 영화 리뷰 부분만 가져오기
reviews <- txt[which(str_detect(txt, "id=\"_filtered_ment"))+4]
# 특수문자 제거
reviews <- gsub("<.+?>|\t","", reviews)
newr <- cbind(reviews)
all_reviews_up <- rbind(all_reviews_up, newr)
}
(1)-1. 텍스트 데이터 Tokenization (형태소 단위 혹은 words단위로 자유롭게)
### 텍스트 데이터 전처리
review_dat_up <- tibble(reply = all_reviews_up,
n_char = nchar(all_reviews_up)) %>%
filter(n_char>1) %>%
mutate(id=row_number()) %>%
select(id,reply)
### 형태소 단위로 Tokenization
review_up_token <- review_dat_up %>%
unnest_tokens(output=word, input=reply, token=SimplePos09) %>%
group_by(id) %>%
mutate(word_order = 1:n())
### 명사만 가져오기
review_up_n_done <- review_up_token %>%
filter(str_detect(word, "/n")) %>% # 명사만 추출
mutate(word_done = str_remove(word, "/.*$")) %>% # 형태소 정보 제거
filter(nchar(word_done) > 1) %>%
filter(nchar(word_done) <= 6) %>%
ungroup()
(1)-2. Wordcloud를 통한 많이 쓰이는 단어 시각화
review_up_n_top50 <- review_up_n_done %>% count(word_done) %>% arrange(-n) %>% head(50)
wordcloud2(review_up_n_top50,
minSize=10,
size = 2,
fontFamily = "나눔바른고딕",
color = "random-light", minRotation=0,
backgroundColor = "grey", shape="circles")
(1)-3. 정규표현식을 활용한 텍스트 데이터 수정 및 변형 (자주 등장하는 단어 위주로)
### 불용어 제거
# 원하는 단어를 넣어서 제거 가능
st_word1 <- tibble(word=c("이제","우리", "이거","완전", "진짜","처음","영화","이영화",
"부분","ㅠㅠ","필요","시작")) # 불용어 추가
st_word11 <- review_up_n_done[str_detect(review_up_n_done$word_done, "^진짜"),]
st_word111 <- review_up_n_done[str_detect(review_up_n_done$word_done, "^재미*"),]
st_word1111 <- review_up_n_done[str_detect(review_up_n_done$word_done, "^재밌*"),]
review_up_n_done1 <- review_up_n_done %>%
anti_join(st_word1, by=c("word_done"="word")) %>% # 불용어 추가 삭제
anti_join(st_word11, by=c("word_done"="word")) %>%
anti_join(st_word111, by=c("word_done"="word")) %>%
anti_join(st_word1111, by=c("word_done"="word")) %>%
mutate(word_done=gsub("\\d+", "", word_done)) %>% # 숫자제거
mutate(word_done=gsub("[[:punct:]]", "", word_done)) %>% # 모든 특수문자 제거
mutate(word_done=gsub("[A-Za-z]", "", word_done)) %>% # 영문 제거
mutate(word_done=gsub("[ㄱ-ㅎ]", "", word_done)) %>% # 자음 제거
mutate(word_done=gsub("\\s+", " ", word_done)) %>% # 띄어쓰기 두 번 -> 한 번
mutate(word_done=gsub("^애니.","애니메이션",word_done,ignore.case=TRUE)) %>%
mutate(word_done=gsub("감동적","감동",word_done,ignore.case=TRUE)) %>%
mutate(word_done=gsub("재밌고","재미",word_done,ignore.case=TRUE)) %>%
filter(nchar(word_done)>1) %>%
filter(nchar(word_done)<=6)
형태소 보정
# ~~은(는), ~~~도, ~~~들, ~~~~으로, ~~~을
# 완벽하게 할 수는 없음
# ifelse, str_detect, str_sub 함수를 사용
review_up_n_done2 <- review_up_n_done1 %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+은"),
str_sub(review_up_n_done1$word_done,1,nchar(review_up_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+으로"),
str_sub(review_up_n_done1$word_done,1,nchar(review_up_n_done1$word_done)-2),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+에서"),
str_sub(review_up_n_done1$word_done,1,nchar(review_up_n_done1$word_done)-2),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+것도"),
str_sub(review_up_n_done1$word_done,1,nchar(review_up_n_done1$word_done)-2),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+은"),
str_sub(review_up_n_done1$word_done,1,nchar(review_up_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+는"),
str_sub(review_up_n_done1$word_done,1,nchar(review_up_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+도"),
str_sub(review_up_n_done1$word_done,1,nchar(review_up_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+들"),
str_sub(review_up_n_done1$word_done,1,nchar(review_up_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+을"),
str_sub(review_up_n_done1$word_done,1,nchar(review_up_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+가"),
str_sub(review_up_n_done1$word_done,1,nchar(review_up_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+되"),
str_sub(review_up_n_done1$word_done,1,nchar(review_up_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+들"),
str_sub(review_up_n_done1$word_done,1,nchar(review_up_n_done1$word_done)-2),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+이"),
str_sub(review_up_n_done1$word_done,1,nchar(review_up_n_done1$word_done)-1),
word_done)) %>%
filter(nchar(word_done2)>1) %>%
filter(nchar(word_done2)<6)
(1)-4. Word Frequency 시각화 및 해석
review_up_n_top50 <- review_up_n_done2 %>% count(word_done2) %>% arrange(-n) %>% head(50)
## 워드클라우드
wordcloud2(review_up_n_top50,
minSize=10,
size = 2 ,
fontFamily = "나눔바른고딕",
color = "random-light",
backgroundColor = "grey",
minRotation=0,
shape="circle"
)
## bar
review_up_n_top50 %>%
slice_max(word_done2, n=15) %>%
ggplot(aes(x = n,
y = reorder(word_done2,n),
fill = word_done2)) +
geom_col(show.legend = FALSE) +
geom_text(aes(label=n), hjust=1, size=3)+
labs(x = "단어", y = NULL)+
scale_fill_manual(values=get_brewer_pal("Set3", n = 18))+
theme_get()+
ggtitle("Word Frequency")
- 해석: 영화 “업”의 리뷰에서 많이 사용된 단어를 워드클라우드로 시각화 한 결과 “최고”, “픽사”,“인생,”오프닝“,”재미" 등의 단어가 많이 사용된 것을 알 수 있다.
(2) 영화: “라라랜드”
### 영화 리뷰 가져오기
all_reviews_ra <- NULL
url_ra <- "https://movie.naver.com/movie/bi/mi/pointWriteFormList.nhn?code=134963&type=after&onlyActualPointYn=N&order=newest&page="
# 페이지 반목문으로 불러오기 page=1:240
for (i in 1:240) {
newr <- NULL
url <- paste(url_ra, i, sep='')
txt <- readLines(url, encoding="UTF-8")
# 영화 리뷰 부분만 가져오기
reviews <- txt[which(str_detect(txt, "id=\"_filtered_ment"))+4]
# 특수문자 제거
reviews <- gsub("<.+?>|\t","", reviews)
newr <- cbind(reviews)
all_reviews_ra <- rbind(all_reviews_ra, newr)
}
(2)-1. 텍스트 데이터 Tokenization
### 텍스트 데이터 전처리
review_dat_ra <- tibble(reply = all_reviews_ra,
n_char = nchar(all_reviews_ra)) %>%
filter(n_char>1) %>%
mutate(id=row_number()) %>%
select(id,reply)
### 형태소 단위로 Tokenization
review_ra_token <- review_dat_ra %>%
unnest_tokens(output=word, input=reply, token=SimplePos09) %>%
# 사용자 별로 그룹 지어서
group_by(id) %>%
mutate(word_order = 1:n())
# 명사만 가져오기
review_ra_n_done <- review_ra_token %>%
filter(str_detect(word, "/n")) %>% # 명사만 추출
mutate(word_done = str_remove(word, "/.*$")) %>% # 형태소 정보 제거
filter(nchar(word_done) > 1) %>%
filter(nchar(word_done) <= 6) %>%
ungroup()
(2)-2. Wordcloud를 통한 많이 쓰이는 단어 시각화
review_ra_n_top50 <- review_ra_n_done %>%
count(word_done) %>%
arrange(-n) %>%
head(50)
wordcloud2(review_ra_n_top50,
minSize=10,
size = 2,
fontFamily = "나눔바른고딕",
color = "random-light",
backgroundColor = "grey",
minRotation=0,
shape = "circle")
(2)-3. 정규표현식을 활용한 텍스트 데이터 수정 및 변형
### 불용어 제거
# 원하는 단어를 넣어서 제거 가능
st_word2 <- tibble(word=c("진짜","우리", "이거","다시봐도","서로","처음","하나","영화")) # 불용어 추가
review_ra_n_done1 <- review_ra_n_done %>%
anti_join(st_word2, by=c("word_done"="word")) %>% # 불용어 추가 삭제
mutate(word_done=gsub("\\d+", "", word_done)) %>% # 숫자제거
mutate(word_done=gsub("[[:punct:]]", "", word_done)) %>% # 모든 특수문자 제거
mutate(word_done=gsub("[A-Za-z]", "", word_done)) %>% # 영문제거
mutate(word_done=gsub("[ㄱ-ㅎ]", "", word_done)) %>%
mutate(word_done=gsub("\\s+", " ", word_done)) %>% # 띄어쓰기 두 번 -> 한 번
filter(nchar(word_done)>1)
형태소 보정
# ~~은(는), ~~~도, ~~~들, ~~~~으로, ~~~을
# 완벽하게 할 수는 없음
# ifelse, str_detect, str_sub 함수를 사용
review_ra_n_done2 <- review_ra_n_done1 %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+은"),
str_sub(review_ra_n_done1$word_done,1,nchar(review_ra_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+으로"),
str_sub(review_ra_n_done1$word_done,1,nchar(review_ra_n_done1$word_done)-2),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+에서"),
str_sub(review_ra_n_done1$word_done,1,nchar(review_ra_n_done1$word_done)-2),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+것도"),
str_sub(review_ra_n_done1$word_done,1,nchar(review_ra_n_done1$word_done)-2),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+은"),
str_sub(review_ra_n_done1$word_done,1,nchar(review_ra_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+는"),
str_sub(review_ra_n_done1$word_done,1,nchar(review_ra_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+도"),
str_sub(review_ra_n_done1$word_done,1,nchar(review_ra_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+들"),
str_sub(review_ra_n_done1$word_done,1,nchar(review_ra_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+을"),
str_sub(review_ra_n_done1$word_done,1,nchar(review_ra_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+가"),
str_sub(review_ra_n_done1$word_done,1,nchar(review_ra_n_done1$word_done)-1),
word_done))
(2)-4. Word Frequency 시각화 및 해석
review_ra_n_top50 <- review_ra_n_done2 %>% count(word_done2) %>% arrange(-n) %>% head(50)
## 워드클라우드
wordcloud2(review_ra_n_top50,
minSize=10,
size = 1,
fontFamily = "나눔바른고딕",
color = "random-light",
backgroundColor = "grey",
minRotation=0,
shape = "circle")
## bar
review_ra_n_top50 %>%
slice_max(word_done2, n=15) %>%
ggplot(aes(x = n,
y = reorder(word_done2,n),
fill = word_done2)) +
geom_col(show.legend = FALSE) +
geom_text(aes(label=n), hjust=1, size=3)+
labs(x = "단어", y = NULL)+
scale_fill_manual(values=get_brewer_pal("Set3", n = 18))+
theme_get()+
ggtitle("Word Frequency")
- 해석: 영화 “라라랜드”의 리뷰에서 많이 사용된 단어를 워드클라우드로 시각화 한 결과 “최고”,“영상미”,“음악”, “인생영화” 등의 단어가 많이 사용된 것을 알 수 있다.
(3) 영화: “그린북”
### 영화 리뷰 가져오기
all_reviews_greenb <- NULL
url_greenb <- "https://movie.naver.com/movie/bi/mi/pointWriteFormList.nhn?code=171539&type=after&onlyActualPointYn=N&order=newest&page="
# 페이지 반목문으로 불러오기 page=1:240
for (i in 1:240) {
newr <- NULL
url <- paste(url_greenb, i, sep='')
txt <- readLines(url, encoding="UTF-8")
# 영화 리뷰 부분만 가져오기
reviews <- txt[which(str_detect(txt, "id=\"_filtered_ment"))+4]
# 특수문자 제거
reviews <- gsub("<.+?>|\t","", reviews)
newr <- cbind(reviews)
all_reviews_greenb <- rbind(all_reviews_greenb, newr)
}
(3)-1. 텍스트 데이터 Tokenization
### 텍스트 데이터 전처리
all_reviews_greenb <- tibble(reply = all_reviews_greenb,
n_char = nchar(all_reviews_greenb)) %>%
filter(n_char>1) %>%
mutate(id=row_number()) %>%
select(id,reply)
### 형태소 단위로 Tokenization
reviews_greenb_token <- all_reviews_greenb %>%
unnest_tokens(output=word, input=reply, token=SimplePos09) %>%
# 사용자 별로 그룹 지어서
group_by(id) %>%
mutate(word_order = 1:n())
# 명사만 가져오기
review_greenb_n_done <- reviews_greenb_token %>%
filter(str_detect(word, "/n")) %>% # 명사만 추출
mutate(word_done = str_remove(word, "/.*$")) %>% # 형태소 정보 제거
filter(nchar(word_done) > 1)%>%
filter(nchar(word_done) <= 6) %>%
ungroup()
(3)-2. Wordcloud를 통한 많이 쓰이는 단어 시각화
review_greenb_n_top50 <- review_greenb_n_done %>% count(word_done) %>% arrange(-n) %>% head(50)
wordcloud2(review_greenb_n_top50,
minSize=10,
size = 1,
fontFamily = "나눔바른고딕",
color = "random-light",
backgroundColor = "grey",
minRotation=0,
shape = "circle")
(3)-3. 정규표현식을 활용한 텍스트 데이터 수정 및 변형
### 불용어 제거
# 원하는 단어를 넣어서 제거가능
st_word3 <- tibble(word=c("이제","우리","이거","이번","이상","완전",
"처음","나름","오랜만","진짜","하나","정도",
"한번","부분","다음", "영화","재밌게","재밌고")) # 불용어 추가
st_word33 <- review_greenb_n_done[str_detect(review_greenb_n_done$word_done, "^진짜"),]
st_word333 <- review_greenb_n_done[str_detect(review_greenb_n_done$word_done, "^재미*"),]
st_word3333 <- review_greenb_n_done[str_detect(review_greenb_n_done$word_done, "^재밌*"),]
st_word33333 <- review_greenb_n_done[str_detect(review_greenb_n_done$word_done, "^영화*"),]
review_greenb_n_done1 <- review_greenb_n_done %>%
anti_join(st_word3, by=c("word_done"="word")) %>% # 불용어 추가 삭제
anti_join(st_word33, by=c("word_done"="word")) %>% # 불용어 추가 삭제
anti_join(st_word333, by=c("word_done"="word")) %>% # 불용어 추가 삭제
anti_join(st_word3333, by=c("word_done"="word")) %>% # 불용어 추가 삭제
anti_join(st_word33333, by=c("word_done"="word")) %>% # 불용어 추가 삭제
mutate(word_done=gsub("\\d+", "", word_done)) %>% # 숫자제거
mutate(word_done=gsub("[[:punct:]]", "", word_done)) %>% # 모든 특수문자 제거
mutate(word_done=gsub("[A-Za-z]", "", word_done)) %>% # 영문제거
mutate(word_done=gsub("[ㄱ-ㅎ]", "", word_done)) %>%
mutate(word_done=gsub("\\s+", " ", word_done)) %>% # 띄어쓰기 두 번 -> 한 번
filter(nchar(word_done)>1)
형태소 보정
# ~~은(는), ~~~도, ~~~들, ~~~~으로, ~~~을
# 완벽하게 할 수는 없음
# ifelse, str_detect, str_sub 함수를 사용
review_greenb_n_done2 <- review_greenb_n_done1 %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+은"),
str_sub(review_greenb_n_done1$word_done,1,nchar(review_greenb_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+으로"),
str_sub(review_greenb_n_done1$word_done,1,nchar(review_greenb_n_done1$word_done)-2),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+에서"),
str_sub(review_greenb_n_done1$word_done,1,nchar(review_greenb_n_done1$word_done)-2),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+것도"),
str_sub(review_greenb_n_done1$word_done,1,nchar(review_greenb_n_done1$word_done)-2),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+은"),
str_sub(review_greenb_n_done1$word_done,1,nchar(review_greenb_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+는"),
str_sub(review_greenb_n_done1$word_done,1,nchar(review_greenb_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+도"),
str_sub(review_greenb_n_done1$word_done,1,nchar(review_greenb_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+들"),
str_sub(review_greenb_n_done1$word_done,1,nchar(review_greenb_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+을"),
str_sub(review_greenb_n_done1$word_done,1,nchar(review_greenb_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+가"),
str_sub(review_greenb_n_done1$word_done,1,nchar(review_greenb_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+중"),
str_sub(review_greenb_n_done1$word_done,1,nchar(review_greenb_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+들이"),
str_sub(review_greenb_n_done1$word_done,1,nchar(review_greenb_n_done1$word_done)-2),
word_done))
(3)-4. Word Frequency 시각화 및 해석
## 워드클라우드
review_greenb_n_top50 <- review_greenb_n_done2 %>% count(word_done2) %>% arrange(-n) %>% head(50)
wordcloud2(review_greenb_n_top50,
minSize=10,
size = 1,
fontFamily = "나눔바른고딕",
color = "random-light",
backgroundColor = "grey",
minRotation=0,
shape = "circle")
## bar
review_greenb_n_top50 %>%
slice_max(word_done2, n=15) %>%
ggplot(aes(x = n,
y = reorder(word_done2,n),
fill = word_done2)) +
geom_col(show.legend = FALSE) +
geom_text(aes(label=n), hjust=1, size=3)+
labs(x = "단어", y = NULL)+
scale_fill_manual(values=get_brewer_pal("Set3", n = 18))+
theme_get()+
ggtitle("Word Frequency")
- 해석: 영화 “그린북”의 리뷰에서 많이 사용된 단어를 워드클라우드로 시각화 한 결과 “최고”,“편견”,“차별”, “인종차별” 등의 단어가 많이 사용된 것을 알 수 있다.
(4) 영화: “토이스토리3”
### 영화 리뷰 가져오기
all_reviews_toy <- NULL
url_toy <- "https://movie.naver.com/movie/bi/mi/pointWriteFormList.nhn?code=66463&type=after&onlyActualPointYn=N&order=newest&page="
# 페이지 반목문으로 불러오기 page=1:240
for (i in 1:240) {
newr <- NULL
url <- paste(url_toy, i, sep='')
txt <- readLines(url, encoding="UTF-8")
# 영화 리뷰 부분만 가져오기
reviews <- txt[which(str_detect(txt, "id=\"_filtered_ment"))+4]
# 특수문자 제거
reviews <- gsub("<.+?>|\t","", reviews)
newr <- cbind(reviews)
all_reviews_toy <- rbind(all_reviews_toy, newr)
}
(4)-1. 텍스트 데이터 Tokenization
### 텍스트 데이터 전처리
review_dat_toy <- tibble(reply = all_reviews_toy,
n_char = nchar(all_reviews_toy)) %>%
filter(n_char>1) %>%
mutate(id=row_number()) %>%
select(id,reply)
### 형태소 단위로 Tokenization
review_toy_token <- review_dat_toy %>%
unnest_tokens(output=word,
input=reply,
token=SimplePos09) %>%
group_by(id) %>% mutate(word_order = 1:n())
# 명사만 가져오기
review_toy_n_done <- review_toy_token %>%
filter(str_detect(word, "/n")) %>% # 명사만 추출
mutate(word_done = str_remove(word, "/.*$")) %>% # 형태소 정보 제거
filter(nchar(word_done) > 1)%>%
filter(nchar(word_done) <= 6) %>%
ungroup()
(4)-2. Wordcloud를 통한 많이 쓰이는 단어 시각화
review_toy_n_top50 <- review_toy_n_done %>% count(word_done) %>% arrange(-n) %>% head(50)
wordcloud2(review_toy_n_top50,
minSize=10,
size = 1,
fontFamily = "나눔바른고딕",
color = "random-light",
backgroundColor = "grey",
minRotation=0)
(4)-3. 정규표현식을 활용한 텍스트 데이터 수정 및 변형
### 불용어 제거
# 원하는 단어를 넣어서 제거 가능
st_word4 <- tibble(word=c("이제","우리", "이거","이번","이상","완전","처음","나름","오랜만","진짜","하나","정도","필요","ㅠㅠ", "누구", "영화")) # 불용어 추가
st_word44 <- review_toy_n_done[str_detect(review_toy_n_done$word_done, "^영화*"),]
review_toy_n_done1 <- review_toy_n_done %>%
anti_join(st_word4, by=c("word_done"="word")) %>% # 불용어 추가 삭제
anti_join(st_word44, by=c("word_done"="word")) %>% # 불용어 추가 삭제
mutate(word_done=gsub("\\d+", "", word_done)) %>% # 숫자제거
mutate(word_done=gsub("[[:punct:]]", "", word_done)) %>% # 모든 특수문자 제거
mutate(word_done=gsub("[A-Za-z]", "", word_done)) %>% # 영문제거
mutate(word_done=gsub("[ㄱ-ㅎ]", "", word_done)) %>%
mutate(word_done=gsub("\\s+", " ", word_done)) %>% # 띄어쓰기 두 번 -> 한 번
mutate(word_done=gsub("장난감들", "", word_done)) %>%
filter(nchar(word_done)>1)
### 형태소 보정
# ~~은(는), ~~~도, ~~~들, ~~~~으로, ~~~을
# 완벽하게 할 수는 없음
# ifelse, str_detect, str_sub 함수를 사용
review_toy_n_done2 <- review_toy_n_done1 %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+은"),
str_sub(review_toy_n_done1$word_done,1,nchar(review_toy_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+으로"),
str_sub(review_toy_n_done1$word_done,1,nchar(review_toy_n_done1$word_done)-2),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+에서"),
str_sub(review_toy_n_done1$word_done,1,nchar(review_toy_n_done1$word_done)-2),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+것도"),
str_sub(review_toy_n_done1$word_done,1,nchar(review_toy_n_done1$word_done)-2),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+은"),
str_sub(review_toy_n_done1$word_done,1,nchar(review_toy_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+는"),
str_sub(review_toy_n_done1$word_done,1,nchar(review_toy_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+도"),
str_sub(review_toy_n_done1$word_done,1,nchar(review_toy_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+들"),
str_sub(review_toy_n_done1$word_done,1,nchar(review_toy_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+을"),
str_sub(review_toy_n_done1$word_done,1,nchar(review_toy_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+가"),
str_sub(review_toy_n_done1$word_done,1,nchar(review_toy_n_done1$word_done)-1),
word_done)) %>%
mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+중"),
str_sub(review_toy_n_done1$word_done,1,nchar(review_toy_n_done1$word_done)-1),
word_done)) %>% mutate(word_done2=ifelse(str_detect(word_done,"[가-힣]+들이"),
str_sub(review_toy_n_done1$word_done,1,nchar(review_toy_n_done1$word_done)-2),
word_done)) %>%
filter(nchar(word_done2)<=4)
(4)-4. Word Frequency 시각화 및 해석
review_toy_n_top50 <- review_toy_n_done2 %>% count(word_done2) %>% arrange(-n) %>% head(50)
## 워드클라우드
wordcloud2(review_toy_n_top50,
minSize=10,
size = 1,
fontFamily = "나눔바른고딕",
color = "random-light",
backgroundColor = "grey",
minRotation=0,
shape="circle")
## bar
review_toy_n_top50 %>%
slice_max(word_done2, n=15) %>%
ggplot(aes(x = n,
y = reorder(word_done2,n),
fill = word_done2)) +
geom_col(show.legend = FALSE) +
geom_text(aes(label=n), hjust=1, size=3)+
labs(x = "단어", y = NULL)+
scale_fill_manual(values=get_brewer_pal("Set3", n = 18))+
theme_get()+
ggtitle("Word Frequency")
- 해석: 영화 “토이스토리3”의 리뷰에서 많이 사용된 단어를 워드클라우드로 시각화 한 결과 “장난감”,“우디”,“앤디”, “애니메이션” 등의 단어가 많이 사용된 것을 알 수 있다.
5. tf-idf score 시각화
review_up_n_done2$movie <- "업"
review_ra_n_done2$movie <- "라라랜드"
review_greenb_n_done2$movie <- "그린북"
review_toy_n_done2$movie <- "토이스토리3"
review_rbind <- rbind(review_up_n_done2, # 업
review_ra_n_done2, # 라라랜드
review_greenb_n_done2, # 그린북
review_toy_n_done2) # 토이스토리3
review_rbind_tf_idf <- review_rbind %>%
count(movie, word_done2, sort = TRUE) %>%
bind_tf_idf(word_done2, movie, n) %>%
mutate(movie = factor(movie, levels = c("업","라라랜드", "그린북","토이스토리3")))
review_rbind_tf_idf %>%
group_by(movie) %>%
slice_max(tf_idf, n = 15) %>%
ungroup() %>%
mutate(word = reorder_within(word_done2, tf_idf,movie)) %>%
ggplot(aes(tf_idf, word, fill = movie)) +
geom_col(show.legend = FALSE) +
labs(x = "tf-idf", y = NULL) +
facet_wrap(~movie, ncol = 2, scales = "free")+
rcartocolor::scale_fill_carto_d(palette = "PurpOr")+
scale_y_reordered()