단어의 의미는 문장에 함께 사용된 단어에 따라 달라집니다. 단어의 빈도를 분석하면 중요한 단어가 무엇인지는 알 수 있지만, 단어가 어떤 맥락에서 사용됐는지는 알 수 없습니다. 텍스트의 맥락을 이해하려면 단어의 관계를 이용해 의미망(semantic network)을 만들고 단어들이 어떻게 연결되는지 살펴봐야 합니다. 이번 수업에서는 의미망을 이용해 단어들의 관계를 분석해 그 의미를 포착하는 방법을 알아봅니다.
‘손-장갑’, ‘머리-모자’ 처럼 관계가 깊은 단어들이 있습니다. 이와 같은 단어 간의 관계를 살펴보는 분석 방법을 동시 출현 단어 분석(공기어 분석; co-occurrence analysis)이라고 합니다. 동시 출현 단어를 이용해 텍스트에 어떤 단어가 함께 사용되었는지 살펴보고 네트워크 그래프를 만드는 방법을 알아보겠습니다.
코로나 백신 관련 기사의 헤드라인에서 AZ와 화이자에 대한 동시 출현 단어 분석
library(tidyverse)
## -- Attaching packages --------------------------------------- tidyverse 1.3.0 --
## v ggplot2 3.3.3 v purrr 0.3.4
## v tibble 3.1.0 v dplyr 1.0.4
## v tidyr 1.1.2 v stringr 1.4.0
## v readr 1.3.1 v forcats 0.5.1
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
library(readxl)
library(lubridate)
##
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
##
## date, intersect, setdiff, union
cv <- read_excel("bigkinds_corona_vaccine.xlsx", sheet = 1)
View(cv)
cv_hls_type <- cv %>%
select(DATE, COMPANY, HEADLINE, FEATURE) %>%
filter(!duplicated(HEADLINE)) %>%
mutate(DATE = ymd(DATE)) %>%
mutate(HEADLINE = str_remove_all(HEADLINE, "^\\[[[:print:]]+\\]|^\\<[[:print:]]+\\>|^\\([[:print:]]+\\)")) %>%
filter(str_detect(HEADLINE, "아스트라|AZ|화이자")) %>%
mutate(type = ifelse(str_detect(HEADLINE, "AZ|아스트라"),
"AZ", "Pfizer"))
cv_hls_type
## # A tibble: 1,006 x 5
## DATE COMPANY HEADLINE FEATURE type
## <date> <chr> <chr> <chr> <chr>
## 1 2021-03-22 중부일보 " 고령층에도 본격화된 AZ 백신 접종"~ az,유럽,고령층,코로나,65세,불안감,코로~ AZ
## 2 2021-03-22 중앙일보 "AZ \"코로나백신, 美 임상서 효과 79~ 아스트라제네카,미국,코로나19,임상시험,고령~ AZ
## 3 2021-03-22 중앙일보 "\"AZ 접종 후 희귀 혈전 발생 20대 ~ 혈전증,az,서은숙,코로나19,정맥동,대응요~ AZ
## 4 2021-03-22 세계일보 "예방접종위 “AZ 백신과 혈전 연관성 없어~ az,예방접종위,접종위,아스트라제네카,뉴시스~ AZ
## 5 2021-03-22 조선일보 "文, 아스트라 접종 하루 전날 “백신 가짜~ 아스트라제네카,부동산,일자리,정상회의,경계심~ AZ
## 6 2021-03-22 조선일보 " 예방접종위 “아스트라, 혈전과 연관 없어~ 아스트라제네카,혈전증,코로나,예방접종위,접종~ AZ
## 7 2021-03-22 동아일보 "예방접종위 “AZ 백신과 혈전 연관성 없다~ 아스트라제네카,전문위,예방접종전문위,코로나,~ AZ
## 8 2021-03-22 세계일보 "AZ 백신 신뢰 회복하고 대상자 불안감 해~ az,대상자,종사자,요양병원,전문가,불안감,~ AZ
## 9 2021-03-22 조선일보 "존슨 英총리 “저도 아스트라 백신 맞았어요~ 존슨,아스트라제네카,유럽,주요국,이탈리아,정~ AZ
## 10 2021-03-22 동아일보 "같은 75세 이상인데 요양병원 환자는 AZ~ 아스트라제네카,요양병원,75세,종사자,고령층~ AZ
## # ... with 996 more rows
빅카인즈에서 수집한 뉴스기사에 의미망 분석을 적용하기 위해 각 기사의 주요 어휘만을 추출해 정리해 놓은 특성(FEATURE)을 토큰화하여 분석해봅시다 .
library(tidytext)
library(RcppMeCab)
cv_feature <- cv_hls_type %>%
select(FEATURE, type) %>%
rowid_to_column() %>%
unnest_tokens(input = FEATURE,
output = word,
token = "regex",
pattern = ",")
cv_feature
## # A tibble: 19,502 x 3
## rowid type word
## <int> <chr> <chr>
## 1 1 AZ az
## 2 1 AZ 유럽
## 3 1 AZ 고령층
## 4 1 AZ 코로나
## 5 1 AZ 65세
## 6 1 AZ 불안감
## 7 1 AZ 코로나19
## 8 1 AZ 그간
## 9 1 AZ 접종일
## 10 1 AZ 전문가
## # ... with 19,492 more rows
pairwise_count()
토큰화한 텍스트를 이용해 단어의 동시 출현 빈도를 구하겠습니다. widyr
패키지의 pairwise_count()
를 이용하면 동시 출현 빈도를 구할 수 있습니다. pairwise_count()
에는 다음과 같은 파라미터를 입력합니다.
item
: 단어. 여기서는 word
를 입력합니다.feature
: 텍스트 구분 기준. 여기서는 rowid
를 입력합니다.sort=T
: 빈도가 높은 순으로 출력 결과를 정렬합니다.pairwise_count()
는 한 단어를 기준으로 함께 사용된 모든 단어의 빈도를 구하기 때문에 출력 결과가 “코로나-백신”, “백신-코로나”와 같이 순서를 바꿔가며 같은 빈도를 지니는 두개의 행으로 구성되는 특징이 있습니다.
#install.packages("widyr")
library(widyr)
pair <- cv_feature %>%
pairwise_count(item = word,
feature = rowid,
sort = T)
## Warning: `distinct_()` was deprecated in dplyr 0.7.0.
## Please use `distinct()` instead.
## See vignette('programming') for more help
## Warning: `tbl_df()` was deprecated in dplyr 1.0.0.
## Please use `tibble::as_tibble()` instead.
pair
## # A tibble: 238,324 x 3
## item1 item2 n
## <chr> <chr> <dbl>
## 1 코로나19 코로나 368
## 2 코로나 코로나19 368
## 3 아스트라제네카 코로나 337
## 4 코로나 아스트라제네카 337
## 5 화이자 미국 294
## 6 미국 화이자 294
## 7 화이자 코로나 293
## 8 코로나 화이자 293
## 9 아스트라제네카 코로나19 282
## 10 코로나19 아스트라제네카 282
## # ... with 238,314 more rows
filter()
를 이용하면 특정 단어와 같은 헤드라인에서 자주 함께 등장하는 단어가 무엇인지 알 수 있습니다.
pair %>% filter(item1 == "화이자")
## # A tibble: 2,178 x 3
## item1 item2 n
## <chr> <chr> <dbl>
## 1 화이자 미국 294
## 2 화이자 코로나 293
## 3 화이자 코로나19 270
## 4 화이자 제약사 153
## 5 화이자 바이오엔테크 139
## 6 화이자 영국 138
## 7 화이자 아스트라제네카 128
## 8 화이자 독일 99
## 9 화이자 코로나바이러스 89
## 10 화이자 모더 86
## # ... with 2,168 more rows
pair %>% filter(item1 == "아스트라제네카")
## # A tibble: 2,544 x 3
## item1 item2 n
## <chr> <chr> <dbl>
## 1 아스트라제네카 코로나 337
## 2 아스트라제네카 코로나19 282
## 3 아스트라제네카 영국 188
## 4 아스트라제네카 미국 130
## 5 아스트라제네카 화이자 128
## 6 아스트라제네카 65세 120
## 7 아스트라제네카 제약사 94
## 8 아스트라제네카 유럽 85
## 9 아스트라제네카 종사자 73
## 10 아스트라제네카 코로나바이러스 72
## # ... with 2,534 more rows
토큰 “코로나”와 “코로나19” 같이 같은 의미의 단어가 개별 노드로 되어 있어 해석이 복잡해지는 문제를 수정해 보겠습니다. 표현은 다르지만 의미가 비슷한 단어를 유의어(synonym)라 합니다. 유의어를 한 단어로 통일하면 네트워크 구조가 간결해지고 단어의 관계가 좀 더 분명하게 드러납니다. cv_feature
에서 토큰을 수정하고 pair
에서 유의어를 통일한 다음 네트워크 그래프 데이터를 만들겠습니다.
# 토큰 오류 수정 및 유의어 처리
cv_feature <- cv_feature %>%
mutate(word = ifelse(word=="코로나", "코로나19", word),
word = ifelse(word=="아스트라", "아스트라제네카", word),
word = ifelse(word=="모더", "모더나", word)) %>%
filter(word != "제네") %>%
mutate(word = ifelse(word == "아스트라제네카", "az", word))
cv_feature %>% count(word, sort=T)
## # A tibble: 4,160 x 2
## word n
## <chr> <int>
## 1 코로나19 1293
## 2 az 668
## 3 미국 428
## 4 화이자 416
## 5 영국 297
## 6 제약사 219
## 7 모더나 207
## 8 코로나바이러스 162
## 9 독일 156
## 10 백신 156
## # ... with 4,150 more rows
cv_feature <- cv_feature %>%
mutate(word = ifelse(word=="코로나바이러스", "코로나19", word),
word = ifelse(word=="우리나라", "한국", word)) %>%
filter(word != "만큼")
cv_feature %>% count(word, sort=T)
## # A tibble: 4,157 x 2
## word n
## <chr> <int>
## 1 코로나19 1455
## 2 az 668
## 3 미국 428
## 4 화이자 416
## 5 영국 297
## 6 제약사 219
## 7 모더나 207
## 8 독일 156
## 9 백신 156
## 10 65세 154
## # ... with 4,147 more rows
# 단어 동시 출현 빈도 구하기
pair <- cv_feature %>%
pairwise_count(item = word,
feature = rowid,
sort = T)
pair
## # A tibble: 225,996 x 3
## item1 item2 n
## <chr> <chr> <dbl>
## 1 코로나19 az 498
## 2 az 코로나19 498
## 3 미국 코로나19 404
## 4 코로나19 미국 404
## 5 화이자 코로나19 399
## 6 코로나19 화이자 399
## 7 화이자 미국 294
## 8 미국 화이자 294
## 9 영국 코로나19 269
## 10 코로나19 영국 269
## # ... with 225,986 more rows
동시 출현 빈도를 이용해 단어의 관계를 네트워크 형태로 표현한 것을 __동시 출현 네트워크(co-occurrence network)__라고 합니다. 동시 출현 네트워크를 이용하면 단어들이 어떤 맥락에서 함께 사용되었는지 이해할 수 있습니다.
as_tbl_graph()
동시 출현 네트워크를 만들려면 동시 출현 빈도 데이터를 ’네트워크 그래프 데이터’로 변환해야 합니다. tidygraph
패키지의 as_tbl_graph()
함수를 이용하면 네트워크 그래프 데이터를 만들 수 있습니다. 네트워크가 너무 복잡하지 않도록 pair
에서 50회 이상 등장한 단어만 추출해 네트워크 그래프 데이터를 만들어 보겠습니다. graph_pair
를 출력하면 단어를 나타내는 노드(node, 꼭짓점) 38개와 단어를 연결하는 엣지(edge, 선) 206개로 구성되어있음을 알 수 있습니다. 그래프를 만들 때 이 값들을 활용합니다.
#install.packages("tidygraph")
library(tidygraph)
##
## Attaching package: 'tidygraph'
## The following object is masked from 'package:stats':
##
## filter
graph_pair <- pair %>%
filter(n >= 50) %>%
as_tbl_graph()
graph_pair
## # A tbl_graph: 38 nodes and 206 edges
## #
## # A directed simple graph with 1 component
## #
## # Node Data: 38 x 1 (active)
## name
## <chr>
## 1 코로나19
## 2 az
## 3 미국
## 4 화이자
## 5 영국
## 6 제약사
## # ... with 32 more rows
## #
## # Edge Data: 206 x 3
## from to n
## <int> <int> <dbl>
## 1 1 2 498
## 2 2 1 498
## 3 3 1 404
## # ... with 203 more rows
ggraph()
ggraph
패키지의 ggraph()
를 이용하면 네트워크 그래프를 만들 수 있습니다.
ggraph()
에 graph_pair
를 입력한 다음 geom_edge_link()
를 추가해 단어를 엣지로 연결합니다.geom_node_point()
를 추가해 단어를 노드로 구성합니다.geom_node_text()
에 aes(label = name)
을 입력해 노드에 단어를 표시합니다.함수의 파라미터를 사용해 엣지와 노드의 색깔, 크기, 텍스트 위치 등을 수정합니다. ggraph()
의 layout
은 네트워크의 형태를 정하는 기능을 합니다. layout
을 정하면 난수를 이용해 매번 다른 모양의 그래프를 만드므로 set.seed()
로 난수를 고정해 항상 같은 모양의 그래프를 만들도록 합니다.
#install.packages("ggraph")
library(ggraph)
library(showtext)
## Warning: package 'showtext' was built under R version 4.0.5
## Loading required package: sysfonts
## Warning: package 'sysfonts' was built under R version 4.0.5
## Loading required package: showtextdb
## Warning: package 'showtextdb' was built under R version 4.0.5
font_add_google(name = "Nanum Gothic",
family = "nanumgothic")
showtext_auto()
set.seed(210531) # 오늘 날짜와 같은 임의의 숫자 조합으로 난수 고정
ggraph(graph_pair, 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() # 배경 삭제
네트워크 그래프는 수많은 단어를 노드로 표현하기 때문에 어떤 단어를 중심으로 해석해야 할지 판단하기 어렵습니다. 그래프에 연결 중심성과 커뮤니티를 표현하면 단어의 관계를 더 분명하게 파악할 수 있습니다.
연결 중심성(degree centrality)은 _노드가 다른 노드들과 얼마나 밀접하게 연결되어 있는지 나타내는 값_입니다. 연결 중심성으로 노드 크기를 조정하면 어떤 단어를 눈여겨봐야 할지 판단하기 쉬워집니다.
연결 중심성을 나타낸 그래프(다른 노드와 빈번하게 연결될 수록 노드의 크기가 큽니다)
어떤 단어들은 관계가 가까워 자주 함께 사용되고 어떤 단어들은 그렇지 않습니다. __단어 간의 관계가 가까워 빈번하게 연결된 노드 집단__을 __커뮤니티(community)__라고 합니다. 노드를 커뮤니티별로 구분지어 서로 다른 색으로 표현하면 의미 연결망 구조를 이해하기 쉬워집니다.
커뮤니티를 나타낸 그래프(관계가 가까운 노드는 같은 색으로 표현됩니다)
pair
를 이용해 네트워크 그래프 데이터를 만든 다음, 연결 중심성과 커뮤니티를 나타낸 변수를 추가합니다.네트워크 그래프 데이터 만들기: pair
에서 50회 이상 함께 사용된 단어만 추출한 다음 as_tbl_graph()
를 이용해 네트워크 그래프 데이터를 만듭니다. 이때, as_tbl_graph()
에 directed=F
를 입력해 방향성이 없도록 설정합니다. 뒤이어 활용할 group_infomap()
은 방향성 없는 네트워크 그래프 데이터에서만 커뮤니티를 찾아줍니다.
연결 중심성, 커뮤니티 변수 추가하기: tidygraph
패키지의 centrality_degree()
는 노드의 연결 중심성을 구하고, group_infomap()
은 커뮤니티를 찾는 기능을 합니다. 두 함수를 mutate()
에 적용해 연결 중심성과 커뮤니티를 나타낸 변수를 추가합니다.
group_infomap()
은 커뮤니티를 정수형 숫자로 표현합니다. 변수가 숫자인 상태로 그래프를 만들면 노드가 그룹에 따라 다른 색으로 표현되는게 아니라 크기에 따라 농도가 다른 그라데이션으로 표현됩니다. as.factor()
를 이용해 group_infomap()
의 결과를 factor타입으로 변환하면 이런 현상을 피할 수 있습니다.
다음 코드의 출력 결과를 보면 노드에 centrality
와 group
변수가 추가됐음을 알 수 있습니다.
set.seed(210531)
graph_pair <- pair %>%
filter(n >= 50) %>%
as_tbl_graph(directed = F) %>%
mutate(centrality = centrality_degree(), # 연결 중심성
group = as.factor(group_louvain())) # 커뮤니티
graph_pair
## # A tbl_graph: 38 nodes and 206 edges
## #
## # An undirected multigraph with 1 component
## #
## # Node Data: 38 x 3 (active)
## name centrality group
## <chr> <dbl> <fct>
## 1 코로나19 74 1
## 2 az 54 1
## 3 미국 36 2
## 4 화이자 26 2
## 5 영국 20 3
## 6 제약사 16 3
## # ... with 32 more rows
## #
## # Edge Data: 206 x 3
## from to n
## <int> <int> <dbl>
## 1 1 2 498
## 2 1 2 498
## 3 1 3 404
## # ... with 203 more rows
graph_pair
를 이용해 연결 중심성과 커뮤니티를 표현한 연결망 그래프를 만들겠습니다.geom_node_point()
에 aes()
를 추가하고, 연결 중심성에 따라 노드 크기를 정하도록 size = centrality
를 입력합니다.aes()
에 color = group
을 입력합니다.geom_node_point()
에 show.legend = F
를 입력합니다.scale_size(range = c(5,15))
를 추가합니다.set.seed(210531)
ggraph(graph_pair, 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(3, 10)) + # 노드 크기 범위
geom_node_text(aes(label = name), # 텍스트 표시
repel = T, # 노드밖 표시
size = 5, # 텍스트 크기
family = "nanumgothic") + # 폰트
theme_graph() # 배경 삭제
***tidygraph
패키지에는 centrality_degree()
외에도 연결 중심성을 구하는 다양한 함수가 있습니다. 또한, group_infomap()
외에도 커뮤니티 탐지 알고리즘을 이용하는 다양한 함수가 있습니다. 다음의 페이지를 참고하세요: https://tidygraph.data-imaginist.com/
“화이자”와 “백신”, 그리고 “az”와 “백신”은 헤드라인에서 가장 빈번히 등장하는 단어쌍이지만 이 단어들은 대부분의 단어와 함께 사용되기 때문에 텍스트 의미를 파악하는 데 별다른 도움이 되지 않습니다. 단어의 의미 관계를 분석할 때는 단순히 자주 함께 사용된 단어가 아니라 다른 단어에 비해 상대적으로 자주 함께 사용된 단어가 무엇인지 살펴봐야 합니다.
__파이 계수(phi coefficient)__는 __두 단어가 함께 사용되는 경우가 각각 사용되는 경우에 비해 얼마나 많은지 나타낸 지표__입니다. 파이 계수를 이용하면 어떤 단어와 함께 사용되지만 다른 단어와는 자주 함께 사용되지 않는 단어, 즉 상대적으로 관련성이 큰 단어가 무엇인지 알 수 있습니다.
파이 계수가 어떠한 의미를 지니는지 알아보겠습니다. X와 Y라는 두 단어가 있을 때, 여러 텍스트에서 두 단어의 사용 여부를 놓고 가능한 모든 경우를 따지면 다음과 같이 나누어 볼 수 있습니다.
이를 표로 정리하면 다음과 같습니다.
각각의 경우에 해당하는 빈도를 구해 다음 공식에 적용하면 파이 계수를 계산할 수 있습니다.
\(\displaystyle \phi = \frac{ad - bc}{\sqrt{(a+b)(c+d)(a+c)(b+d)}}\)
파이 계수의 범위는 -1 ~ +1입니다. +1에 가까울수록 두 단어가 자주 함께 사용되어 관련성이 크다는 의미입니다. 반대로 -1에 가까울수록 함게 사용되는 경우가 드물어 관련성이 작다는 의미입니다.
pairwise_cor()
헤드라인 텍스트를 형태소로 토큰화하고 유의어 처리를 완료한 cv_feature
를 이용해 파이 계수를 구하겠습니다. add_count()
를 이용해 단어 빈도를 추가하고 10회 이상 사용된 단어만 추출합니다. 사용 빈도가 낮은 단어는 텍스트의 전반적인 의미 구조를 파악하는 데 도움이 되지 않으므로 제거합니다. 그런 다음 widyr
패키지의 pairwise_cor()
를 이용해 파이 계수를 구합니다. pairwise_cor()
에는 다음과 같은 파라미터를 입력합니다.
item
: 단어. 여기서는 word
를 입력합니다.feature
: 텍스트 구분 기준. 여기서는 rowid
를 입력합니다.sort = T
: 파이 계수가 높은 순으로 출력 결과를 정렬합니다.다음 코드의 출력 결과에서 correlation
이 파이 계수를 의미합니다. correlation
을 보면 두 단어의 관련성이 얼마나 큰지 알 수 있습니다.
count()
를 이용하면 빈도만 남고 원자료가 제거되지만, add_count()
를 이용하면 원자료에 빈도를 나타낸 변수를 추가합니다
feature_cors <- cv_feature %>%
add_count(word) %>%
filter(n >= 50) %>% # 절대적 기준치 없음
pairwise_cor(item = word,
feature = rowid,
sort = T)
pair
## # A tibble: 225,996 x 3
## item1 item2 n
## <chr> <chr> <dbl>
## 1 코로나19 az 498
## 2 az 코로나19 498
## 3 미국 코로나19 404
## 4 코로나19 미국 404
## 5 화이자 코로나19 399
## 6 코로나19 화이자 399
## 7 화이자 미국 294
## 8 미국 화이자 294
## 9 영국 코로나19 269
## 10 코로나19 영국 269
## # ... with 225,986 more rows
feature_cors
## # A tibble: 1,806 x 3
## item1 item2 correlation
## <chr> <chr> <dbl>
## 1 접종 백신 0.600
## 2 백신 접종 0.600
## 3 65세 고령층 0.513
## 4 고령층 65세 0.513
## 5 화이자 미국 0.477
## 6 미국 화이자 0.477
## 7 고령자 65세 0.470
## 8 65세 고령자 0.470
## 9 보건소 요양병원 0.451
## 10 요양병원 보건소 0.451
## # ... with 1,796 more rows
특정 단어와 관련성이 큰 단어를 살펴보겠습니다. 출력 결과를 보면 단순히 자주 사용된 단어가 아니라 상대적으로 자주 함게 사용되어 의미적 관련성이 큰 단어가 무엇인지 알 수 있습니다.
pair %>% filter(item1 == "az")
## # A tibble: 2,629 x 3
## item1 item2 n
## <chr> <chr> <dbl>
## 1 az 코로나19 498
## 2 az 영국 193
## 3 az 65세 134
## 4 az 미국 132
## 5 az 화이자 129
## 6 az 한국 103
## 7 az 유럽 98
## 8 az 제약사 94
## 9 az 종사자 86
## 10 az 모더나 86
## # ... with 2,619 more rows
feature_cors %>%
filter(item1 == "az")
## # A tibble: 42 x 3
## item1 item2 correlation
## <chr> <chr> <dbl>
## 1 az 65세 0.273
## 2 az 요양병원 0.196
## 3 az 한국 0.191
## 4 az 고령층 0.173
## 5 az 유럽 0.157
## 6 az 식약처 0.150
## 7 az 입소자 0.145
## 8 az 고령자 0.137
## 9 az 영국 0.128
## 10 az 보건소 0.124
## # ... with 32 more rows
feature_cors %>%
filter(item1 == "화이자")
## # A tibble: 42 x 3
## item1 item2 correlation
## <chr> <chr> <dbl>
## 1 화이자 미국 0.477
## 2 화이자 바이오엔테크 0.429
## 3 화이자 모더나 0.329
## 4 화이자 제약사 0.305
## 5 화이자 fda 0.247
## 6 화이자 독일 0.192
## 7 화이자 의약국 0.172
## 8 화이자 참가자 0.168
## 9 화이자 얀센 0.128
## 10 화이자 감염증 0.115
## # ... with 32 more rows
파이 계수로 막대 그래프를 만들면 관심 단어가 어떤 단어와 관련성이 높은지 한눈에 살펴 볼 수 있습니다.
feature_cors
에서 관심 단어별로 파이 계수가 가장 큰 단어를 10개씩 추출하겠습니다.target <- c("백신", "az", "화이자")
top_cors <- feature_cors %>%
filter(item1 %in% target) %>%
group_by(item1) %>%
slice_max(correlation, n = 10)
top_cors
## # A tibble: 30 x 3
## # Groups: item1 [3]
## item1 item2 correlation
## <chr> <chr> <dbl>
## 1 az 65세 0.273
## 2 az 요양병원 0.196
## 3 az 한국 0.191
## 4 az 고령층 0.173
## 5 az 유럽 0.157
## 6 az 식약처 0.150
## 7 az 입소자 0.145
## 8 az 고령자 0.137
## 9 az 영국 0.128
## 10 az 보건소 0.124
## # ... with 20 more rows
top_cors
를 이용해 그래프를 만듭니다. 출력한 그래프를 보면 관심 단어가 어떤 단어와 관련성이 큰지 한눈에 알 수 있습니다.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_minimal()
파이 계수를 이용해 네트워크 그래프를 만들겠습니다. 동시 출현 빈도를 이용해 네트워크 그래프를 만들 때와 같은 방법을 이용하면 됩니다. 파이 계수로 네트워크 그래프를 만들면 관련성이 큰 단어를 중심으로 텍스트의 맥락을 살펴볼 수 있습니다.
feature_cors
에서 correlation
이 0.15
이상인 단어쌍만 추출합니다. 그런 다음, 네트워크 그래프 데이터를 만들고 연결 중심성과 커뮤니티를 추가합니다.set.seed(210531)
graph_cors <- feature_cors %>%
filter(correlation >= 0.15) %>% # 절대적 기준치 없음
as_tbl_graph(directed = F) %>%
mutate(centrality = centrality_degree(),
group = as.factor(group_louvain()))
graph_cors
## # A tbl_graph: 41 nodes and 158 edges
## #
## # An undirected multigraph with 2 components
## #
## # Node Data: 41 x 3 (active)
## name centrality group
## <chr> <dbl> <fct>
## 1 접종 4 4
## 2 백신 4 4
## 3 65세 16 3
## 4 고령층 8 3
## 5 화이자 16 1
## 6 미국 16 1
## # ... with 35 more rows
## #
## # Edge Data: 158 x 3
## from to correlation
## <int> <int> <dbl>
## 1 1 2 0.600
## 2 1 2 0.600
## 3 3 4 0.513
## # ... with 155 more rows
graph_cors
를 이용해 네트워크 그래프를 만들겠습니다.geom_edge_link()
에 aes()
를 추가하고, 단어 간 관련성이 클수록 엣지를 진하게 표현하도록 edge_alpha = correlation
를 입력합니다.aes()
에 edge_width = correlation
를 입력합니다.출력한 그래프를 보면 관련성이 큰 단어쌍을 한눈에 알 수 있습니다.
set.seed(210531)
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(0.5, 2)) + # 엣지 두께 범위
geom_node_point(aes(size = centrality,
color = group),
show.legend = F) +
scale_size(range = c(2, 7)) +
geom_node_text(aes(label = name),
repel = T,
size = 3,
family = "nanumgothic") +
theme_graph()
네트워크 그래프를 만들 때 자주 사용된 단어를 파악하려면 동시 출현 빈도를 활용하는게 좋고, 상대적으로 더욱 밀접하게 관련된 단어쌍을 파악하려면 파이 계수를 활용하는게 좋습니다.