Do it! 쉽게 배우는 R 텍스트 마이닝
05 의미망 분석: 
 어떤 맥락에서 단어를 썼을까?
We'll make

We'll make

and

05-1 동시 출현 단어 분석:
Co-occurrence analysis
# 기생충 기사 댓글 불러오기library(readr)raw_news_comment <- read_csv("news_comment_parasite.csv")# 전처리library(dplyr)library(stringr)library(textclean)news_comment <- raw_news_comment %>%  select(reply) %>%  mutate(reply = str_replace_all(reply, "[^가-힣]", " "),         reply = str_squish(reply),         id = row_number())SimplePos22() : 문장의 단어를 22개의 품사로 구분library(tidytext)library(KoNLP)comment_pos <- news_comment %>%  unnest_tokens(input = reply,                output = word,                token = SimplePos22,                drop = F)comment_pos %>%  select(reply, word)## # A tibble: 39,956 x 2##    reply                                word      ##    <chr>                                <chr>     ##  1 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 정말/ma   ##  2 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 우리/np   ##  3 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 집/nc+에/jc…##  4 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 좋/pa+은/et…##  5 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 일/nc+이/jc…##  6 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 생기/pv+어/e…##  7 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 기쁘/pa+고/e…##  8 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 행복한/nc ##  9 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 것/nb+처럼/j…## 10 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 나/np+의/jc…## # … with 39,946 more rowstidyr::separate_rows():sep  = "[+]": "+"가 등장할 때마다 행을 나눔# 품사별로 행 분리library(tidyr)comment_pos <- comment_pos %>%  separate_rows(word, sep = "[+]")comment_pos %>%  select(word, reply)## # A tibble: 70,553 x 2##    word    reply                                  ##    <chr>   <chr>                                  ##  1 정말/ma 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …##  2 우리/np 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …##  3 집/nc   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …##  4 에/jc   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …##  5 좋/pa   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …##  6 은/et   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …##  7 일/nc   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …##  8 이/jc   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …##  9 생기/pv 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …## 10 어/ec   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …## # … with 70,543 more rows"/n"이 붙어있는 단어 추출# 명사 추출하기noun <- comment_pos %>%  filter(str_detect(word, "/n")) %>%  mutate(word = str_remove(word, "/.*$"))noun %>%  select(word, reply)## # A tibble: 27,457 x 2##    word   reply                                   ##    <chr>  <chr>                                   ##  1 우리   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…##  2 집     정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…##  3 일     정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…##  4 행복한 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…##  5 것     정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…##  6 나     정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…##  7 일     정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…##  8 양     정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…##  9 행복   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…## 10 행복   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…## # … with 27,447 more rows# 명사 빈도 구하기noun %>%  count(word, sort = T)## # A tibble: 8,069 x 2##    word         n##    <chr>    <int>##  1 영화       463##  2 기생충     445##  3 봉준호     372##  4 것         353##  5 아카데미   252##  6 축하       232##  7 나         230##  8 대한민국   226##  9 자랑       222## 10 작품상     218## # … with 8,059 more rows"/pv", 형용사:"/pa" 붙어있는 단어 추출# 동사, 형용사 추출하기pvpa <- comment_pos %>%  filter(str_detect(word, "/pv|/pa")) %>%         # "/pv", "/pa" 추출  mutate(word = str_replace(word, "/.*$", "다"))  # "/"로 시작 문자를 "다"로 바꾸기pvpa %>%  select(word, reply)## # A tibble: 5,317 x 2##    word      reply                                ##    <chr>     <chr>                                ##  1 좋다      정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  2 생기다    정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  3 기쁘다    정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  4 축하드리다… 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  5 기쁘다    정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  6 기쁘다    와 너무 기쁘다 이 시국에 정말 내 일같이 기쁘고 감사하다 축하드…##  7 기쁘다    와 너무 기쁘다 이 시국에 정말 내 일같이 기쁘고 감사하다 축하드…##  8 축하드리다… 와 너무 기쁘다 이 시국에 정말 내 일같이 기쁘고 감사하다 축하드…##  9 불다      우리나라의 영화감독분들 그리고 앞으로 그 꿈을 그리는 분들에게 큰…## 10 크다      우리나라의 영화감독분들 그리고 앞으로 그 꿈을 그리는 분들에게 큰…## # … with 5,307 more rows# 품사 결합comment <- bind_rows(noun, pvpa) %>%  filter(str_count(word) >= 2) %>%  arrange(id)comment %>%  select(word, reply)## # A tibble: 26,860 x 2##    word      reply                                ##    <chr>     <chr>                                ##  1 우리      정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  2 행복한    정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  3 행복      정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  4 행복      정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  5 좋다      정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  6 생기다    정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  7 기쁘다    정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  8 축하드리다… 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  9 기쁘다    정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …## 10 시국      와 너무 기쁘다 이 시국에 정말 내 일같이 기쁘고 감사하다 축하드…## # … with 26,850 more rows명사, 동사, 형용사를 한 번에 추출하기
comment_new <- comment_pos %>%  separate_rows(word, sep = "[+]") %>%  filter(str_detect(word, "/n|/pv|/pa")) %>%  mutate(word = ifelse(str_detect(word, "/pv|/pa"),                       str_replace(word, "/.*$", "다"),                       str_remove(word, "/.*$"))) %>%  filter(str_count(word) >= 2) %>%  arrange(id)widyr::pairwise_count()item: 단어feature: 텍스트 구분 기준sort = T: 빈도가 높은 순으로 출력 결과 정렬install.packages("widyr")library(widyr)pair <- comment %>%  pairwise_count(item = word,                 feature = id,                 sort = T)pair## # A tibble: 245,920 x 3##    item1      item2      n##    <chr>      <chr>  <dbl>##  1 영화       기생충   111##  2 기생충     영화     111##  3 감독       봉준호    86##  4 봉준호     감독      86##  5 감독님     봉준호    66##  6 봉준호     감독님    66##  7 만들다     영화      57##  8 영화       만들다    57##  9 기생충     봉준호    54## 10 블랙리스트 감독      54## # … with 245,910 more rows## # A tibble: 245,920 x 3##    item1      item2      n##    <chr>      <chr>  <dbl>##  1 영화       기생충   111##  2 기생충     영화     111##  3 감독       봉준호    86##  4 봉준호     감독      86##  5 감독님     봉준호    66##  6 봉준호     감독님    66##  7 만들다     영화      57##  8 영화       만들다    57##  9 기생충     봉준호    54## 10 블랙리스트 감독      54## # … with 245,910 more rowspair %>% filter(item1 == "영화")## # A tibble: 2,313 x 3##    item1 item2        n##    <chr> <chr>    <dbl>##  1 영화  기생충     111##  2 영화  만들다      57##  3 영화  봉준호      52##  4 영화  받다        48##  5 영화  한국        46##  6 영화  아카데미    42##  7 영화  같다        41##  8 영화  감독        39##  9 영화  아니다      38## 10 영화  좋다        35## # … with 2,303 more rowspair %>% filter(item1 == "봉준호")## # A tibble: 1,579 x 3##    item1  item2          n##    <chr>  <chr>      <dbl>##  1 봉준호 감독          86##  2 봉준호 감독님        66##  3 봉준호 기생충        54##  4 봉준호 영화          52##  5 봉준호 블랙리스트    48##  6 봉준호 대한민국      38##  7 봉준호 자랑          33##  8 봉준호 축하드리다    30##  9 봉준호 송강호        30## 10 봉준호 축하          25## # … with 1,569 more rows05-2 동시 출현 네트워크:
Co-occurrence network
tidygraph::as_tbl_graph()네트워크가 너무 복잡하지 않도록 25회 이상 사용된 단어 추출해 생성
install.packages("tidygraph")library(tidygraph)graph_comment <- pair %>%  filter(n >= 25) %>%  as_tbl_graph()graph_comment## # A tbl_graph: 30 nodes and 108 edges## ### # A directed simple graph with 2 components## ### # Node Data: 30 x 1 (active)##   name  ##   <chr> ## 1 영화  ## 2 기생충## 3 감독  ## 4 봉준호## 5 감독님## 6 만들다## # … with 24 more rows## ### # Edge Data: 108 x 3##    from    to     n##   <int> <int> <dbl>## 1     1     2   111## 2     2     1   111## 3     3     4    86## # … with 105 more rowsggraph::ggraph()install.packages("ggraph")library(ggraph)ggraph(graph_comment) +  geom_edge_link() +                 # 엣지  geom_node_point() +                # 노드  geom_node_text(aes(label = name))  # 텍스트

그래프를 큰 화면에 출력하는 방법
windows()x11()# 한글 폰트 설정library(showtext)font_add_google(name = "Nanum Gothic", family = "nanumgothic")showtext_auto()ggraph(layout = "fr"): 네트워크 형태 결정set.seed()로 난수 고정set.seed(1234)                              # 난수 고정ggraph(graph_comment, layout = "fr") +      # 레이아웃  geom_edge_link(color = "gray50",          # 엣지 색깔                 alpha = 0.5) +             # 엣지 명암  geom_node_point(color = "lightcoral",     # 노드 색깔                  size = 5) +               # 노드 크기  geom_node_text(aes(label = name),         # 텍스트 표시                 repel = T,                 # 노드밖 표시                 size = 5,                  # 텍스트 크기                 family = "nanumgothic") +  # 폰트  theme_graph()                             # 배경 삭제  노드 텍스트 폰트 geom_node_text()의 family로 별도 설정. theme()으로 적용 안됨.

word_network <- function(x) {  ggraph(x, layout = "fr") +    geom_edge_link(color = "gray50",                   alpha = 0.5) +    geom_node_point(color = "lightcoral",                    size = 5) +    geom_node_text(aes(label = name),                   repel = T,                   size = 5,                   family = "nanumgothic") +    theme_graph()}set.seed(1234)word_network(graph_comment)"감독", "봉감독", "봉준호감독"# 유의어 처리하기comment <- comment %>%  mutate(word = ifelse(str_detect(word, "감독") &                      !str_detect(word, "감독상"), "봉준호", word),         word = ifelse(word == "오르다", "올리다", word),         word = ifelse(str_detect(word, "축하"), "축하", word))# 단어 동시 출현 빈도 구하기pair <- comment %>%  pairwise_count(item = word,                 feature = id,                 sort = T)# 네트워크 그래프 데이터 만들기graph_comment <- pair %>%  filter(n >= 25) %>%  as_tbl_graph()# 네트워크 그래프 만들기set.seed(1234)word_network(graph_comment)



as_tbl_graph()directed = F: 방향성 없도록 설정group_infomap()은 방향성 없는 네트워크 그래프 데이터에서만 커뮤니티를 찾아줌as_tbl_graph()directed = F: 방향성 없도록 설정group_infomap()은 방향성 없는 네트워크 그래프 데이터에서만 커뮤니티를 찾아줌centrality_degree()group_infomap()as.factor(): factor 타입으로 변환해 노드 그룹별로 다른 색으로 표현set.seed(1234)graph_comment <- pair %>%  filter(n >= 25) %>%  as_tbl_graph(directed = F) %>%  mutate(centrality = centrality_degree(),    # 연결 중심성         group = as.factor(group_infomap()))  # 커뮤니티graph_comment## # A tbl_graph: 36 nodes and 152 edges## ### # An undirected multigraph with 1 component## ### # Node Data: 36 x 3 (active)##   name       centrality group##   <chr>           <dbl> <fct>## 1 봉준호             62 4    ## 2 축하               34 2    ## 3 영화               26 3    ## 4 블랙리스트          6 6    ## 5 기생충             26 1    ## 6 대한민국           10 3    ## # … with 30 more rows## ### # Edge Data: 152 x 3##    from    to     n##   <int> <int> <dbl>## 1     1     2   198## 2     1     2   198## 3     1     3   119## # … with 149 more rowsgeom_node_point(aes())size = centrality: 연결 중심성에 따라 노드 크기 설정color = group: 커뮤니티 별로 노드 색깔 다르게geom_node_point(show.legend = F): 범례 제거scale_size(range = c(5, 15)): 노드 크기 5~15 범위 유지set.seed(1234)ggraph(graph_comment, layout = "fr") +      # 레이아웃  geom_edge_link(color = "gray50",          # 엣지 색깔                 alpha = 0.5) +             # 엣지 명암  geom_node_point(aes(size = centrality,    # 노드 크기                      color = group),       # 노드 색깔                  show.legend = F) +        # 범례 삭제  scale_size(range = c(5, 15)) +            # 노드 크기 범위  geom_node_text(aes(label = name),         # 텍스트 표시                 repel = T,                 # 노드밖 표시                 size = 5,                  # 텍스트 크기                 family = "nanumgothic") +  # 폰트  theme_graph()                             # 배경 삭제
graph_comment %>%  filter(name == "봉준호")## # A tbl_graph: 1 nodes and 0 edges## ### # An unrooted tree## ### # Node Data: 1 x 3 (active)##   name   centrality group##   <chr>       <dbl> <fct>## 1 봉준호         62 4    ## ### # Edge Data: 0 x 3## # … with 3 variables: from <int>, to <int>, n <dbl>graph_comment %>%  filter(group == 4) %>%  arrange(-centrality) %>%  data.frame()##     name centrality group## 1 봉준호         62     4## 2   받다         10     4## 3   자랑          6     4## 4 만들다          4     4graph_comment %>%  arrange(-centrality)## # A tbl_graph: 36 nodes and 152 edges## ### # An undirected multigraph with 1 component## ### # Node Data: 36 x 3 (active)##   name     centrality group##   <chr>         <dbl> <fct>## 1 봉준호           62 4    ## 2 축하             34 2    ## 3 영화             26 3    ## 4 기생충           26 1    ## 5 작품상           14 5    ## 6 대한민국         10 3    ## # … with 30 more rows## ### # Edge Data: 152 x 3##    from    to     n##   <int> <int> <dbl>## 1     1     2   198## 2     1     2   198## 3     1     3   119## # … with 149 more rowsgraph_comment %>%  filter(group == 2) %>%  arrange(-centrality) %>%  data.frame()##     name centrality group## 1   축하         34     2## 2   좋다          8     2## 3   진심          4     2## 4   수상          4     2## 5   없다          4     2## 6   대단          2     2## 7 기쁘다          2     2news_comment %>%  filter(str_detect(reply, "봉준호") & str_detect(reply, "대박")) %>%  select(reply)## # A tibble: 19 x 1##    reply                                          ##    <chr>                                          ##  1 대박 대박 진짜 대박 봉준호 감독님과 우리 배우들 너무 다랑스러워요…##  2 내가 죽기전에 아카데미에서 한국어를 들을줄이야 봉준호대박 기생충대박…##  3 대박 관왕이라니 축하합니다 봉준호를 배출한 충무로 그리고 문화강국 대한 민국…##  4 우와 대박 진자 대단하다 봉준호                 ##  5 봉준호 경사났네 대박중에 대에박 축하합니다     ##  6 봉준호 작품상 탔다 대박                        ##  7 봉준호 군대 면제시켜도될듯 대박 여윽시 위대한 한국에는 위대한 봉준호 형님이 계시지…##  8 아니 다른상을 받은것도 충분히 대단하고 굉장하지만 최고의 영예인 작품상을 받은거는 …##  9 봉준호 군대 면제시켜도될듯 대박 여윽시 위대한 한국에는 위대한 봉준호 형님이 계시지…## 10 봉준호감독님대박 축하합니다                    ## # … with 9 more rowsnews_comment %>%  filter(str_detect(reply, "박근혜") & str_detect(reply, "블랙리스트")) %>%  select(reply)## # A tibble: 63 x 1##    reply                                          ##    <chr>                                          ##  1 일베와 자한당이 싫어하는 봉준호 감독이 아카데미에서 상받으니 쪽바리들처럼 엄청 싫어…##  2 박근혜 블랙리스트 로 낙인찍은 봉준호 감독님이 아시아 최초로 오스카에서 상을 받아버…##  3 우리나라에서만 좌파다 빨갱이다 라고 비하함 박근혜 때 이런 세계적 감독을 블랙리스트…##  4 박근혜 최순실 블랙리스트에 오른 훌륭하신 감독님 축하합니다…##  5 박근혜정부가 얼마나 썩고 무능했냐면 각종 영화제에서 최고상 수상을 받는 유능한 감독…##  6 넷상 보수들 만큼 이중적인 새 끼들 없음 봉준호 송강호 보고 종북좌빨 홍어드립 치던…##  7 박근혜 자한당 독재시절 봉준호 송강호를 블랙리스트 올려놓고 활동 방해 감시하면서 괴…##  8 대단합니다 김연아 방탄 봉준호 스포츠 음악 영화 못하는게 없어요 좌빨 감독이라 좌파…##  9 송강호 봉준호 박근혜 이명박 시절 블랙리스트 이제 어떻게 깔려구…## 10 이명박근혜정권당시 좌파감독이라고 블랙리스트까지 올랏던 봉준호 역사적위업을 달성햇네 …## # … with 53 more rowsnews_comment %>%  filter(str_detect(reply, "기생충") & str_detect(reply, "조국")) %>%  select(reply)## # A tibble: 64 x 1##    reply                                          ##    <chr>                                          ##  1 조국이가 받아야 한다 기생충 스토리 제공        ##  2 한번도경험하지 못한 조국가족사기단기생충 개봉박두…##  3 와 조국 가족 사기단 부제 기생충 최고           ##  4 문재인과 조국 기생충 리얼                      ##  5 기생충은 좌좀 조국 가족을 패러디한 영화라서 우파들도 열광하고 있는 것이다 같은 영…##  6 조국 가족이 기생충 영화를 꼭 봐야되는데        ##  7 좌파 인생영화인데 좌파 기생충들에게 이 상을 받쳐라 조국 서울대 문서위조학과 교수님…##  8 기생충 조국 봉준호 만세                        ##  9 봉준호감독님 글로벌 영화계 큰상수상을 진심으로 축하합니다 다만 기생충 작품은 조국 …## 10 기생충보면서 조국생각난사람 나쁜일라나 봉준호 감독님이 현 시대를 참 잘 반영해서 만…## # … with 54 more rows tidygraph 패키지의 연결 중심성 지표, 커뮤니티 탐지 알고리즘: tidygraph.data-imaginist.com
05-3 단어 간 상관 분석:
Phi coefficient
"영화"-"기생충""영화"-"기생충"

 
ϕ=ad−bc√(a+b)(c+d)(a+c)(b+d)
widyr::pairwise_cor()item: 단어feature: 텍스트 구분 기준sort = T: 파이 계수 높은순 정렬word_cors <- comment %>%  add_count(word) %>%  filter(n >= 20) %>%  pairwise_cor(item = word,                feature = id,                sort = T)word_cors  add_count() 원자료에 빈도 나타낸 변수 추가
widyr::pairwise_cor()item: 단어feature: 텍스트 구분 기준sort = T: 파이 계수 높은순 정렬word_cors <- comment %>%  add_count(word) %>%  filter(n >= 20) %>%  pairwise_cor(item = word,                feature = id,                sort = T)word_cors  add_count() 원자료에 빈도 나타낸 변수 추가
## # A tibble: 26,732 x 3##    item1      item2      correlation##    <chr>      <chr>            <dbl>##  1 올리다     블랙리스트       0.478##  2 블랙리스트 올리다           0.478##  3 역사       쓰다             0.370##  4 쓰다       역사             0.370##  5 박근혜     블랙리스트       0.322##  6 블랙리스트 박근혜           0.322##  7 가족       조국             0.306##  8 조국       가족             0.306##  9 작품상     감독상           0.276## 10 감독상     작품상           0.276## # … with 26,722 more rowsword_cors %>%  filter(item1 == "대한민국")## # A tibble: 163 x 3##    item1    item2  correlation##    <chr>    <chr>        <dbl>##  1 대한민국 국민        0.182 ##  2 대한민국 자랑        0.158 ##  3 대한민국 위상        0.149 ##  4 대한민국 국격        0.129 ##  5 대한민국 위대한      0.100 ##  6 대한민국 세계        0.0910##  7 대한민국 문화        0.0757##  8 대한민국 감사합      0.0724##  9 대한민국 나라        0.0715## 10 대한민국 오늘        0.0715## # … with 153 more rowsword_cors %>%  filter(item1 == "역사")## # A tibble: 163 x 3##    item1 item2    correlation##    <chr> <chr>          <dbl>##  1 역사  쓰다          0.370 ##  2 역사  최초          0.117 ##  3 역사  한국          0.0982##  4 역사  순간          0.0910##  5 역사  한국영화      0.0821##  6 역사  아니다        0.0774##  7 역사  감사          0.0654##  8 역사  영광          0.0640##  9 역사  영화제        0.0596## 10 역사  오스카        0.0593## # … with 153 more rows# 관심 단어 목록 생성target <- c("대한민국", "역사", "수상소감", "조국", "박근혜", "블랙리스트")top_cors <- word_cors %>%  filter(item1 %in% target) %>%  group_by(item1) %>%  slice_max(correlation, n = 8)# 그래프 순서 정하기top_cors$item1 <- factor(top_cors$item1, levels = target)library(ggplot2)ggplot(top_cors, aes(x = reorder_within(item2, correlation, item1),                 y = correlation,                 fill = item1)) +  geom_col(show.legend = F) +  facet_wrap(~ item1, scales = "free") +  coord_flip() +  scale_x_reordered() +  labs(x = NULL) +  theme(text = element_text(family = "nanumgothic"))
set.seed(1234)graph_cors <- word_cors %>%  filter(correlation >= 0.15) %>%  as_tbl_graph(directed = F) %>%  mutate(centrality = centrality_degree(),         group = as.factor(group_infomap()))set.seed(1234)ggraph(graph_cors, layout = "fr") +  geom_edge_link(color = "gray50",                 aes(edge_alpha = correlation,   # 엣지 명암                     edge_width = correlation),  # 엣지 두께                 show.legend = F) +              # 범례 삭제  scale_edge_width(range = c(1, 4)) +            # 엣지 두께 범위  geom_node_point(aes(size = centrality,                      color = group),                  show.legend = F) +  scale_size(range = c(5, 10)) +  geom_node_text(aes(label = name),                 repel = T,                 size = 5,                 family = "nanumgothic") +  theme_graph()
05-4
연이어 사용된 단어쌍 분석: n-gram


샘플 텍스트로 엔그램 토큰화해보기
tidytext::unnest_tokens()token = "ngrams"n: 기준 단어 수text <- tibble(value = "대한민국은 민주공화국이다. 대한민국의 주권은 국민에게 있고, 모든 권력은 국민으로부터 나온다.")text## # A tibble: 1 x 1##   value                                                                                       ##   <chr>                                                                                       ## 1 대한민국은 민주공화국이다. 대한민국의 주권은 국민에게 있고, 모든 권력은 국민으로부터 나온다.# 바이그램 토큰화text %>%  unnest_tokens(input = value,                output = word,                token = "ngrams",                n = 2)## # A tibble: 9 x 1##   word                     ##   <chr>                    ## 1 대한민국은 민주공화국이다## 2 민주공화국이다 대한민국의## 3 대한민국의 주권은        ## 4 주권은 국민에게          ## 5 국민에게 있고            ## 6 있고 모든                ## 7 모든 권력은              ## 8 권력은 국민으로부터      ## 9 국민으로부터 나온다# 트라이그램 토큰화text %>%  unnest_tokens(input = value,                output = word,                token = "ngrams",                n = 3)## # A tibble: 8 x 1##   word                                ##   <chr>                               ## 1 대한민국은 민주공화국이다 대한민국의## 2 민주공화국이다 대한민국의 주권은    ## 3 대한민국의 주권은 국민에게          ## 4 주권은 국민에게 있고                ## 5 국민에게 있고 모든                  ## 6 있고 모든 권력은                    ## 7 모든 권력은 국민으로부터            ## 8 권력은 국민으로부터 나온다# 단어 기준 토큰화text %>%  unnest_tokens(input = value,                output = word,                token = "words")## # A tibble: 10 x 1##    word          ##    <chr>         ##  1 대한민국은    ##  2 민주공화국이다##  3 대한민국의    ##  4 주권은        ##  5 국민에게      ##  6 있고          ##  7 모든          ##  8 권력은        ##  9 국민으로부터  ## 10 나온다# 유니그램 토큰화text %>%  unnest_tokens(input = value,                output = word,                token = "ngrams",                n = 1)## # A tibble: 10 x 1##    word          ##    <chr>         ##  1 대한민국은    ##  2 민주공화국이다##  3 대한민국의    ##  4 주권은        ##  5 국민에게      ##  6 있고          ##  7 모든          ##  8 권력은        ##  9 국민으로부터  ## 10 나온다comment_pos 이용: 댓글을 형태소로 토큰화 후 품사별로 행 분리comment_new <- comment_pos %>%  separate_rows(word, sep = "[+]") %>%  filter(str_detect(word, "/n|/pv|/pa")) %>%  mutate(word = ifelse(str_detect(word, "/pv|/pa"),                       str_replace(word, "/.*$", "다"),                       str_remove(word, "/.*$"))) %>%  filter(str_count(word) >= 2) %>%  arrange(id)바이그램으로 토큰화할 때는 형태소 추출 먼저
comment_new <- comment_new %>%  mutate(word = ifelse(str_detect(word, "감독") &                      !str_detect(word, "감독상"), "봉준호", word),         word = ifelse(word  == "오르다", "올리다", word),         word = ifelse(str_detect(word, "축하"), "축하", word))comment_new %>%  select(word)## # A tibble: 26,860 x 1##    word  ##    <chr> ##  1 우리  ##  2 좋다  ##  3 생기다##  4 기쁘다##  5 행복한##  6 행복  ##  7 축하  ##  8 행복  ##  9 기쁘다## 10 기쁘다## # … with 26,850 more rowsline_comment <- comment_new %>%  group_by(id) %>%  summarise(sentence = paste(word, collapse = " "))line_comment## # A tibble: 4,007 x 2##       id sentence                                                               ##  * <int> <chr>                                                                  ##  1     1 우리 좋다 생기다 기쁘다 행복한 행복 축하 행복 기쁘다                   ##  2     2 기쁘다 시국 기쁘다 감사하다 축하 진심                                  ##  3     3 우리나라 봉준호 불다 크다 영감 봉준호 공동각본쓴 한진 작가님 축하 축하 드리다…##  4     4 봉준호 봉준호 우리나라 대한민국 자랑 세계 어디 우리 한국인 힘내다 삽시 ##  5     5 노벨상 탄느낌이네요 축하                                               ##  6     6 기생충 받다 박수 치다 감독상 기대다 봉준호 봉준호                      ##  7     7 대한민국 영화사 쓰다 계시다                                            ##  8     8 아카데미상 받다 태극기 휘날리다 광해 명량 전부문 휩쓸어야겠            ##  9     9 다시한번 보이다 영화관                                                 ## 10    10 대한민국 봉준호 대단 한국의 문화 자긍심 가지                           ## # … with 3,997 more rowsbigram_comment <- line_comment %>%  unnest_tokens(input = sentence,                output = bigram,                token = "ngrams",                n = 2)bigram_comment## # A tibble: 23,348 x 2##       id bigram       ##    <int> <chr>        ##  1     1 우리 좋다    ##  2     1 좋다 생기다  ##  3     1 생기다 기쁘다##  4     1 기쁘다 행복한##  5     1 행복한 행복  ##  6     1 행복 축하    ##  7     1 축하 행복    ##  8     1 행복 기쁘다  ##  9     2 기쁘다 시국  ## 10     2 시국 기쁘다  ## # … with 23,338 more rows# 바이그램 분리하기bigram_seprated <- bigram_comment %>%  separate(bigram, c("word1", "word2"), sep = " ")bigram_seprated## # A tibble: 23,348 x 3##       id word1  word2 ##    <int> <chr>  <chr> ##  1     1 우리   좋다  ##  2     1 좋다   생기다##  3     1 생기다 기쁘다##  4     1 기쁘다 행복한##  5     1 행복한 행복  ##  6     1 행복   축하  ##  7     1 축하   행복  ##  8     1 행복   기쁘다##  9     2 기쁘다 시국  ## 10     2 시국   기쁘다## # … with 23,338 more rows# 단어쌍 빈도 구하기pair_bigram <- bigram_seprated %>%  count(word1, word2, sort = T) %>%  na.omit()pair_bigram## # A tibble: 19,030 x 3##    word1      word2          n##    <chr>      <chr>      <int>##  1 봉준호     봉준호       155##  2 블랙리스트 올리다        64##  3 진심       축하          64##  4 봉준호     축하          57##  5 봉준호     송강호        34##  6 영화       만들다        31##  7 축하       봉준호        31##  8 대단       축하          27##  9 봉준호     블랙리스트    27## 10 대박       축하          26## # … with 19,020 more rows na.omit(): 결측치 행 제거: 한 단어로 된 문장은 바이그램으로 토큰화하면 NA가 됨 
    ex) '축하합니다', '멋집니다'
# 동시 출현 단어쌍pair %>%  filter(item1 == "대한민국")## # A tibble: 1,010 x 3##    item1    item2        n##    <chr>    <chr>    <dbl>##  1 대한민국 봉준호      70##  2 대한민국 축하        54##  3 대한민국 자랑        44##  4 대한민국 영화        30##  5 대한민국 기생충      27##  6 대한민국 국민        22##  7 대한민국 세계        16##  8 대한민국 아카데미    16##  9 대한민국 위상        15## 10 대한민국 좋다        14## # … with 1,000 more rows# 바이그램 단어쌍pair_bigram %>%  filter(word1 == "대한민국")## # A tibble: 109 x 3##    word1    word2      n##    <chr>    <chr>  <int>##  1 대한민국 국민      21##  2 대한민국 자랑      15##  3 대한민국 영화      11##  4 대한민국 국격       8##  5 대한민국 위상       7##  6 대한민국 만세       6##  7 대한민국 봉준호     5##  8 대한민국 문화       4##  9 대한민국 영광       4## 10 대한민국 기생충     3## # … with 99 more rows# 네트워크 그래프 데이터 만들기graph_bigram <- pair_bigram %>%  filter(n >= 8) %>%  as_tbl_graph()# 네트워크 그래프 만들기set.seed(1234)word_network(graph_bigram)

bigram_seprated의 유의어 통일, 같은 단어 연속 단어쌍 제거# 유의어 처리bigram_seprated <- bigram_seprated %>%  mutate(word1 = ifelse(str_detect(word1, "대단"), "대단", word1),         word2 = ifelse(str_detect(word2, "대단"), "대단", word2),         word1 = ifelse(str_detect(word1, "자랑"), "자랑", word1),         word2 = ifelse(str_detect(word2, "자랑"), "자랑", word2),         word1 = ifelse(str_detect(word1, "짝짝짝"), "짝짝짝", word1),         word2 = ifelse(str_detect(word2, "짝짝짝"), "짝짝짝", word2)) %>%  # 같은 단어 연속 제거  filter(word1 != word2)# 단어쌍 빈도 구하기pair_bigram <- bigram_seprated %>%  count(word1, word2, sort = T) %>%  na.omit()# 네트워크 그래프 데이터 만들기set.seed(1234)graph_bigram <- pair_bigram %>%  filter(n >= 8) %>%  as_tbl_graph(directed = F) %>%  mutate(centrality = centrality_degree(),    # 중심성         group = as.factor(group_infomap()))  # 커뮤니티# 네트워크 그래프 만들기set.seed(1234)ggraph(graph_bigram, layout = "fr") +         # 레이아웃  geom_edge_link(color = "gray50",            # 엣지 색깔                 alpha = 0.5) +               # 엣지 명암  geom_node_point(aes(size = centrality,      # 노드 크기                      color = group),         # 노드 색깔                  show.legend = F) +          # 범례 삭제  scale_size(range = c(4, 8)) +               # 노드 크기 범위  geom_node_text(aes(label = name),           # 텍스트 표시                 repel = T,                   # 노드밖 표시                 size = 5,                    # 텍스트 크기                 family = "nanumgothic") +    # 폰트  theme_graph()                               # 배경 삭제

 
 




정리하기
# 품사 기준 토큰화comment_pos <- news_comment %>%  unnest_tokens(input = reply,                output = word,                token = SimplePos22,                drop = F)# 명사, 동사, 형용사 추출comment <- comment_pos %>%  separate_rows(word, sep = "[+]") %>%  filter(str_detect(word, "/n|/pv|/pa")) %>%  mutate(word = ifelse(str_detect(word, "/pv|/pa"),                       str_replace(word, "/.*$", "다"),                       str_remove(word, "/.*$"))) %>%  filter(str_count(word) >= 2) %>%  arrange(id)# 단어 동시 출현 빈도 구하기pair <- comment %>%  pairwise_count(item = word,                 feature = id,                 sort = T)# 파이 계수 구하기word_cors <- comment %>%  add_count(word) %>%  filter(n >= 20) %>%  pairwise_cor(item = word,               feature = id,               sort = T)# 텍스트를 한 행으로 구성line_comment <- comment %>%  group_by(id) %>%  summarise(sentence = paste(word, collapse = " "))# 바이그램 토큰화bigram_comment <- line_comment %>%  unnest_tokens(input = sentence,                output = bigram,                token = "ngrams",                n = 2)# 바이그램 분리bigram_seprated <- bigram_comment %>%  separate(bigram, c("word1", "word2"), sep = " ")# 단어쌍 빈도 구하기pair_bigram <- bigram_seprated %>%  count(word1, word2, sort = T) %>%  na.omit()# 네트워크 그래프 데이터 만들기set.seed(1234)graph_comment <- pair_bigram %>%  filter(n >= 8) %>%  as_tbl_graph(directed = F) %>%  mutate(centrality = centrality_degree(),         group = as.factor(group_infomap()))# 네트워크 그래프 만들기set.seed(1234)ggraph(graph_comment) +  geom_edge_link() +  geom_node_point(aes(size = centrality,                      color = group)) +  geom_node_text(aes(label = name))"news_comment_BTS.csv"에는 2020년 9월 21일 방탄소년단이 '빌보드 핫 100 차트' 1위에 오른 소식을 다룬 기사에 달린 댓글이 들어있습니다. "news_comment_BTS.csv"를 이용해 문제를 해결해 보세요.
Q1. "news_comment_BTS.csv"를 불러온 다음 행 번호를 나타낸 변수를 추가하고 분석에 적합하게
       전처리하세요.
Q2. 댓글에서 명사, 동사, 형용사를 추출하고 '/로 시작하는 모든 문자'를 '다'로 바꾸세요.
Q3. 다음 코드를 이용해 유의어를 통일한 다음 한 댓글이 하나의 행이 되도록 단어를 결합하세요.
# 유의어 통일하기comment <- comment %>%  mutate(word = case_when(str_detect(word, "축하") ~ "축하",                          str_detect(word, "방탄") ~ "자랑",                          str_detect(word, "대단") ~ "대단",                          str_detect(word, "자랑") ~ "자랑",                          T ~ word))"news_comment_BTS.csv"에는 2020년 9월 21일 방탄소년단이 '빌보드 핫 100 차트' 1위에 오른 소식을 다룬 기사에 달린 댓글이 들어있습니다. "news_comment_BTS.csv"를 이용해 문제를 해결해 보세요.
"fr"로 설정하세요.Q1. "news_comment_BTS.csv"를 불러온 다음 행 번호를 나타낸 변수를 추가하고 분석에 적합하게
       전처리하세요.
library(readr)library(dplyr)raw_news_comment <- read_csv("news_comment_BTS.csv")glimpse(raw_news_comment)## Rows: 1,200## Columns: 5## $ reg_time <dttm> 2020-09-01 22:58:09, 2020-09-01 09:56:46…## $ reply    <chr> "국보소년단<U+0001F49C>", "아줌마가 들어도 좋더라", "팩트체…## $ press    <chr> "한국경제", "한국경제", "한국경제", "한국경제", "한국경제", "…## $ title    <chr> "[속보]BTS '다이너마이트', 한국 가수 최초로 빌보드 싱글 1위", …## $ url      <chr> "https://news.naver.com/main/read.nhn?mod…library(stringr)library(textclean)news_comment <- raw_news_comment %>%  select(reply) %>%  mutate(id = row_number(),         reply = str_replace_all(reply, "[^가-힣]", " "),         reply = str_squish(reply))news_comment %>%  select(id, reply)## # A tibble: 1,200 x 2##       id reply                                    ##    <int> <chr>                                    ##  1     1 국보소년단                               ##  2     2 아줌마가 들어도 좋더라                   ##  3     3 팩트체크 현재 빌보드 위 방탄소년단 위 위 위 위 위 위 위 위 위…##  4     4 방탄소년단이 한국사람이라 너무 자랑스러워요 우리오래오래 함께하자…##  5     5 대단한 월드 클래스는 다르네 좋은 소식 응원해요…##  6     6 정국오빠 생일과 더불어 빌보드 위기사라니 축제구나…##  7     7 정말 축하하고 응원하지만 집에서 여러 계정으로 스트리밍 돌리고 사재기하고…##  8     8 기자는 자고 일어났지만 팬들은 못자고 발표 기다림…##  9     9 자랑스럽다 축하합니다                    ## 10    10 늘 응원하고 사랑합니다                   ## # … with 1,190 more rowsQ2. 댓글에서 명사, 동사, 형용사를 추출하고 '/로 시작하는 모든 문자'를 '다'로 바꾸세요.
# 품사 기준 토큰화library(tidytext)library(KoNLP)comment_pos <- news_comment %>%  unnest_tokens(input = reply,                output = word,                token = SimplePos22,                drop = F)# 한 행이 한 품사를 구성하도록 분리library(tidyr)comment_pos <- comment_pos %>%  separate_rows(word, sep = "[+]")comment_pos %>%  select(word, reply)## # A tibble: 20,851 x 2##    word        reply                 ##    <chr>       <chr>                 ##  1 국보소년/nc 국보소년단            ##  2 단/ma       국보소년단            ##  3 아줌마/nc   아줌마가 들어도 좋더라##  4 가/jc       아줌마가 들어도 좋더라##  5 들/pv       아줌마가 들어도 좋더라##  6 어도/ec     아줌마가 들어도 좋더라##  7 좋/pa       아줌마가 들어도 좋더라##  8 더/ep       아줌마가 들어도 좋더라##  9 어/ec       아줌마가 들어도 좋더라## 10 라/nc       아줌마가 들어도 좋더라## # … with 20,841 more rows# 명사, 동사, 형용사 추출comment <- comment_pos %>%  separate_rows(word, sep = "[+]") %>%  filter(str_detect(word, "/n|/pv|/pa")) %>%  mutate(word = ifelse(str_detect(word, "/pv|/pa"),                       str_replace(word, "/.*$", "다"),                       str_remove(word, "/.*$"))) %>%  filter(str_count(word) >= 2) %>%  arrange(id)comment %>%  select(word, reply)## # A tibble: 7,539 x 2##    word      reply                                ##    <chr>     <chr>                                ##  1 국보소년  국보소년단                           ##  2 아줌마    아줌마가 들어도 좋더라               ##  3 들다      아줌마가 들어도 좋더라               ##  4 좋다      아줌마가 들어도 좋더라               ##  5 팩트체크  팩트체크 현재 빌보드 위 방탄소년단 위 위 위 위 위 위 위 위 …##  6 빌보드    팩트체크 현재 빌보드 위 방탄소년단 위 위 위 위 위 위 위 위 …##  7 방탄소년단… 팩트체크 현재 빌보드 위 방탄소년단 위 위 위 위 위 위 위 위 …##  8 방탄소년단… 방탄소년단이 한국사람이라 너무 자랑스러워요 우리오래오래 함께하자…##  9 한국사람  방탄소년단이 한국사람이라 너무 자랑스러워요 우리오래오래 함께하자…## 10 자랑      방탄소년단이 한국사람이라 너무 자랑스러워요 우리오래오래 함께하자…## # … with 7,529 more rowsQ3. 다음 코드를 이용해 유의어를 통일한 다음 한 댓글이 하나의 행이 되도록 단어를 결합하세요.
# 유의어 통일하기comment <- comment %>%  mutate(word = case_when(str_detect(word, "축하") ~ "축하",                          str_detect(word, "방탄") ~ "자랑",                          str_detect(word, "대단") ~ "대단",                          str_detect(word, "자랑") ~ "자랑",                          T ~ word))# 단어를 댓글별 한 행으로 결합line_comment <- comment %>%  group_by(id) %>%  summarise(sentence = paste(word, collapse = " "))line_comment## # A tibble: 1,155 x 2##       id sentence                                 ##  * <int> <chr>                                    ##  1     1 국보소년                                 ##  2     2 아줌마 들다 좋다                         ##  3     3 팩트체크 빌보드 자랑                     ##  4     4 자랑 한국사람 자랑 우리오래오래 함께하다 ##  5     5 대단 월드 클래스 다르다 좋다 소식 응원해 ##  6     6 정국오빠 생일 더불다 빌보드 위기사 축제구##  7     7 축하 응원하지 계정 스트리밍 돌리다 사재기 팬덤 테러하 개념보고 놀라다…##  8     8 기자 자다 일어나다 패다 못자 발표        ##  9     9 자랑 축하                                ## 10    10 응원 사랑합                              ## # … with 1,145 more rowsQ4. 댓글을 바이그램으로 토큰화한 다음 바이그램 단어쌍을 분리하세요.
# 바이그램 토큰화bigram_comment <- line_comment %>%  unnest_tokens(input = sentence,                output = bigram,                token = "ngrams",                n = 2)bigram_comment## # A tibble: 6,541 x 2##       id bigram               ##    <int> <chr>                ##  1     1 <NA>                 ##  2     2 아줌마 들다          ##  3     2 들다 좋다            ##  4     3 팩트체크 빌보드      ##  5     3 빌보드 자랑          ##  6     4 자랑 한국사람        ##  7     4 한국사람 자랑        ##  8     4 자랑 우리오래오래    ##  9     4 우리오래오래 함께하다## 10     5 대단 월드            ## # … with 6,531 more rows# 바이그램 단어쌍 분리bigram_seprated <- bigram_comment %>%  separate(bigram, c("word1", "word2"), sep = " ")bigram_seprated## # A tibble: 6,541 x 3##       id word1        word2       ##    <int> <chr>        <chr>       ##  1     1 <NA>         <NA>        ##  2     2 아줌마       들다        ##  3     2 들다         좋다        ##  4     3 팩트체크     빌보드      ##  5     3 빌보드       자랑        ##  6     4 자랑         한국사람    ##  7     4 한국사람     자랑        ##  8     4 자랑         우리오래오래##  9     4 우리오래오래 함께하다    ## 10     5 대단         월드        ## # … with 6,531 more rows# 단어쌍 빈도 구하기pair_bigram <- bigram_seprated %>%  count(word1, word2, sort = T) %>%  na.omit()pair_bigram## # A tibble: 5,455 x 3##    word1  word2     n##    <chr>  <chr> <int>##  1 축하   하다     43##  2 자랑   축하     40##  3 자랑   자랑     38##  4 축하   자랑     35##  5 대단   자랑     24##  6 진짜   자랑     24##  7 진짜   대단     23##  8 자랑   진짜     17##  9 빌보드 축하     14## 10 군대   면제     13## # … with 5,445 more rows# 네트워크 그래프 데이터 만들기library(tidygraph)set.seed(1234)graph_bigram <- pair_bigram %>%  filter(n >= 3) %>%  as_tbl_graph(directed = F) %>%  mutate(centrality = centrality_degree(),         group = as.factor(group_infomap()))graph_bigram## # A tbl_graph: 90 nodes and 130 edges## ### # An undirected multigraph with 6 components## ### # Node Data: 90 x 3 (active)##   name   centrality group##   <chr>       <dbl> <fct>## 1 축하           18 1    ## 2 자랑           45 1    ## 3 대단            9 1    ## 4 진짜           12 1    ## 5 빌보드         16 2    ## 6 군대            3 4    ## # … with 84 more rows## ### # Edge Data: 130 x 3##    from    to     n##   <int> <int> <int>## 1     1    61    43## 2     1     2    40## 3     2     2    38## # … with 127 more rows"fr"로 설정하세요.library(ggraph)set.seed(1234)ggraph(graph_bigram, layout = "fr") +  geom_edge_link() +  geom_node_point(aes(size = centrality,                      color = group),                  show.legend = F) +  geom_node_text(aes(label = name),                 repel = T,                 size = 5) +  theme_graph()
# 그래프 꾸미기library(showtext)font_add_google(name = "Nanum Gothic", family = "nanumgothic")set.seed(1234)ggraph(graph_bigram, layout = "fr") +         # 레이아웃  geom_edge_link(color = "gray50",            # 엣지 색깔                 alpha = 0.5) +               # 엣지 명암  geom_node_point(aes(size = centrality,      # 노드 크기                      color = group),         # 노드 색깔                  show.legend = F) +          # 범례 삭제  scale_size(range = c(4, 8)) +               # 노드 크기 범위  geom_node_text(aes(label = name),           # 텍스트 표시                 repel = T,                   # 노드밖 표시                 size = 5,                    # 텍스트 크기                 family = "nanumgothic") +    # 폰트  theme_graph()                               # 배경 삭제
끝
Keyboard shortcuts
| ↑, ←, Pg Up, k | Go to previous slide | 
| ↓, →, Pg Dn, Space, j | Go to next slide | 
| Home | Go to first slide | 
| End | Go to last slide | 
| Number + Return | Go to specific slide | 
| b / m / f | Toggle blackout / mirrored / fullscreen mode | 
| c | Clone slideshow | 
| p | Toggle presenter mode | 
| t | Restart the presentation timer | 
| ?, h | Toggle this help | 
| o | Tile View: Overview of Slides | 
| Esc | Back to slideshow | 
Do it! 쉽게 배우는 R 텍스트 마이닝
05 의미망 분석: 
 어떤 맥락에서 단어를 썼을까?
We'll make

We'll make

and

05-1 동시 출현 단어 분석:
Co-occurrence analysis
# 기생충 기사 댓글 불러오기library(readr)raw_news_comment <- read_csv("news_comment_parasite.csv")# 전처리library(dplyr)library(stringr)library(textclean)news_comment <- raw_news_comment %>%  select(reply) %>%  mutate(reply = str_replace_all(reply, "[^가-힣]", " "),         reply = str_squish(reply),         id = row_number())SimplePos22() : 문장의 단어를 22개의 품사로 구분library(tidytext)library(KoNLP)comment_pos <- news_comment %>%  unnest_tokens(input = reply,                output = word,                token = SimplePos22,                drop = F)comment_pos %>%  select(reply, word)## # A tibble: 39,956 x 2##    reply                                word      ##    <chr>                                <chr>     ##  1 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 정말/ma   ##  2 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 우리/np   ##  3 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 집/nc+에/jc…##  4 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 좋/pa+은/et…##  5 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 일/nc+이/jc…##  6 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 생기/pv+어/e…##  7 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 기쁘/pa+고/e…##  8 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 행복한/nc ##  9 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 것/nb+처럼/j…## 10 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인… 나/np+의/jc…## # … with 39,946 more rowstidyr::separate_rows():sep  = "[+]": "+"가 등장할 때마다 행을 나눔# 품사별로 행 분리library(tidyr)comment_pos <- comment_pos %>%  separate_rows(word, sep = "[+]")comment_pos %>%  select(word, reply)## # A tibble: 70,553 x 2##    word    reply                                  ##    <chr>   <chr>                                  ##  1 정말/ma 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …##  2 우리/np 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …##  3 집/nc   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …##  4 에/jc   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …##  5 좋/pa   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …##  6 은/et   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …##  7 일/nc   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …##  8 이/jc   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …##  9 생기/pv 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …## 10 어/ec   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 …## # … with 70,543 more rows"/n"이 붙어있는 단어 추출# 명사 추출하기noun <- comment_pos %>%  filter(str_detect(word, "/n")) %>%  mutate(word = str_remove(word, "/.*$"))noun %>%  select(word, reply)## # A tibble: 27,457 x 2##    word   reply                                   ##    <chr>  <chr>                                   ##  1 우리   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…##  2 집     정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…##  3 일     정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…##  4 행복한 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…##  5 것     정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…##  6 나     정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…##  7 일     정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…##  8 양     정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…##  9 행복   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…## 10 행복   정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 양 행…## # … with 27,447 more rows# 명사 빈도 구하기noun %>%  count(word, sort = T)## # A tibble: 8,069 x 2##    word         n##    <chr>    <int>##  1 영화       463##  2 기생충     445##  3 봉준호     372##  4 것         353##  5 아카데미   252##  6 축하       232##  7 나         230##  8 대한민국   226##  9 자랑       222## 10 작품상     218## # … with 8,059 more rows"/pv", 형용사:"/pa" 붙어있는 단어 추출# 동사, 형용사 추출하기pvpa <- comment_pos %>%  filter(str_detect(word, "/pv|/pa")) %>%         # "/pv", "/pa" 추출  mutate(word = str_replace(word, "/.*$", "다"))  # "/"로 시작 문자를 "다"로 바꾸기pvpa %>%  select(word, reply)## # A tibble: 5,317 x 2##    word      reply                                ##    <chr>     <chr>                                ##  1 좋다      정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  2 생기다    정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  3 기쁘다    정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  4 축하드리다… 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  5 기쁘다    정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  6 기쁘다    와 너무 기쁘다 이 시국에 정말 내 일같이 기쁘고 감사하다 축하드…##  7 기쁘다    와 너무 기쁘다 이 시국에 정말 내 일같이 기쁘고 감사하다 축하드…##  8 축하드리다… 와 너무 기쁘다 이 시국에 정말 내 일같이 기쁘고 감사하다 축하드…##  9 불다      우리나라의 영화감독분들 그리고 앞으로 그 꿈을 그리는 분들에게 큰…## 10 크다      우리나라의 영화감독분들 그리고 앞으로 그 꿈을 그리는 분들에게 큰…## # … with 5,307 more rows# 품사 결합comment <- bind_rows(noun, pvpa) %>%  filter(str_count(word) >= 2) %>%  arrange(id)comment %>%  select(word, reply)## # A tibble: 26,860 x 2##    word      reply                                ##    <chr>     <chr>                                ##  1 우리      정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  2 행복한    정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  3 행복      정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  4 행복      정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  5 좋다      정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  6 생기다    정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  7 기쁘다    정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  8 축하드리다… 정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …##  9 기쁘다    정말 우리 집에 좋은 일이 생겨 기쁘고 행복한 것처럼 나의 일인 …## 10 시국      와 너무 기쁘다 이 시국에 정말 내 일같이 기쁘고 감사하다 축하드…## # … with 26,850 more rows명사, 동사, 형용사를 한 번에 추출하기
comment_new <- comment_pos %>%  separate_rows(word, sep = "[+]") %>%  filter(str_detect(word, "/n|/pv|/pa")) %>%  mutate(word = ifelse(str_detect(word, "/pv|/pa"),                       str_replace(word, "/.*$", "다"),                       str_remove(word, "/.*$"))) %>%  filter(str_count(word) >= 2) %>%  arrange(id)widyr::pairwise_count()item: 단어feature: 텍스트 구분 기준sort = T: 빈도가 높은 순으로 출력 결과 정렬install.packages("widyr")library(widyr)pair <- comment %>%  pairwise_count(item = word,                 feature = id,                 sort = T)pair## # A tibble: 245,920 x 3##    item1      item2      n##    <chr>      <chr>  <dbl>##  1 영화       기생충   111##  2 기생충     영화     111##  3 감독       봉준호    86##  4 봉준호     감독      86##  5 감독님     봉준호    66##  6 봉준호     감독님    66##  7 만들다     영화      57##  8 영화       만들다    57##  9 기생충     봉준호    54## 10 블랙리스트 감독      54## # … with 245,910 more rows## # A tibble: 245,920 x 3##    item1      item2      n##    <chr>      <chr>  <dbl>##  1 영화       기생충   111##  2 기생충     영화     111##  3 감독       봉준호    86##  4 봉준호     감독      86##  5 감독님     봉준호    66##  6 봉준호     감독님    66##  7 만들다     영화      57##  8 영화       만들다    57##  9 기생충     봉준호    54## 10 블랙리스트 감독      54## # … with 245,910 more rowspair %>% filter(item1 == "영화")## # A tibble: 2,313 x 3##    item1 item2        n##    <chr> <chr>    <dbl>##  1 영화  기생충     111##  2 영화  만들다      57##  3 영화  봉준호      52##  4 영화  받다        48##  5 영화  한국        46##  6 영화  아카데미    42##  7 영화  같다        41##  8 영화  감독        39##  9 영화  아니다      38## 10 영화  좋다        35## # … with 2,303 more rowspair %>% filter(item1 == "봉준호")## # A tibble: 1,579 x 3##    item1  item2          n##    <chr>  <chr>      <dbl>##  1 봉준호 감독          86##  2 봉준호 감독님        66##  3 봉준호 기생충        54##  4 봉준호 영화          52##  5 봉준호 블랙리스트    48##  6 봉준호 대한민국      38##  7 봉준호 자랑          33##  8 봉준호 축하드리다    30##  9 봉준호 송강호        30## 10 봉준호 축하          25## # … with 1,569 more rows05-2 동시 출현 네트워크:
Co-occurrence network
tidygraph::as_tbl_graph()네트워크가 너무 복잡하지 않도록 25회 이상 사용된 단어 추출해 생성
install.packages("tidygraph")library(tidygraph)graph_comment <- pair %>%  filter(n >= 25) %>%  as_tbl_graph()graph_comment## # A tbl_graph: 30 nodes and 108 edges## ### # A directed simple graph with 2 components## ### # Node Data: 30 x 1 (active)##   name  ##   <chr> ## 1 영화  ## 2 기생충## 3 감독  ## 4 봉준호## 5 감독님## 6 만들다## # … with 24 more rows## ### # Edge Data: 108 x 3##    from    to     n##   <int> <int> <dbl>## 1     1     2   111## 2     2     1   111## 3     3     4    86## # … with 105 more rowsggraph::ggraph()install.packages("ggraph")library(ggraph)ggraph(graph_comment) +  geom_edge_link() +                 # 엣지  geom_node_point() +                # 노드  geom_node_text(aes(label = name))  # 텍스트

그래프를 큰 화면에 출력하는 방법
windows()x11()# 한글 폰트 설정library(showtext)font_add_google(name = "Nanum Gothic", family = "nanumgothic")showtext_auto()ggraph(layout = "fr"): 네트워크 형태 결정set.seed()로 난수 고정set.seed(1234)                              # 난수 고정ggraph(graph_comment, layout = "fr") +      # 레이아웃  geom_edge_link(color = "gray50",          # 엣지 색깔                 alpha = 0.5) +             # 엣지 명암  geom_node_point(color = "lightcoral",     # 노드 색깔                  size = 5) +               # 노드 크기  geom_node_text(aes(label = name),         # 텍스트 표시                 repel = T,                 # 노드밖 표시                 size = 5,                  # 텍스트 크기                 family = "nanumgothic") +  # 폰트  theme_graph()                             # 배경 삭제  노드 텍스트 폰트 geom_node_text()의 family로 별도 설정. theme()으로 적용 안됨.

word_network <- function(x) {  ggraph(x, layout = "fr") +    geom_edge_link(color = "gray50",                   alpha = 0.5) +    geom_node_point(color = "lightcoral",                    size = 5) +    geom_node_text(aes(label = name),                   repel = T,                   size = 5,                   family = "nanumgothic") +    theme_graph()}set.seed(1234)word_network(graph_comment)"감독", "봉감독", "봉준호감독"# 유의어 처리하기comment <- comment %>%  mutate(word = ifelse(str_detect(word, "감독") &                      !str_detect(word, "감독상"), "봉준호", word),         word = ifelse(word == "오르다", "올리다", word),         word = ifelse(str_detect(word, "축하"), "축하", word))# 단어 동시 출현 빈도 구하기pair <- comment %>%  pairwise_count(item = word,                 feature = id,                 sort = T)# 네트워크 그래프 데이터 만들기graph_comment <- pair %>%  filter(n >= 25) %>%  as_tbl_graph()# 네트워크 그래프 만들기set.seed(1234)word_network(graph_comment)



as_tbl_graph()directed = F: 방향성 없도록 설정group_infomap()은 방향성 없는 네트워크 그래프 데이터에서만 커뮤니티를 찾아줌as_tbl_graph()directed = F: 방향성 없도록 설정group_infomap()은 방향성 없는 네트워크 그래프 데이터에서만 커뮤니티를 찾아줌centrality_degree()group_infomap()as.factor(): factor 타입으로 변환해 노드 그룹별로 다른 색으로 표현set.seed(1234)graph_comment <- pair %>%  filter(n >= 25) %>%  as_tbl_graph(directed = F) %>%  mutate(centrality = centrality_degree(),    # 연결 중심성         group = as.factor(group_infomap()))  # 커뮤니티graph_comment## # A tbl_graph: 36 nodes and 152 edges## ### # An undirected multigraph with 1 component## ### # Node Data: 36 x 3 (active)##   name       centrality group##   <chr>           <dbl> <fct>## 1 봉준호             62 4    ## 2 축하               34 2    ## 3 영화               26 3    ## 4 블랙리스트          6 6    ## 5 기생충             26 1    ## 6 대한민국           10 3    ## # … with 30 more rows## ### # Edge Data: 152 x 3##    from    to     n##   <int> <int> <dbl>## 1     1     2   198## 2     1     2   198## 3     1     3   119## # … with 149 more rowsgeom_node_point(aes())size = centrality: 연결 중심성에 따라 노드 크기 설정color = group: 커뮤니티 별로 노드 색깔 다르게geom_node_point(show.legend = F): 범례 제거scale_size(range = c(5, 15)): 노드 크기 5~15 범위 유지set.seed(1234)ggraph(graph_comment, layout = "fr") +      # 레이아웃  geom_edge_link(color = "gray50",          # 엣지 색깔                 alpha = 0.5) +             # 엣지 명암  geom_node_point(aes(size = centrality,    # 노드 크기                      color = group),       # 노드 색깔                  show.legend = F) +        # 범례 삭제  scale_size(range = c(5, 15)) +            # 노드 크기 범위  geom_node_text(aes(label = name),         # 텍스트 표시                 repel = T,                 # 노드밖 표시                 size = 5,                  # 텍스트 크기                 family = "nanumgothic") +  # 폰트  theme_graph()                             # 배경 삭제
graph_comment %>%  filter(name == "봉준호")## # A tbl_graph: 1 nodes and 0 edges## ### # An unrooted tree## ### # Node Data: 1 x 3 (active)##   name   centrality group##   <chr>       <dbl> <fct>## 1 봉준호         62 4    ## ### # Edge Data: 0 x 3## # … with 3 variables: from <int>, to <int>, n <dbl>graph_comment %>%  filter(group == 4) %>%  arrange(-centrality) %>%  data.frame()##     name centrality group## 1 봉준호         62     4## 2   받다         10     4## 3   자랑          6     4## 4 만들다          4     4graph_comment %>%  arrange(-centrality)## # A tbl_graph: 36 nodes and 152 edges## ### # An undirected multigraph with 1 component## ### # Node Data: 36 x 3 (active)##   name     centrality group##   <chr>         <dbl> <fct>## 1 봉준호           62 4    ## 2 축하             34 2    ## 3 영화             26 3    ## 4 기생충           26 1    ## 5 작품상           14 5    ## 6 대한민국         10 3    ## # … with 30 more rows## ### # Edge Data: 152 x 3##    from    to     n##   <int> <int> <dbl>## 1     1     2   198## 2     1     2   198## 3     1     3   119## # … with 149 more rowsgraph_comment %>%  filter(group == 2) %>%  arrange(-centrality) %>%  data.frame()##     name centrality group## 1   축하         34     2## 2   좋다          8     2## 3   진심          4     2## 4   수상          4     2## 5   없다          4     2## 6   대단          2     2## 7 기쁘다          2     2news_comment %>%  filter(str_detect(reply, "봉준호") & str_detect(reply, "대박")) %>%  select(reply)## # A tibble: 19 x 1##    reply                                          ##    <chr>                                          ##  1 대박 대박 진짜 대박 봉준호 감독님과 우리 배우들 너무 다랑스러워요…##  2 내가 죽기전에 아카데미에서 한국어를 들을줄이야 봉준호대박 기생충대박…##  3 대박 관왕이라니 축하합니다 봉준호를 배출한 충무로 그리고 문화강국 대한 민국…##  4 우와 대박 진자 대단하다 봉준호                 ##  5 봉준호 경사났네 대박중에 대에박 축하합니다     ##  6 봉준호 작품상 탔다 대박                        ##  7 봉준호 군대 면제시켜도될듯 대박 여윽시 위대한 한국에는 위대한 봉준호 형님이 계시지…##  8 아니 다른상을 받은것도 충분히 대단하고 굉장하지만 최고의 영예인 작품상을 받은거는 …##  9 봉준호 군대 면제시켜도될듯 대박 여윽시 위대한 한국에는 위대한 봉준호 형님이 계시지…## 10 봉준호감독님대박 축하합니다                    ## # … with 9 more rowsnews_comment %>%  filter(str_detect(reply, "박근혜") & str_detect(reply, "블랙리스트")) %>%  select(reply)## # A tibble: 63 x 1##    reply                                          ##    <chr>                                          ##  1 일베와 자한당이 싫어하는 봉준호 감독이 아카데미에서 상받으니 쪽바리들처럼 엄청 싫어…##  2 박근혜 블랙리스트 로 낙인찍은 봉준호 감독님이 아시아 최초로 오스카에서 상을 받아버…##  3 우리나라에서만 좌파다 빨갱이다 라고 비하함 박근혜 때 이런 세계적 감독을 블랙리스트…##  4 박근혜 최순실 블랙리스트에 오른 훌륭하신 감독님 축하합니다…##  5 박근혜정부가 얼마나 썩고 무능했냐면 각종 영화제에서 최고상 수상을 받는 유능한 감독…##  6 넷상 보수들 만큼 이중적인 새 끼들 없음 봉준호 송강호 보고 종북좌빨 홍어드립 치던…##  7 박근혜 자한당 독재시절 봉준호 송강호를 블랙리스트 올려놓고 활동 방해 감시하면서 괴…##  8 대단합니다 김연아 방탄 봉준호 스포츠 음악 영화 못하는게 없어요 좌빨 감독이라 좌파…##  9 송강호 봉준호 박근혜 이명박 시절 블랙리스트 이제 어떻게 깔려구…## 10 이명박근혜정권당시 좌파감독이라고 블랙리스트까지 올랏던 봉준호 역사적위업을 달성햇네 …## # … with 53 more rowsnews_comment %>%  filter(str_detect(reply, "기생충") & str_detect(reply, "조국")) %>%  select(reply)## # A tibble: 64 x 1##    reply                                          ##    <chr>                                          ##  1 조국이가 받아야 한다 기생충 스토리 제공        ##  2 한번도경험하지 못한 조국가족사기단기생충 개봉박두…##  3 와 조국 가족 사기단 부제 기생충 최고           ##  4 문재인과 조국 기생충 리얼                      ##  5 기생충은 좌좀 조국 가족을 패러디한 영화라서 우파들도 열광하고 있는 것이다 같은 영…##  6 조국 가족이 기생충 영화를 꼭 봐야되는데        ##  7 좌파 인생영화인데 좌파 기생충들에게 이 상을 받쳐라 조국 서울대 문서위조학과 교수님…##  8 기생충 조국 봉준호 만세                        ##  9 봉준호감독님 글로벌 영화계 큰상수상을 진심으로 축하합니다 다만 기생충 작품은 조국 …## 10 기생충보면서 조국생각난사람 나쁜일라나 봉준호 감독님이 현 시대를 참 잘 반영해서 만…## # … with 54 more rows tidygraph 패키지의 연결 중심성 지표, 커뮤니티 탐지 알고리즘: tidygraph.data-imaginist.com
05-3 단어 간 상관 분석:
Phi coefficient
"영화"-"기생충""영화"-"기생충"

 
ϕ=ad−bc√(a+b)(c+d)(a+c)(b+d)
widyr::pairwise_cor()item: 단어feature: 텍스트 구분 기준sort = T: 파이 계수 높은순 정렬word_cors <- comment %>%  add_count(word) %>%  filter(n >= 20) %>%  pairwise_cor(item = word,                feature = id,                sort = T)word_cors  add_count() 원자료에 빈도 나타낸 변수 추가
widyr::pairwise_cor()item: 단어feature: 텍스트 구분 기준sort = T: 파이 계수 높은순 정렬word_cors <- comment %>%  add_count(word) %>%  filter(n >= 20) %>%  pairwise_cor(item = word,                feature = id,                sort = T)word_cors  add_count() 원자료에 빈도 나타낸 변수 추가
## # A tibble: 26,732 x 3##    item1      item2      correlation##    <chr>      <chr>            <dbl>##  1 올리다     블랙리스트       0.478##  2 블랙리스트 올리다           0.478##  3 역사       쓰다             0.370##  4 쓰다       역사             0.370##  5 박근혜     블랙리스트       0.322##  6 블랙리스트 박근혜           0.322##  7 가족       조국             0.306##  8 조국       가족             0.306##  9 작품상     감독상           0.276## 10 감독상     작품상           0.276## # … with 26,722 more rowsword_cors %>%  filter(item1 == "대한민국")## # A tibble: 163 x 3##    item1    item2  correlation##    <chr>    <chr>        <dbl>##  1 대한민국 국민        0.182 ##  2 대한민국 자랑        0.158 ##  3 대한민국 위상        0.149 ##  4 대한민국 국격        0.129 ##  5 대한민국 위대한      0.100 ##  6 대한민국 세계        0.0910##  7 대한민국 문화        0.0757##  8 대한민국 감사합      0.0724##  9 대한민국 나라        0.0715## 10 대한민국 오늘        0.0715## # … with 153 more rowsword_cors %>%  filter(item1 == "역사")## # A tibble: 163 x 3##    item1 item2    correlation##    <chr> <chr>          <dbl>##  1 역사  쓰다          0.370 ##  2 역사  최초          0.117 ##  3 역사  한국          0.0982##  4 역사  순간          0.0910##  5 역사  한국영화      0.0821##  6 역사  아니다        0.0774##  7 역사  감사          0.0654##  8 역사  영광          0.0640##  9 역사  영화제        0.0596## 10 역사  오스카        0.0593## # … with 153 more rows# 관심 단어 목록 생성target <- c("대한민국", "역사", "수상소감", "조국", "박근혜", "블랙리스트")top_cors <- word_cors %>%  filter(item1 %in% target) %>%  group_by(item1) %>%  slice_max(correlation, n = 8)# 그래프 순서 정하기top_cors$item1 <- factor(top_cors$item1, levels = target)library(ggplot2)ggplot(top_cors, aes(x = reorder_within(item2, correlation, item1),                 y = correlation,                 fill = item1)) +  geom_col(show.legend = F) +  facet_wrap(~ item1, scales = "free") +  coord_flip() +  scale_x_reordered() +  labs(x = NULL) +  theme(text = element_text(family = "nanumgothic"))
set.seed(1234)graph_cors <- word_cors %>%  filter(correlation >= 0.15) %>%  as_tbl_graph(directed = F) %>%  mutate(centrality = centrality_degree(),         group = as.factor(group_infomap()))set.seed(1234)ggraph(graph_cors, layout = "fr") +  geom_edge_link(color = "gray50",                 aes(edge_alpha = correlation,   # 엣지 명암                     edge_width = correlation),  # 엣지 두께                 show.legend = F) +              # 범례 삭제  scale_edge_width(range = c(1, 4)) +            # 엣지 두께 범위  geom_node_point(aes(size = centrality,                      color = group),                  show.legend = F) +  scale_size(range = c(5, 10)) +  geom_node_text(aes(label = name),                 repel = T,                 size = 5,                 family = "nanumgothic") +  theme_graph()
05-4
연이어 사용된 단어쌍 분석: n-gram


샘플 텍스트로 엔그램 토큰화해보기
tidytext::unnest_tokens()token = "ngrams"n: 기준 단어 수text <- tibble(value = "대한민국은 민주공화국이다. 대한민국의 주권은 국민에게 있고, 모든 권력은 국민으로부터 나온다.")text## # A tibble: 1 x 1##   value                                                                                       ##   <chr>                                                                                       ## 1 대한민국은 민주공화국이다. 대한민국의 주권은 국민에게 있고, 모든 권력은 국민으로부터 나온다.# 바이그램 토큰화text %>%  unnest_tokens(input = value,                output = word,                token = "ngrams",                n = 2)## # A tibble: 9 x 1##   word                     ##   <chr>                    ## 1 대한민국은 민주공화국이다## 2 민주공화국이다 대한민국의## 3 대한민국의 주권은        ## 4 주권은 국민에게          ## 5 국민에게 있고            ## 6 있고 모든                ## 7 모든 권력은              ## 8 권력은 국민으로부터      ## 9 국민으로부터 나온다# 트라이그램 토큰화text %>%  unnest_tokens(input = value,                output = word,                token = "ngrams",                n = 3)## # A tibble: 8 x 1##   word                                ##   <chr>                               ## 1 대한민국은 민주공화국이다 대한민국의## 2 민주공화국이다 대한민국의 주권은    ## 3 대한민국의 주권은 국민에게          ## 4 주권은 국민에게 있고                ## 5 국민에게 있고 모든                  ## 6 있고 모든 권력은                    ## 7 모든 권력은 국민으로부터            ## 8 권력은 국민으로부터 나온다# 단어 기준 토큰화text %>%  unnest_tokens(input = value,                output = word,                token = "words")## # A tibble: 10 x 1##    word          ##    <chr>         ##  1 대한민국은    ##  2 민주공화국이다##  3 대한민국의    ##  4 주권은        ##  5 국민에게      ##  6 있고          ##  7 모든          ##  8 권력은        ##  9 국민으로부터  ## 10 나온다# 유니그램 토큰화text %>%  unnest_tokens(input = value,                output = word,                token = "ngrams",                n = 1)## # A tibble: 10 x 1##    word          ##    <chr>         ##  1 대한민국은    ##  2 민주공화국이다##  3 대한민국의    ##  4 주권은        ##  5 국민에게      ##  6 있고          ##  7 모든          ##  8 권력은        ##  9 국민으로부터  ## 10 나온다comment_pos 이용: 댓글을 형태소로 토큰화 후 품사별로 행 분리comment_new <- comment_pos %>%  separate_rows(word, sep = "[+]") %>%  filter(str_detect(word, "/n|/pv|/pa")) %>%  mutate(word = ifelse(str_detect(word, "/pv|/pa"),                       str_replace(word, "/.*$", "다"),                       str_remove(word, "/.*$"))) %>%  filter(str_count(word) >= 2) %>%  arrange(id)바이그램으로 토큰화할 때는 형태소 추출 먼저
comment_new <- comment_new %>%  mutate(word = ifelse(str_detect(word, "감독") &                      !str_detect(word, "감독상"), "봉준호", word),         word = ifelse(word  == "오르다", "올리다", word),         word = ifelse(str_detect(word, "축하"), "축하", word))comment_new %>%  select(word)## # A tibble: 26,860 x 1##    word  ##    <chr> ##  1 우리  ##  2 좋다  ##  3 생기다##  4 기쁘다##  5 행복한##  6 행복  ##  7 축하  ##  8 행복  ##  9 기쁘다## 10 기쁘다## # … with 26,850 more rowsline_comment <- comment_new %>%  group_by(id) %>%  summarise(sentence = paste(word, collapse = " "))line_comment## # A tibble: 4,007 x 2##       id sentence                                                               ##  * <int> <chr>                                                                  ##  1     1 우리 좋다 생기다 기쁘다 행복한 행복 축하 행복 기쁘다                   ##  2     2 기쁘다 시국 기쁘다 감사하다 축하 진심                                  ##  3     3 우리나라 봉준호 불다 크다 영감 봉준호 공동각본쓴 한진 작가님 축하 축하 드리다…##  4     4 봉준호 봉준호 우리나라 대한민국 자랑 세계 어디 우리 한국인 힘내다 삽시 ##  5     5 노벨상 탄느낌이네요 축하                                               ##  6     6 기생충 받다 박수 치다 감독상 기대다 봉준호 봉준호                      ##  7     7 대한민국 영화사 쓰다 계시다                                            ##  8     8 아카데미상 받다 태극기 휘날리다 광해 명량 전부문 휩쓸어야겠            ##  9     9 다시한번 보이다 영화관                                                 ## 10    10 대한민국 봉준호 대단 한국의 문화 자긍심 가지                           ## # … with 3,997 more rowsbigram_comment <- line_comment %>%  unnest_tokens(input = sentence,                output = bigram,                token = "ngrams",                n = 2)bigram_comment## # A tibble: 23,348 x 2##       id bigram       ##    <int> <chr>        ##  1     1 우리 좋다    ##  2     1 좋다 생기다  ##  3     1 생기다 기쁘다##  4     1 기쁘다 행복한##  5     1 행복한 행복  ##  6     1 행복 축하    ##  7     1 축하 행복    ##  8     1 행복 기쁘다  ##  9     2 기쁘다 시국  ## 10     2 시국 기쁘다  ## # … with 23,338 more rows# 바이그램 분리하기bigram_seprated <- bigram_comment %>%  separate(bigram, c("word1", "word2"), sep = " ")bigram_seprated## # A tibble: 23,348 x 3##       id word1  word2 ##    <int> <chr>  <chr> ##  1     1 우리   좋다  ##  2     1 좋다   생기다##  3     1 생기다 기쁘다##  4     1 기쁘다 행복한##  5     1 행복한 행복  ##  6     1 행복   축하  ##  7     1 축하   행복  ##  8     1 행복   기쁘다##  9     2 기쁘다 시국  ## 10     2 시국   기쁘다## # … with 23,338 more rows# 단어쌍 빈도 구하기pair_bigram <- bigram_seprated %>%  count(word1, word2, sort = T) %>%  na.omit()pair_bigram## # A tibble: 19,030 x 3##    word1      word2          n##    <chr>      <chr>      <int>##  1 봉준호     봉준호       155##  2 블랙리스트 올리다        64##  3 진심       축하          64##  4 봉준호     축하          57##  5 봉준호     송강호        34##  6 영화       만들다        31##  7 축하       봉준호        31##  8 대단       축하          27##  9 봉준호     블랙리스트    27## 10 대박       축하          26## # … with 19,020 more rows na.omit(): 결측치 행 제거: 한 단어로 된 문장은 바이그램으로 토큰화하면 NA가 됨 
    ex) '축하합니다', '멋집니다'
# 동시 출현 단어쌍pair %>%  filter(item1 == "대한민국")## # A tibble: 1,010 x 3##    item1    item2        n##    <chr>    <chr>    <dbl>##  1 대한민국 봉준호      70##  2 대한민국 축하        54##  3 대한민국 자랑        44##  4 대한민국 영화        30##  5 대한민국 기생충      27##  6 대한민국 국민        22##  7 대한민국 세계        16##  8 대한민국 아카데미    16##  9 대한민국 위상        15## 10 대한민국 좋다        14## # … with 1,000 more rows# 바이그램 단어쌍pair_bigram %>%  filter(word1 == "대한민국")## # A tibble: 109 x 3##    word1    word2      n##    <chr>    <chr>  <int>##  1 대한민국 국민      21##  2 대한민국 자랑      15##  3 대한민국 영화      11##  4 대한민국 국격       8##  5 대한민국 위상       7##  6 대한민국 만세       6##  7 대한민국 봉준호     5##  8 대한민국 문화       4##  9 대한민국 영광       4## 10 대한민국 기생충     3## # … with 99 more rows# 네트워크 그래프 데이터 만들기graph_bigram <- pair_bigram %>%  filter(n >= 8) %>%  as_tbl_graph()# 네트워크 그래프 만들기set.seed(1234)word_network(graph_bigram)

bigram_seprated의 유의어 통일, 같은 단어 연속 단어쌍 제거# 유의어 처리bigram_seprated <- bigram_seprated %>%  mutate(word1 = ifelse(str_detect(word1, "대단"), "대단", word1),         word2 = ifelse(str_detect(word2, "대단"), "대단", word2),         word1 = ifelse(str_detect(word1, "자랑"), "자랑", word1),         word2 = ifelse(str_detect(word2, "자랑"), "자랑", word2),         word1 = ifelse(str_detect(word1, "짝짝짝"), "짝짝짝", word1),         word2 = ifelse(str_detect(word2, "짝짝짝"), "짝짝짝", word2)) %>%  # 같은 단어 연속 제거  filter(word1 != word2)# 단어쌍 빈도 구하기pair_bigram <- bigram_seprated %>%  count(word1, word2, sort = T) %>%  na.omit()# 네트워크 그래프 데이터 만들기set.seed(1234)graph_bigram <- pair_bigram %>%  filter(n >= 8) %>%  as_tbl_graph(directed = F) %>%  mutate(centrality = centrality_degree(),    # 중심성         group = as.factor(group_infomap()))  # 커뮤니티# 네트워크 그래프 만들기set.seed(1234)ggraph(graph_bigram, layout = "fr") +         # 레이아웃  geom_edge_link(color = "gray50",            # 엣지 색깔                 alpha = 0.5) +               # 엣지 명암  geom_node_point(aes(size = centrality,      # 노드 크기                      color = group),         # 노드 색깔                  show.legend = F) +          # 범례 삭제  scale_size(range = c(4, 8)) +               # 노드 크기 범위  geom_node_text(aes(label = name),           # 텍스트 표시                 repel = T,                   # 노드밖 표시                 size = 5,                    # 텍스트 크기                 family = "nanumgothic") +    # 폰트  theme_graph()                               # 배경 삭제

 
 




정리하기
# 품사 기준 토큰화comment_pos <- news_comment %>%  unnest_tokens(input = reply,                output = word,                token = SimplePos22,                drop = F)# 명사, 동사, 형용사 추출comment <- comment_pos %>%  separate_rows(word, sep = "[+]") %>%  filter(str_detect(word, "/n|/pv|/pa")) %>%  mutate(word = ifelse(str_detect(word, "/pv|/pa"),                       str_replace(word, "/.*$", "다"),                       str_remove(word, "/.*$"))) %>%  filter(str_count(word) >= 2) %>%  arrange(id)# 단어 동시 출현 빈도 구하기pair <- comment %>%  pairwise_count(item = word,                 feature = id,                 sort = T)# 파이 계수 구하기word_cors <- comment %>%  add_count(word) %>%  filter(n >= 20) %>%  pairwise_cor(item = word,               feature = id,               sort = T)# 텍스트를 한 행으로 구성line_comment <- comment %>%  group_by(id) %>%  summarise(sentence = paste(word, collapse = " "))# 바이그램 토큰화bigram_comment <- line_comment %>%  unnest_tokens(input = sentence,                output = bigram,                token = "ngrams",                n = 2)# 바이그램 분리bigram_seprated <- bigram_comment %>%  separate(bigram, c("word1", "word2"), sep = " ")# 단어쌍 빈도 구하기pair_bigram <- bigram_seprated %>%  count(word1, word2, sort = T) %>%  na.omit()# 네트워크 그래프 데이터 만들기set.seed(1234)graph_comment <- pair_bigram %>%  filter(n >= 8) %>%  as_tbl_graph(directed = F) %>%  mutate(centrality = centrality_degree(),         group = as.factor(group_infomap()))# 네트워크 그래프 만들기set.seed(1234)ggraph(graph_comment) +  geom_edge_link() +  geom_node_point(aes(size = centrality,                      color = group)) +  geom_node_text(aes(label = name))"news_comment_BTS.csv"에는 2020년 9월 21일 방탄소년단이 '빌보드 핫 100 차트' 1위에 오른 소식을 다룬 기사에 달린 댓글이 들어있습니다. "news_comment_BTS.csv"를 이용해 문제를 해결해 보세요.
Q1. "news_comment_BTS.csv"를 불러온 다음 행 번호를 나타낸 변수를 추가하고 분석에 적합하게
       전처리하세요.
Q2. 댓글에서 명사, 동사, 형용사를 추출하고 '/로 시작하는 모든 문자'를 '다'로 바꾸세요.
Q3. 다음 코드를 이용해 유의어를 통일한 다음 한 댓글이 하나의 행이 되도록 단어를 결합하세요.
# 유의어 통일하기comment <- comment %>%  mutate(word = case_when(str_detect(word, "축하") ~ "축하",                          str_detect(word, "방탄") ~ "자랑",                          str_detect(word, "대단") ~ "대단",                          str_detect(word, "자랑") ~ "자랑",                          T ~ word))"news_comment_BTS.csv"에는 2020년 9월 21일 방탄소년단이 '빌보드 핫 100 차트' 1위에 오른 소식을 다룬 기사에 달린 댓글이 들어있습니다. "news_comment_BTS.csv"를 이용해 문제를 해결해 보세요.
"fr"로 설정하세요.Q1. "news_comment_BTS.csv"를 불러온 다음 행 번호를 나타낸 변수를 추가하고 분석에 적합하게
       전처리하세요.
library(readr)library(dplyr)raw_news_comment <- read_csv("news_comment_BTS.csv")glimpse(raw_news_comment)## Rows: 1,200## Columns: 5## $ reg_time <dttm> 2020-09-01 22:58:09, 2020-09-01 09:56:46…## $ reply    <chr> "국보소년단<U+0001F49C>", "아줌마가 들어도 좋더라", "팩트체…## $ press    <chr> "한국경제", "한국경제", "한국경제", "한국경제", "한국경제", "…## $ title    <chr> "[속보]BTS '다이너마이트', 한국 가수 최초로 빌보드 싱글 1위", …## $ url      <chr> "https://news.naver.com/main/read.nhn?mod…library(stringr)library(textclean)news_comment <- raw_news_comment %>%  select(reply) %>%  mutate(id = row_number(),         reply = str_replace_all(reply, "[^가-힣]", " "),         reply = str_squish(reply))news_comment %>%  select(id, reply)## # A tibble: 1,200 x 2##       id reply                                    ##    <int> <chr>                                    ##  1     1 국보소년단                               ##  2     2 아줌마가 들어도 좋더라                   ##  3     3 팩트체크 현재 빌보드 위 방탄소년단 위 위 위 위 위 위 위 위 위…##  4     4 방탄소년단이 한국사람이라 너무 자랑스러워요 우리오래오래 함께하자…##  5     5 대단한 월드 클래스는 다르네 좋은 소식 응원해요…##  6     6 정국오빠 생일과 더불어 빌보드 위기사라니 축제구나…##  7     7 정말 축하하고 응원하지만 집에서 여러 계정으로 스트리밍 돌리고 사재기하고…##  8     8 기자는 자고 일어났지만 팬들은 못자고 발표 기다림…##  9     9 자랑스럽다 축하합니다                    ## 10    10 늘 응원하고 사랑합니다                   ## # … with 1,190 more rowsQ2. 댓글에서 명사, 동사, 형용사를 추출하고 '/로 시작하는 모든 문자'를 '다'로 바꾸세요.
# 품사 기준 토큰화library(tidytext)library(KoNLP)comment_pos <- news_comment %>%  unnest_tokens(input = reply,                output = word,                token = SimplePos22,                drop = F)# 한 행이 한 품사를 구성하도록 분리library(tidyr)comment_pos <- comment_pos %>%  separate_rows(word, sep = "[+]")comment_pos %>%  select(word, reply)## # A tibble: 20,851 x 2##    word        reply                 ##    <chr>       <chr>                 ##  1 국보소년/nc 국보소년단            ##  2 단/ma       국보소년단            ##  3 아줌마/nc   아줌마가 들어도 좋더라##  4 가/jc       아줌마가 들어도 좋더라##  5 들/pv       아줌마가 들어도 좋더라##  6 어도/ec     아줌마가 들어도 좋더라##  7 좋/pa       아줌마가 들어도 좋더라##  8 더/ep       아줌마가 들어도 좋더라##  9 어/ec       아줌마가 들어도 좋더라## 10 라/nc       아줌마가 들어도 좋더라## # … with 20,841 more rows# 명사, 동사, 형용사 추출comment <- comment_pos %>%  separate_rows(word, sep = "[+]") %>%  filter(str_detect(word, "/n|/pv|/pa")) %>%  mutate(word = ifelse(str_detect(word, "/pv|/pa"),                       str_replace(word, "/.*$", "다"),                       str_remove(word, "/.*$"))) %>%  filter(str_count(word) >= 2) %>%  arrange(id)comment %>%  select(word, reply)## # A tibble: 7,539 x 2##    word      reply                                ##    <chr>     <chr>                                ##  1 국보소년  국보소년단                           ##  2 아줌마    아줌마가 들어도 좋더라               ##  3 들다      아줌마가 들어도 좋더라               ##  4 좋다      아줌마가 들어도 좋더라               ##  5 팩트체크  팩트체크 현재 빌보드 위 방탄소년단 위 위 위 위 위 위 위 위 …##  6 빌보드    팩트체크 현재 빌보드 위 방탄소년단 위 위 위 위 위 위 위 위 …##  7 방탄소년단… 팩트체크 현재 빌보드 위 방탄소년단 위 위 위 위 위 위 위 위 …##  8 방탄소년단… 방탄소년단이 한국사람이라 너무 자랑스러워요 우리오래오래 함께하자…##  9 한국사람  방탄소년단이 한국사람이라 너무 자랑스러워요 우리오래오래 함께하자…## 10 자랑      방탄소년단이 한국사람이라 너무 자랑스러워요 우리오래오래 함께하자…## # … with 7,529 more rowsQ3. 다음 코드를 이용해 유의어를 통일한 다음 한 댓글이 하나의 행이 되도록 단어를 결합하세요.
# 유의어 통일하기comment <- comment %>%  mutate(word = case_when(str_detect(word, "축하") ~ "축하",                          str_detect(word, "방탄") ~ "자랑",                          str_detect(word, "대단") ~ "대단",                          str_detect(word, "자랑") ~ "자랑",                          T ~ word))# 단어를 댓글별 한 행으로 결합line_comment <- comment %>%  group_by(id) %>%  summarise(sentence = paste(word, collapse = " "))line_comment## # A tibble: 1,155 x 2##       id sentence                                 ##  * <int> <chr>                                    ##  1     1 국보소년                                 ##  2     2 아줌마 들다 좋다                         ##  3     3 팩트체크 빌보드 자랑                     ##  4     4 자랑 한국사람 자랑 우리오래오래 함께하다 ##  5     5 대단 월드 클래스 다르다 좋다 소식 응원해 ##  6     6 정국오빠 생일 더불다 빌보드 위기사 축제구##  7     7 축하 응원하지 계정 스트리밍 돌리다 사재기 팬덤 테러하 개념보고 놀라다…##  8     8 기자 자다 일어나다 패다 못자 발표        ##  9     9 자랑 축하                                ## 10    10 응원 사랑합                              ## # … with 1,145 more rowsQ4. 댓글을 바이그램으로 토큰화한 다음 바이그램 단어쌍을 분리하세요.
# 바이그램 토큰화bigram_comment <- line_comment %>%  unnest_tokens(input = sentence,                output = bigram,                token = "ngrams",                n = 2)bigram_comment## # A tibble: 6,541 x 2##       id bigram               ##    <int> <chr>                ##  1     1 <NA>                 ##  2     2 아줌마 들다          ##  3     2 들다 좋다            ##  4     3 팩트체크 빌보드      ##  5     3 빌보드 자랑          ##  6     4 자랑 한국사람        ##  7     4 한국사람 자랑        ##  8     4 자랑 우리오래오래    ##  9     4 우리오래오래 함께하다## 10     5 대단 월드            ## # … with 6,531 more rows# 바이그램 단어쌍 분리bigram_seprated <- bigram_comment %>%  separate(bigram, c("word1", "word2"), sep = " ")bigram_seprated## # A tibble: 6,541 x 3##       id word1        word2       ##    <int> <chr>        <chr>       ##  1     1 <NA>         <NA>        ##  2     2 아줌마       들다        ##  3     2 들다         좋다        ##  4     3 팩트체크     빌보드      ##  5     3 빌보드       자랑        ##  6     4 자랑         한국사람    ##  7     4 한국사람     자랑        ##  8     4 자랑         우리오래오래##  9     4 우리오래오래 함께하다    ## 10     5 대단         월드        ## # … with 6,531 more rows# 단어쌍 빈도 구하기pair_bigram <- bigram_seprated %>%  count(word1, word2, sort = T) %>%  na.omit()pair_bigram## # A tibble: 5,455 x 3##    word1  word2     n##    <chr>  <chr> <int>##  1 축하   하다     43##  2 자랑   축하     40##  3 자랑   자랑     38##  4 축하   자랑     35##  5 대단   자랑     24##  6 진짜   자랑     24##  7 진짜   대단     23##  8 자랑   진짜     17##  9 빌보드 축하     14## 10 군대   면제     13## # … with 5,445 more rows# 네트워크 그래프 데이터 만들기library(tidygraph)set.seed(1234)graph_bigram <- pair_bigram %>%  filter(n >= 3) %>%  as_tbl_graph(directed = F) %>%  mutate(centrality = centrality_degree(),         group = as.factor(group_infomap()))graph_bigram## # A tbl_graph: 90 nodes and 130 edges## ### # An undirected multigraph with 6 components## ### # Node Data: 90 x 3 (active)##   name   centrality group##   <chr>       <dbl> <fct>## 1 축하           18 1    ## 2 자랑           45 1    ## 3 대단            9 1    ## 4 진짜           12 1    ## 5 빌보드         16 2    ## 6 군대            3 4    ## # … with 84 more rows## ### # Edge Data: 130 x 3##    from    to     n##   <int> <int> <int>## 1     1    61    43## 2     1     2    40## 3     2     2    38## # … with 127 more rows"fr"로 설정하세요.library(ggraph)set.seed(1234)ggraph(graph_bigram, layout = "fr") +  geom_edge_link() +  geom_node_point(aes(size = centrality,                      color = group),                  show.legend = F) +  geom_node_text(aes(label = name),                 repel = T,                 size = 5) +  theme_graph()
# 그래프 꾸미기library(showtext)font_add_google(name = "Nanum Gothic", family = "nanumgothic")set.seed(1234)ggraph(graph_bigram, layout = "fr") +         # 레이아웃  geom_edge_link(color = "gray50",            # 엣지 색깔                 alpha = 0.5) +               # 엣지 명암  geom_node_point(aes(size = centrality,      # 노드 크기                      color = group),         # 노드 색깔                  show.legend = F) +          # 범례 삭제  scale_size(range = c(4, 8)) +               # 노드 크기 범위  geom_node_text(aes(label = name),           # 텍스트 표시                 repel = T,                   # 노드밖 표시                 size = 5,                    # 텍스트 크기                 family = "nanumgothic") +    # 폰트  theme_graph()                               # 배경 삭제
끝