7주차 수업 전까지 한 학기 동안 분석할 언어 (한국어 또는 영어) 코퍼스를 구성하여 데이터 처리 할 수 있도록 구조화 후 요약과 함께 제출합니다.
8주차 수업 시간에 학생 개인은 자신의 연구 프로젝트를 수행하기 위한 계획서를 작성하여 제출하고 (5장 내외) 이에 대한 발표를 진행합니다.
연구계획서의 구성은 다음과 같습니다.
대단위의 텍스트를 컴퓨터로 분석하기 위한 SW는 많이 있지만, 그중에서 R은 “데이터과학”의 영역에서 애용되고 있는 프로그래밍 환경이다. 그 이유는 R이 무료이면서 오픈소스라는 장점과 함께 통계분석을 위해 고안된 SW로서 데이터과학 응용에 적합하기 때문이다. 특히, 오픈소스 프로그래밍 환경을 제공하기 때문에 다양한 목적에 따라 다양한 기능을 수행하는 확장 SW 라이브러리들이 패키지 형태로 모인다는 점은 R의 큰 장점 중 하나이다. 예를 들어, 대표적 패키지 저장소인 “Comprehensive R Archive Network (CRAN)”에는 절차적 적합성과 호환성 검토를 통과한 10,000개 이상의 패키지들이 집적되어 있고, 각각의 패키지는 사용 편의와 유용성을 위해 지속적인 관리를 받는다. 이러한 패키지는 매우 간단하게 R에 설치 후 사용가능하기 때문에 협업 프로젝트에도 적합하다. 특히, R에는 기초적인 문자열 조작부터 감정분석, 토픽모델링까지 다양한 텍스트 분석용 패키지가 50개가 넘게 있다. 또한 rOpenSci는 R 사용자들의 공간으로서 텍스트 분석에 관심있는 연구자과 개발자의 모임이 결성되어 있기 때문에 협력과 도움이 필요할 때도 유용하다. 결국, R을 활용하여 텍스트를 분석하는 것은 사회과학의 영역에서 심도있고 다양한 주제의 연구를 위해 컴퓨터 텍스트 분석을 수행하기 위한 효과적인 수단이다. 이러한 R을 보다 편리하게 이용하기 위해 사용자 친화적 인터페이스인 RStudio 사용을 추천한다.
[출처: Welbers, Attenveldt, Benoit, 2017]
텍스트 마이닝 순서
위 과정에 따르면 각 문서의 디지털 텍스트를 정리해야 할 필요가 있는데, 예를 들어 문자열에 등장하는 불필요한 공란과 구두점 등을 제거해줌으로써 텍스트를 균일한 의미 단위로 분석할 수 있는 준비 과정이 필요하다. 이를 텍스트 전처리 과정이라 한다.
토큰화 과정은 텍스트를 분석의 어휘 등의 기본 단위로 쪼개는 것을 의미한다. 한국어의 경우 형태소 분석 및 품사 태깅 작업이 요구된다. http://konlpy.org/ko/v0.4.4/morph/
토큰화를 거친 텍스트 데이터는 정제와 숫자 변환 및 가중치 부여, 정보 추출 등의 자연어 처리를 거쳐 분류와 유목화, 예측을 위한 알고리즘에 적용한다.
분석 결과를 해석한다.
rJava
패키지 설치가 필요함. multilinguer
패키지의 install_jdk()
이용해 설치.install.packages("multilinguer")
library(multilinguer)
install_jdk()
KoNLP
설치를 위해 먼저 KoNLP
가 의존하는 패키지들 설치#install.packages(c("stringr", "hash", "tau", "Sejong", "RSQLite", "devtools","processx"), type = "binary")
#install.packages("remotes")
remotes::install_github("haven-jeon/KoNLP",
upgrade = "never",
INSTALL_opts = c("--no-multiarch"))
library(KoNLP)
useNIADic()
#install.packages('devtools')
library(devtools)
install_github('haven-jeon/NIADic/NIADic', build_vignettes = TRUE)
4-1. 띄어쓰기 분석기
remotes::install_github('haven-jeon/KoSpacing', force = TRUE)
install_conda()
#install.packages("reticulate")
install_miniconda()
library(KoSpacing)
KoSpacing::set_env()
library(KoNLP)
library(KoSpacing)
text <- "한국어 텍스트를 컴퓨터로 분석해 봅시다."
text
?extractNoun
extractNoun(text)
?KoNLP::SimplePos09()
?KoNLP::SimplePos22()
KoNLP::SimplePos09(text)
KoNLP::SimplePos22(text)
# 띄어쓰기
extractNoun("아버지가방에들어가신다")
spacing("아버지가방에들어가신다")
extractNoun(spacing("아버지가방에들어가신다"))
수집한 뉴스기사를 분석을 위한 데이터 프레임으로 불러온다.
library(readxl)
cv <- read_excel("bigkinds_corona_vaccine.xlsx", sheet = 1)
cv
## # A tibble: 2,442 x 11
## DATE COMPANY BYLINE HEADLINE PERSON PLACE ORG KEYWORD FEATURE TEXT URL
## <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 20210~ 조선일보~ 신정훈 기~ "코로나 백신~ <NA> 충북,충~ 아스트라~ 코로나,백신~ 종사자,충북~ "충북에~ http~
## 2 20210~ 중앙일보~ 서유진(s~ "임신중 백신~ 러드닉,채~ 이스라엘~ WPBF~ 임신,백신,~ 미국,코로나~ "미국에~ http~
## 3 20210~ 조선일보~ 김승현 기~ "코로나 백신~ 트럼프,빌~ 미국 폭스뉴스~ 코로나,백신~ 코로나,미국~ "도널드~ http~
## 4 20210~ 영남일보~ 김기태 "포항가속기硏~ 강흥식 독일,미~ 포항가속~ 포항가속기,~ 가속기,포항~ "인류 ~ http~
## 5 20210~ 세계일보~ 김현주 "英 전문가 ~ 앨버트,피~ 최고경영~ HBO,~ 코로나,전문~ 코로나19,~ "미국 ~ http~
## 6 20210~ 국민일보~ 권남영 "임신 중 코~ <NA> 플로리다~ 모더나~ 임신,코로나~ 미국,코로나~ "미국에~ http~
## 7 20210~ 중앙일보~ 나운채(n~ "이란도 코로~ 파크리자데~ 소도,중~ AP통신~ 이란도,코로~ 코로나19,~ "이란이~ http~
## 8 20210~ 충청투데이~ 조선교 기~ "백신 이상반~ <NA> 대전을지~ 대전,아~ 백신,반응,~ 의료진,코로~ "[충청~ http~
## 9 20210~ 강원도민일보~ 양희문 "접종 후 두~ 이창률 강원도~ 춘천성심~ 접종,두통,~ 이상반응,관~ "\"경~ www.~
## 10 20210~ 국제신문~ 방종근 기~ "울산 첫 코~ <NA> 울산,중~ 울산,예~ 울산,개소,~ 동천체육관,~ "울산에~ http~
## # ... with 2,432 more rows
데이터 정제를 위한 tidyverse 패키지 불러오기
지금부터 tibble이라는 데이터 프레임의 형식으로 이루어진 뉴스기사 데이터를 텍스트 분석을 위한 전처리 방식에 대해서 알아보도록 하겠습니다. 이를 위해 필요한 함수를 제공하는 tidyverse 패키지에 대해서 살펴보도록 하겠습니다.
우선, tidyverse패키지의 함수들을 이용해서 트위터 데이터를 처리하는 방법을 알아보도록 하겠습니다. 우선, tidyverse 패키지를 R세션에 설치해 봅시다.
#install.packages(tidyverse")
library(tidyverse)
## -- Attaching packages --------------------------------------- tidyverse 1.3.0 --
## √ ggplot2 3.3.3 √ purrr 0.3.4
## √ tibble 3.1.0 √ dplyr 1.0.4
## √ tidyr 1.1.2 √ stringr 1.4.0
## √ readr 1.3.1 √ forcats 0.5.1
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
첫번째로 살펴 볼 dplyr 패키지의 함수는 select()
입니다. 이 함수는 데이터의 변수를 선택해서 해당 변수만 남기고 나머지 변수들은 제거하는 기능을 합니다. 예를 들어서, 우리의 데이터 객체인 cv
는 11개의 변수로 구성이 되어있죠. 앞서 말했듯, 이 변수들은 우리가 모은 기사들의 성격을 규정하는 역할을 합니다. 예를 들어서, 첫번째 변수의 이름을 DATE
이고 이 변수에는 각 기사의 날짜가 문자 벡터 형태로 포함되어 있습니다.
# 데이터의 변수 선택은: 데이터 객체 이름에 Dollar 사인 후 변수 이름 입력
class(cv$DATE) # 문자 벡터
## [1] "character"
cv$DATE[1:10] # 첫번째 기사부터 열번째 기사의 날짜 정보보 인덱싱
## [1] "20210317" "20210317" "20210317" "20210317" "20210317" "20210317"
## [7] "20210317" "20210317" "20210317" "20210317"
cv 데이터는 11개의 변수로 구성되어 있고, 여기에서 우리가 필요한 변수 중 하나는 HEADLINE
입니다. 이 변수에는 각 기사의 제목, 즉 우리가 분석할 어휘들로 구성된 뉴스 헤드라인이 문자열 벡터 형태로 포함되어 있습니다. 또, 언론사 정보 “COMPANY”와, 날짜 “DATE”, 리드(기사의 첫 200자) “TEXT” 등이 우리가 필요한 기사 정보들이라 할 수 있겠네요.
이 변수들만 남기고 나머지 변수들을 제거하기 위해서 필요한 함수가 바로 select()
입니다.
select()
: 데이터의 변수(들)을 선택 및 처리dim(cv)
## [1] 2442 11
class(cv$HEADLINE) #문자(열) 벡터
## [1] "character"
cv$HEADLINE[1:10] # 첫번째 기사부터 열번째 기사의 문자열 내용 인덱싱
## [1] "코로나 백신 접종 요양병원 종사자 ‘확진’ 충북 첫 사례"
## [2] "임신중 백신 맞은 엄마 아기는 코로나 항체 갖고 태어났다"
## [3] "코로나 백신 독려 광고 빠졌던 트럼프, 돌연 “백신 맞으라” 당부"
## [4] "포항가속기\u784f, 인류 사상 최고 밝은 빛 구현 \"코로나 백신 개발 우선 제공\""
## [5] "\u82f1 전문가 \"코로나 변이 바이러스 사라지지 않아 백신 평생 맞아야 할지도\" 우려"
## [6] "임신 중 코로나 백신 맞은 엄마, ‘항체 보유’ 아기 출산"
## [7] "이란도 코로나 백신 공개 암살된 핵 과학자 이름 붙였다"
## [8] "백신 이상반응에도 다시 코로나 최전선으로"
## [9] "접종 후 두통 발열 몸살 코로나 백신공포증 확산"
## [10] "울산 첫 코로나 백신 접종센터 동천체육관 개소"
cv %>% select(DATE, COMPANY, HEADLINE, TEXT) # 데이터 처리 과정을 연쇄적으로 이어주는 파이프(pipe) 연산자; cv에서 다음의 변수들만 남기고 나머지는 제거
## # A tibble: 2,442 x 4
## DATE COMPANY HEADLINE TEXT
## <chr> <chr> <chr> <chr>
## 1 20210~ 조선일보 "코로나 백신 접종 요양병원 종사자 ‘확진’ 충북 첫 ~ "충북에서도 백신 1차 접종자의 코로나 확진 판정~
## 2 20210~ 중앙일보 "임신중 백신 맞은 엄마 아기는 코로나 항체 갖고 태어~ "미국에서 임신 중 코로나 19 백신을 접종한 여~
## 3 20210~ 조선일보 "코로나 백신 독려 광고 빠졌던 트럼프, 돌연 “백신 ~ "도널드 트럼프 전 미국 대통령이 16일(현지 시~
## 4 20210~ 영남일보 "포항가속기硏, 인류 사상 최고 밝은 빛 구현 \"코로~ "인류 사상 최고 밝기의 빛이 국내 연구진에 의해~
## 5 20210~ 세계일보 "英 전문가 \"코로나 변이 바이러스 사라지지 않아 백~ "미국 제약사 화이자의 코로나19 백신. AFP연~
## 6 20210~ 국민일보 "임신 중 코로나 백신 맞은 엄마, ‘항체 보유’ 아기~ "미국에서 임신 중 코로나19 백신을 접종한 여성~
## 7 20210~ 중앙일보 "이란도 코로나 백신 공개 암살된 핵 과학자 이름 붙였~ "이란이 세 번쨰 자체 개발 신종 코로나바이러스 ~
## 8 20210~ 충청투데이~ "백신 이상반응에도 다시 코로나 최전선으로"~ "[충청투데이 조선교 기자] #. 대전의 한 대학~
## 9 20210~ 강원도민일보~ "접종 후 두통 발열 몸살 코로나 백신공포증 확산"~ "\"경미한 이상반응 이틀 내 회복\"전국적 사망~
## 10 20210~ 국제신문 "울산 첫 코로나 백신 접종센터 동천체육관 개소"~ "울산에서도 코로나19 백신 접종센터가 16일 문~
## # ... with 2,432 more rows
cv_frames <- cv %>% select(DATE, COMPANY, HEADLINE, TEXT) # 위 처리 과정을 거친 데이터를 cv_text라는 새로운 객체에 할당
dim(cv_frames) # 새로운 데이터 프레임 구조 확인
## [1] 2442 4
filter()
: 데이터의 기사(observation)를 선택 및 처리기사 데이터를 처리하는데 있어, 특정 관측치를 선택할 필요 filter()
함수는 입력된 조건에 부합하는 행들만 남기고 나머지는 지워주는 역할을 합니다. 가령, 어떤 기사의 텍스트에 특정 단어가 포함되어 있는지 여부에 따라 해당 기사만 출력하기 위해 필요한 함수는: str_detect()
- 해당 벡터의 값 중 원하는 문자열이 포함되어 있는지 아닌지 판별하는 기능
library(stringr)
cv_frames %>% filter(str_detect(HEADLINE, "코로나")) %>% dim()
## [1] 2442 4
cv_frames %>% filter(str_detect(HEADLINE, "백신")) %>% dim()
## [1] 2442 4
만약 해당 문자열을 포함하지 않는 기사를 추출하기 위해 필요한 연산자는: !
! 는 논리 연산에서 부정의 뜻을 의미: ~~이 아니다.
cv_frames %>% filter(!str_detect(HEADLINE, regex("AZ", ignore_case = T)))
## # A tibble: 2,428 x 4
## DATE COMPANY HEADLINE TEXT
## <chr> <chr> <chr> <chr>
## 1 20210~ 조선일보 "코로나 백신 접종 요양병원 종사자 ‘확진’ 충북 첫 ~ "충북에서도 백신 1차 접종자의 코로나 확진 판정~
## 2 20210~ 중앙일보 "임신중 백신 맞은 엄마 아기는 코로나 항체 갖고 태어~ "미국에서 임신 중 코로나 19 백신을 접종한 여~
## 3 20210~ 조선일보 "코로나 백신 독려 광고 빠졌던 트럼프, 돌연 “백신 ~ "도널드 트럼프 전 미국 대통령이 16일(현지 시~
## 4 20210~ 영남일보 "포항가속기硏, 인류 사상 최고 밝은 빛 구현 \"코로~ "인류 사상 최고 밝기의 빛이 국내 연구진에 의해~
## 5 20210~ 세계일보 "英 전문가 \"코로나 변이 바이러스 사라지지 않아 백~ "미국 제약사 화이자의 코로나19 백신. AFP연~
## 6 20210~ 국민일보 "임신 중 코로나 백신 맞은 엄마, ‘항체 보유’ 아기~ "미국에서 임신 중 코로나19 백신을 접종한 여성~
## 7 20210~ 중앙일보 "이란도 코로나 백신 공개 암살된 핵 과학자 이름 붙였~ "이란이 세 번쨰 자체 개발 신종 코로나바이러스 ~
## 8 20210~ 충청투데이~ "백신 이상반응에도 다시 코로나 최전선으로"~ "[충청투데이 조선교 기자] #. 대전의 한 대학~
## 9 20210~ 강원도민일보~ "접종 후 두통 발열 몸살 코로나 백신공포증 확산"~ "\"경미한 이상반응 이틀 내 회복\"전국적 사망~
## 10 20210~ 국제신문 "울산 첫 코로나 백신 접종센터 동천체육관 개소"~ "울산에서도 코로나19 백신 접종센터가 16일 문~
## # ... with 2,418 more rows
text 변수에 문자열 벡터로 담겨있는 텍스트 내용이 “코로나”, “우한” 또는 “중국” 문자열 포함하는 조건에 해당하는 행만 남기고 나머지는 제거
dim(cv_frames)
## [1] 2442 4
?duplicated
## starting httpd help server ... done
table(duplicated(cv_frames$HEADLINE))
##
## FALSE TRUE
## 2425 17
cv_frames %>% filter(!duplicated(HEADLINE)) %>% dim()
## [1] 2425 4
cv_frames_unique <- cv_frames %>% filter(!duplicated(HEADLINE))
dim(cv_frames_unique)
## [1] 2425 4
cv_frames_unique$HEADLINE[1:10]
## [1] "코로나 백신 접종 요양병원 종사자 ‘확진’ 충북 첫 사례"
## [2] "임신중 백신 맞은 엄마 아기는 코로나 항체 갖고 태어났다"
## [3] "코로나 백신 독려 광고 빠졌던 트럼프, 돌연 “백신 맞으라” 당부"
## [4] "포항가속기\u784f, 인류 사상 최고 밝은 빛 구현 \"코로나 백신 개발 우선 제공\""
## [5] "\u82f1 전문가 \"코로나 변이 바이러스 사라지지 않아 백신 평생 맞아야 할지도\" 우려"
## [6] "임신 중 코로나 백신 맞은 엄마, ‘항체 보유’ 아기 출산"
## [7] "이란도 코로나 백신 공개 암살된 핵 과학자 이름 붙였다"
## [8] "백신 이상반응에도 다시 코로나 최전선으로"
## [9] "접종 후 두통 발열 몸살 코로나 백신공포증 확산"
## [10] "울산 첫 코로나 백신 접종센터 동천체육관 개소"
mutate()
: 기존 변수를 이용하여 생성한 새로운 변수를 데이터 열에 추가cv_frames_unique
## # A tibble: 2,425 x 4
## DATE COMPANY HEADLINE TEXT
## <chr> <chr> <chr> <chr>
## 1 20210~ 조선일보 "코로나 백신 접종 요양병원 종사자 ‘확진’ 충북 첫 ~ "충북에서도 백신 1차 접종자의 코로나 확진 판정~
## 2 20210~ 중앙일보 "임신중 백신 맞은 엄마 아기는 코로나 항체 갖고 태어~ "미국에서 임신 중 코로나 19 백신을 접종한 여~
## 3 20210~ 조선일보 "코로나 백신 독려 광고 빠졌던 트럼프, 돌연 “백신 ~ "도널드 트럼프 전 미국 대통령이 16일(현지 시~
## 4 20210~ 영남일보 "포항가속기硏, 인류 사상 최고 밝은 빛 구현 \"코로~ "인류 사상 최고 밝기의 빛이 국내 연구진에 의해~
## 5 20210~ 세계일보 "英 전문가 \"코로나 변이 바이러스 사라지지 않아 백~ "미국 제약사 화이자의 코로나19 백신. AFP연~
## 6 20210~ 국민일보 "임신 중 코로나 백신 맞은 엄마, ‘항체 보유’ 아기~ "미국에서 임신 중 코로나19 백신을 접종한 여성~
## 7 20210~ 중앙일보 "이란도 코로나 백신 공개 암살된 핵 과학자 이름 붙였~ "이란이 세 번쨰 자체 개발 신종 코로나바이러스 ~
## 8 20210~ 충청투데이~ "백신 이상반응에도 다시 코로나 최전선으로"~ "[충청투데이 조선교 기자] #. 대전의 한 대학~
## 9 20210~ 강원도민일보~ "접종 후 두통 발열 몸살 코로나 백신공포증 확산"~ "\"경미한 이상반응 이틀 내 회복\"전국적 사망~
## 10 20210~ 국제신문 "울산 첫 코로나 백신 접종센터 동천체육관 개소"~ "울산에서도 코로나19 백신 접종센터가 16일 문~
## # ... with 2,415 more rows
names(cv_frames_unique)
## [1] "DATE" "COMPANY" "HEADLINE" "TEXT"
cv_frames_unique$DATE[1:10]
## [1] "20210317" "20210317" "20210317" "20210317" "20210317" "20210317"
## [7] "20210317" "20210317" "20210317" "20210317"
library(lubridate) # 날짜 정보를 다루기 위한 함수를 제공
##
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
##
## date, intersect, setdiff, union
cv_frames_unique %>% mutate(date = ymd(DATE))
## # A tibble: 2,425 x 5
## DATE COMPANY HEADLINE TEXT date
## <chr> <chr> <chr> <chr> <date>
## 1 20210~ 조선일보 "코로나 백신 접종 요양병원 종사자 ‘확진’~ "충북에서도 백신 1차 접종자의 코로나 ~ 2021-03-17
## 2 20210~ 중앙일보 "임신중 백신 맞은 엄마 아기는 코로나 항체~ "미국에서 임신 중 코로나 19 백신을 ~ 2021-03-17
## 3 20210~ 조선일보 "코로나 백신 독려 광고 빠졌던 트럼프, 돌~ "도널드 트럼프 전 미국 대통령이 16일~ 2021-03-17
## 4 20210~ 영남일보 "포항가속기硏, 인류 사상 최고 밝은 빛 구~ "인류 사상 최고 밝기의 빛이 국내 연구~ 2021-03-17
## 5 20210~ 세계일보 "英 전문가 \"코로나 변이 바이러스 사라지~ "미국 제약사 화이자의 코로나19 백신.~ 2021-03-17
## 6 20210~ 국민일보 "임신 중 코로나 백신 맞은 엄마, ‘항체 ~ "미국에서 임신 중 코로나19 백신을 접~ 2021-03-17
## 7 20210~ 중앙일보 "이란도 코로나 백신 공개 암살된 핵 과학자~ "이란이 세 번쨰 자체 개발 신종 코로나~ 2021-03-17
## 8 20210~ 충청투데이~ "백신 이상반응에도 다시 코로나 최전선으로"~ "[충청투데이 조선교 기자] #. 대전의~ 2021-03-17
## 9 20210~ 강원도민일보~ "접종 후 두통 발열 몸살 코로나 백신공포증~ "\"경미한 이상반응 이틀 내 회복\"전~ 2021-03-17
## 10 20210~ 국제신문 "울산 첫 코로나 백신 접종센터 동천체육관 ~ "울산에서도 코로나19 백신 접종센터가 ~ 2021-03-17
## # ... with 2,415 more rows
# ymd 함수의 기능은?
cv_frames_date <- cv_frames_unique %>% mutate(date = ymd(DATE))
library(ggplot2) #시각화 예시
cv_frames_date %>%
count(date) %>%
ggplot(aes(x=date, y=n)) +
geom_col() +
scale_x_date(date_breaks = "1 month", date_labels = "%b")
cv_frames_date %>%
count(DATE) %>%
ggplot(aes(x=DATE, y=n)) +
geom_col()
select()
와 filter()
, mutate()
등 dplyr
패키지의 함수를 이용해서 데이터 처리하는 과정을 살펴봄.
*보편적 고려사항: Basic-level 1) 빈칸 (white space) 2) 구두점 (punctuation) 3) 숫자 (digit numbers) 4) 한국어 (UTF-8) 이외의 문자 (e.g., ASCII code)
# 1) space
cv_frames_date$TEXT[1]
## [1] "충북에서도 백신 1차 접종자의 코로나 확진 판정 사례가 나왔다. \r\n \r\n17일 충북도 등에 따르면 충주시 모 요양병원 원무과에서 근무하는 30대 A씨가 이날 코로나 ‘양성’ 판정을 받았다. \r\n \r\nA씨는 매주 두 차례씩 진행되는 요양시설 종사자 등에 대한 선제 검사에서 양성으로 나왔다. 지난 12일 직전 검사에서는 음성 판정을 받았다. \r\n \r\n1분기 접종 대.."
str_squish(cv_frames_date$TEXT[1])
## [1] "충북에서도 백신 1차 접종자의 코로나 확진 판정 사례가 나왔다. 17일 충북도 등에 따르면 충주시 모 요양병원 원무과에서 근무하는 30대 A씨가 이날 코로나 ‘양성’ 판정을 받았다. A씨는 매주 두 차례씩 진행되는 요양시설 종사자 등에 대한 선제 검사에서 양성으로 나왔다. 지난 12일 직전 검사에서는 음성 판정을 받았다. 1분기 접종 대.."
# 2) punctuation
cv_frames_date$TEXT[1]
## [1] "충북에서도 백신 1차 접종자의 코로나 확진 판정 사례가 나왔다. \r\n \r\n17일 충북도 등에 따르면 충주시 모 요양병원 원무과에서 근무하는 30대 A씨가 이날 코로나 ‘양성’ 판정을 받았다. \r\n \r\nA씨는 매주 두 차례씩 진행되는 요양시설 종사자 등에 대한 선제 검사에서 양성으로 나왔다. 지난 12일 직전 검사에서는 음성 판정을 받았다. \r\n \r\n1분기 접종 대.."
str_replace_all(cv_frames_date$TEXT[1], "[[:punct:]]+", " ")
## [1] "충북에서도 백신 1차 접종자의 코로나 확진 판정 사례가 나왔다 \r\n \r\n17일 충북도 등에 따르면 충주시 모 요양병원 원무과에서 근무하는 30대 A씨가 이날 코로나 양성 판정을 받았다 \r\n \r\nA씨는 매주 두 차례씩 진행되는 요양시설 종사자 등에 대한 선제 검사에서 양성으로 나왔다 지난 12일 직전 검사에서는 음성 판정을 받았다 \r\n \r\n1분기 접종 대 "
str_replace_all(cv_frames_date$TEXT[1], "[^[:word:]]+", " ")
## [1] "충북에서도 백신 1차 접종자의 코로나 확진 판정 사례가 나왔다 17일 충북도 등에 따르면 충주시 모 요양병원 원무과에서 근무하는 30대 A씨가 이날 코로나 양성 판정을 받았다 A씨는 매주 두 차례씩 진행되는 요양시설 종사자 등에 대한 선제 검사에서 양성으로 나왔다 지난 12일 직전 검사에서는 음성 판정을 받았다 1분기 접종 대 "
# 3) number
str_replace_all(cv_frames_date$TEXT[1], "\\d+", " ")
## [1] "충북에서도 백신 차 접종자의 코로나 확진 판정 사례가 나왔다. \r\n \r\n 일 충북도 등에 따르면 충주시 모 요양병원 원무과에서 근무하는 대 A씨가 이날 코로나 ‘양성’ 판정을 받았다. \r\n \r\nA씨는 매주 두 차례씩 진행되는 요양시설 종사자 등에 대한 선제 검사에서 양성으로 나왔다. 지난 일 직전 검사에서는 음성 판정을 받았다. \r\n \r\n 분기 접종 대.."
# 4) 한국어 이외의 문자? 알파벳?
cv_frames_date$TEXT[1]
## [1] "충북에서도 백신 1차 접종자의 코로나 확진 판정 사례가 나왔다. \r\n \r\n17일 충북도 등에 따르면 충주시 모 요양병원 원무과에서 근무하는 30대 A씨가 이날 코로나 ‘양성’ 판정을 받았다. \r\n \r\nA씨는 매주 두 차례씩 진행되는 요양시설 종사자 등에 대한 선제 검사에서 양성으로 나왔다. 지난 12일 직전 검사에서는 음성 판정을 받았다. \r\n \r\n1분기 접종 대.."
str_replace_all(cv_frames_date$TEXT[1], "[[:ascii:]]+", " ")
## [1] "충북에서도 백신 차 접종자의 코로나 확진 판정 사례가 나왔다 일 충북도 등에 따르면 충주시 모 요양병원 원무과에서 근무하는 대 씨가 이날 코로나 ‘양성’ 판정을 받았다 씨는 매주 두 차례씩 진행되는 요양시설 종사자 등에 대한 선제 검사에서 양성으로 나왔다 지난 일 직전 검사에서는 음성 판정을 받았다 분기 접종 대 "
cv_frames_date$HEADLINE[1]
SimplePos09(cv_frames_date$HEADLINE[1])
extractNoun(cv_frames_date$HEADLINE[1])
은전한닢 프로젝트가 기반으로 하고 있는 mecab은 일본어 형태소 분석기로, 띄어쓰기와 관계없이 형태소를 분석합니다. 인터넷에서 수집한 텍스트는 띄어쓰기에 오류가 있는 경우가 많아, 텍스트 분석을 진행할 때 은전한닢 프로젝트의 mecab-ko를 통해 진행하는 것이 유용할 수 있습니다." by 김준혁 https://www.rdocumentation.org/packages/RcppMeCab/versions/0.0.1.2
#install.packages("RmecabKo")
library(RmecabKo)
RmecabKo::install_mecab("C:/mecab")
#install.packages("RcppMeCab")
library(RcppMeCab)
?pos
pos(iconv("아버지가방에들어가신다", to="utf8"))
spacing("아버지가방에들어가신다")
pos("한국어 텍스트를 컴퓨터로 분석해 봅시다")
pos(iconv("한국어 텍스트를 컴퓨터로 분석해 봅시다", to="utf8"))
RcppMeCab::pos(iconv("한국어 텍스트를 컴퓨터로 분석해 봅시다", to="utf8"))
cv$HEADLINE[1:10]
## [1] "코로나 백신 접종 요양병원 종사자 ‘확진’ 충북 첫 사례"
## [2] "임신중 백신 맞은 엄마 아기는 코로나 항체 갖고 태어났다"
## [3] "코로나 백신 독려 광고 빠졌던 트럼프, 돌연 “백신 맞으라” 당부"
## [4] "포항가속기\u784f, 인류 사상 최고 밝은 빛 구현 \"코로나 백신 개발 우선 제공\""
## [5] "\u82f1 전문가 \"코로나 변이 바이러스 사라지지 않아 백신 평생 맞아야 할지도\" 우려"
## [6] "임신 중 코로나 백신 맞은 엄마, ‘항체 보유’ 아기 출산"
## [7] "이란도 코로나 백신 공개 암살된 핵 과학자 이름 붙였다"
## [8] "백신 이상반응에도 다시 코로나 최전선으로"
## [9] "접종 후 두통 발열 몸살 코로나 백신공포증 확산"
## [10] "울산 첫 코로나 백신 접종센터 동천체육관 개소"
cv$HEADLINE[7]
## [1] "이란도 코로나 백신 공개 암살된 핵 과학자 이름 붙였다"
RcppMeCab::pos(cv$HEADLINE[7])
## $`이란도 코로나 백신 공개 암살된 핵 과학자 이름 붙였다`
## [1] "이란/NNP" "도/JX" "코로나/NNG" "백신/NNG" "공개/NNG"
## [6] "암살/NNG" "된/XSV+ETM" "핵/NNG" "과학자/NNG" "이름/NNG"
## [11] "붙였/VV+EP" "다/EC"
dim(cv)
## [1] 2442 11
RcppMeCab::pos(cv$HEADLINE) %>%
unlist() %>%
paste(collapse=" ") %>%
str_extract_all(pattern = "[가-힣]+[/]N") %>%
unlist() %>%
paste(collapse=" ") %>%
str_remove_all(pattern="[/]N") %>%
str_split(pattern=" ") %>%
unlist() %>%
table() %>%
sort(decreasing=T) %>%
head()
## .
## 백신 코로나 접종 명 만 화이자
## 2509 2465 946 288 214 178
RcppMeCab::pos(str_squish(cv_frames_date$HEADLINE[20:28]))
## $`"팔에는 백신 주사, 주머니엔 코로나 지원금"... 바이든, 신바람 내치 홍보전`
## [1] "\"/SY" "팔/NNG" "에/JKB" "는/JX" "백신/NNG"
## [6] "주사/NNG" ",/SC" "주머니/NNG" "엔/JKB+JX" "코로나/NNG"
## [11] "지원금/NNG" "\".../SY" "바이든/NNP" ",/SC" "신바람/NNG"
## [16] "내치/NNG" "홍보전/NNG"
##
## $`코로나 신규 확진자 이틀째 300명대 백신 접종 60만 2천여 명`
## [1] "코로나/NNP" "신규/NNG" "확진/NNG" "자/XSN" "이틀/NNG"
## [6] "째/XSN" "300/SN" "명/NNBC" "대/NNBC" "백/NR"
## [11] "신/XPN" "접종/NNG" "60/SN" "만/NR" "2/SN"
## [16] "천/NR" "여/XSN" "명/NNBC"
##
## $`판치는 코로나 백신 가짜 뉴스 페이스북, '알림 딱지' 붙인다`
## [1] "판치/VV" "는/ETM" "코로나/NNG" "백신/NNG" "가짜/NNG"
## [6] "뉴스/NNG" "페이스북/NNP" ",/SC" "'/SY" "알림/VV+ETN"
## [11] "딱지/NNG" "'/SY" "붙인다/VV+EC"
##
## $`코로나 백신 18일간 총 60만2천150명 어제 363명 신규 확진`
## [1] "코로나/NNP" "백신/NNG" "18/SN" "일/NNBC" "간/NNG"
## [6] "총/MM" "60/SN" "만/NR" "2/SN" "천/NR"
## [11] "150/SN" "명/NNBC" "어제/MAG" "363/SN" "명/NNBC"
## [16] "신규/NNG" "확진/NNG"
##
## $`[여기는 남미] “우리 엄마 코로나 백신 맞으러” 노모 안고 가는 아들`
## [1] "[/SSO" "여기/NP" "는/JX" "남미/NNP" "]/SSC"
## [6] "“/SSO" "우리/NP" "엄마/NNG" "코로나/NNG" "백신/NNG"
## [11] "맞/VV" "으러/EC" "”/SSC" "노모/NNG" "안/VV"
## [16] "고/EC" "가/VX" "는/ETM" "아들/NNG"
##
## $`[속보] 정총리 "코로나 4차 유행 현실화 우려" 백신 휴가도 언급`
## [1] "[/SSO" "속보/NNG" "]/SSC" "정/XPN" "총리/NNG"
## [6] "\"/SY" "코로나/NNP" "4/SN" "차/NNBC" "유행/NNG"
## [11] "현실/NNG" "화/XSN" "우려/NNG" "\"/SY" "백신/NNG"
## [16] "휴가/NNG" "도/JX" "언급/NNG"
##
## $`정 총리 "코로나 4차 유행 현실화 우려...백신 휴가 검토하라"`
## [1] "정/NNP" "총리/NNG" "\"/SY" "코로나/NNP" "4/SN"
## [6] "차/NNBC" "유행/NNG" "현실/NNG" "화/XSN" "우려/NNG"
## [11] "./SF" "../SY" "백신/NNG" "휴가/NNG" "검토/NNG"
## [16] "하/XSV" "라/EC" "\"/SY"
##
## $`AI가 코로나 중증도 분류 스마트 링으로 백신 이상 반응 체크`
## [1] "AI/SL" "가/JKS" "코로나/NNG" "중증/NNG" "도/JX"
## [6] "분류/NNG" "스마트/NNG" "링/NNG" "으로/JKB" "백신/NNG"
## [11] "이상/NNG" "반응/NNG" "체크/NNG"
##
## $`코로나 백신에 투영된 ‘콜드체인’ 빛과 그림자`
## [1] "코로나/NNP" "백신/NNG" "에/JKB" "투영/NNG" "된/XSV+ETM"
## [6] "‘/SY" "콜드/NNG" "체인/NNG" "’/SY" "빛/NNG"
## [11] "과/JC" "그림자/NNG"
RcppMeCab::pos(str_remove_all(str_squish(cv_frames_date$HEADLINE[28]), "[^[:word:]#. ]"))
## $`코로나 백신에 투영된 콜드체인 빛과 그림자`
## [1] "코로나/NNP" "백신/NNG" "에/JKB" "투영/NNG" "된/XSV+ETM"
## [6] "콜드/NNG" "체인/NNG" "빛/NNG" "과/JC" "그림자/NNG"
tidytext
자, 이제는 “tidy” 데이터가 무엇인지, 그 원리를 살펴보고 이를 기반으로 한 어휘 빈도수 분석에 효율적인 함수를 제공하는 “tidytext” 패키지를 소개해드리도록 하겠습니다. 특히, 이 패키지의 unnest_tokens()
함수는 텍스트 전처리에 매우 편리한 기능을 제공합니다.
자 우선, tidytext
패키지와 텍스트 전처리에 필요한 stringr
패키지를 R세션에 설치해 봅시다.
library(tidytext)
library(stringr)
앞서 우리는 어휘 빈도수 분석을 위해서, 여러 전처리 과정을 거쳐왔습니다. 예를 들어, 문자열에서 구두점, 숫자, 알파벳 이외의 문자 등을 정규 표현을 이용해서 매칭하고 지워주거나 바꿔주는 전처리 작업을 했었죠. 그리고 이렇게 전처리 과정을 거친 텍스트를 단어 단위로 분석하기 위해서 빈칸을 기준으로 문자열을 쪼개는 작업을 거쳤습니다. 이를 위해 str_split()
이라는 함수를 사용했었죠.
tidytext
패키지의 unnest_tokens()
함수는 이 과정을 한번에 그리고 편리하게 수행할 수 있도록 해주는 기능을 수행합니다. apostrophe의 축약형을 제외한 텍스트의 구두점은 자동적으로 삭제하고, 알파벳을 소문자로 변환하고 빈칸을 기준으로 단어 단위로 텍스트를 쪼개서 그 결과값을 ‘tidy’ 데이터로 만들어 줍니다. 결국, 텍스트를 토큰 단위로 쪼개서 한 행에 하나의 토큰, 여기에선 한 단어씩 위치하게하는 데이터 프레임 형식으로 변환하는 기능을 수행하는 거죠.
tidy
데이터란 각 행에 하나의 토큰(여기에선 하나의 단어)만 위치하도록 구성된 테이블을 말합니다. 결국 tidy
한 데이터를 만든다는 것은 토큰의 단위를 정하고 텍스트 데이터를 토큰화하여 각 행이 하나의 토큰으로 구성되게 만든다는 것이죠. 이렇게 tidy
데이터를 구성한다는 것은 각 행이 하나의 단어씩 가지고 있기 때문에 이후 어휘 빈도수 분석 또는 사전기반 감정분석을 수행할 때 편리하게 연계 작업할 수 있다는 장점이 있습니다.
자, 다음의 R코드는 unnest_tokens()
함수를 이용해서 cv_frames_date
라는 기사 데이터를 토큰화한 과정을 보여주는데요.
cv_frames_date %>% arrange(date) # dplyr의 arrange() 함수는 해당 변수를 순차적으로 정렬 (작은 것부터); 시간의 경우 오래된 데이터부터 정렬
## # A tibble: 2,425 x 5
## DATE COMPANY HEADLINE TEXT date
## <chr> <chr> <chr> <chr> <date>
## 1 20200~ OBS "전 세계 코로나 3천만 명 넘어 美, 백~ "【앵커】 \r\n\r\n여러분 안녕하십니까~ 2020-09-17
## 2 20200~ 국민일보 "정은경 “코로나 종식 기대 어려워 마스크~ "정은경 중앙방역대책본부장이 전 세계 코로나~ 2020-09-17
## 3 20200~ 한국일보 "'스포트라이트', 코로나 19 최초 백신~ "JTBC ‘이규연의 스포트라이트’에서 코로~ 2020-09-17
## 4 20200~ 한국일보 "코로나 백신 '입도선매' 외국은 수억 회~ "전 세계 신종 코로나바이러스 감염증(코로나~ 2020-09-17
## 5 20200~ 한국일보 "안전 불안감 점점 커지는 '코로나 백신'~ "신종 코로나바이러스 감염증(코로나19) 백~ 2020-09-17
## 6 20200~ 한국일보 "美 CDC국장 \"일반인용 코로나 백신,~ "미국 보건당국은 내년 2~3분기쯤 돼야 일~ 2020-09-17
## 7 20200~ YTN "트럼프 \"코로나 백신, 3 4주 안에 ~ "도널드 트럼프 미국 대통령은 ABC뉴스 주~ 2020-09-17
## 8 20200~ 한국일보 "\"전 국민 무료ㆍ2회 접종\"...美당~ "미국 정부가 가능하면 올 연말 또는 내년 ~ 2020-09-17
## 9 20200~ 한국일보 "유럽 코로나 확산 '3월 대유행' 넘어섰~ "유럽의 신종 코로나바이러스 감염증(코로나1~ 2020-09-18
## 10 20200~ 조선일보 "[복지4.0] 빌 게이츠가 코로나 백신 ~ "빌 게이츠 마이크로소프트(MS) 창업자가 ~ 2020-09-18
## # ... with 2,415 more rows
cv_frames_date %>% arrange(date) %>% unnest_tokens(word, HEADLINE, token = "words") %>% slice(1:30)
## # A tibble: 30 x 5
## DATE COMPANY TEXT date word
## <chr> <chr> <chr> <date> <chr>
## 1 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나1~ 2020-09-17 전
## 2 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나1~ 2020-09-17 세계
## 3 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나1~ 2020-09-17 코로나~
## 4 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나1~ 2020-09-17 3
## 5 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나1~ 2020-09-17 천만
## 6 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나1~ 2020-09-17 명
## 7 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나1~ 2020-09-17 넘어
## 8 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나1~ 2020-09-17 美
## 9 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나1~ 2020-09-17 백신
## 10 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나1~ 2020-09-17 갈등
## # ... with 20 more rows
cv_frames_date %>% arrange(date) %>% unnest_regex(word, HEADLINE, pattern=" ") %>% slice(1:30) # dplyr의 slice() 함수는 특정 범위의 행(들)만 추출해서 보여주는 기능을 함
## # A tibble: 30 x 5
## DATE COMPANY TEXT date word
## <chr> <chr> <chr> <date> <chr>
## 1 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나~ 2020-09-17 전
## 2 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나~ 2020-09-17 세계
## 3 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나~ 2020-09-17 코로나~
## 4 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나~ 2020-09-17 3천만
## 5 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나~ 2020-09-17 명
## 6 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나~ 2020-09-17 넘어
## 7 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나~ 2020-09-17 美,
## 8 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나~ 2020-09-17 백신
## 9 202009~ OBS "【앵커】 \r\n\r\n여러분 안녕하십니까. \r\n\r\n전 세계 코로나~ 2020-09-17 갈등
## 10 202009~ 국민일보 "정은경 중앙방역대책본부장이 전 세계 코로나19 누적 확진자 수가 3000만~ 2020-09-17 정은경~
## # ... with 20 more rows
이 코드는 cv_frames_date
는 데이터를 unnest_tokens()
함수를 이용하여, HEADLINE
라는 변수의 문자열을 단어 단위로 쪼개서 word
라는 새로운 변수에 저장해주라는 명령을 수행합니다. 여기에서 토큰화 단위는 즉, 문자열을 쪼개고자 하는 기본 단위는 token
이라는 인자를 “words”로 설정했죠. 이를 통해 단어 단위로 문자열을 토큰화하라는 설정이 취해진 것입니다.
unnest_tokens()
함수의 기능은 문자열을 단어 단위로 토큰화하라는 것 이외에 정규 표현식을 이용해서 텍스트를 토큰화하도록 할 수 있다는 점인데요. 따라서 텍스트를 쪼개는 토큰의 단위를 다양하게 설정할 수 있는 장점이 있습니다. 예를 들어서, 우리가 다루는 기사 데이터에 경우, 키워드에 단어들이 쉼표로 구분되어 있어 이를 기준으로 토큰화 방법이 필요하고, 이 때 unnest_regex()
는 유용한 기능을 합니다.
자, 이러한 tidytext
방식의 토큰화를 거치면, 뉴스 텍스트가 어휘 단위로 구분된 새로운 데이터를 얻게 되는데요. 이를 이용하면 어휘 빈도수 분석이 매우 용이합니다.
cv_tidy_count <- cv_frames_date %>%
unnest_regex(word, HEADLINE, pattern=" ") %>%
count(word, sort = TRUE)
cv_tidy_count
## # A tibble: 7,517 x 2
## word n
## <chr> <int>
## 1 "백신" 1943
## 2 "코로나" 1725
## 3 "접종" 539
## 4 "“코로나" 238
## 5 "\"코로나" 203
## 6 "백신," 161
## 7 "화이자" 120
## 8 "美" 99
## 9 "치료제" 85
## 10 "개발" 82
## # ... with 7,507 more rows
cv_word_count <- cv_frames_date %>%
unnest_tokens(word, HEADLINE, token="words") %>%
count(word, sort = TRUE)
cv_word_count
## # A tibble: 5,754 x 2
## word n
## <chr> <int>
## 1 코로나 2383
## 2 백신 2284
## 3 접종 683
## 4 화이자 165
## 5 1 162
## 6 2 150
## 7 美 144
## 8 명 132
## 9 3 106
## 10 개발 102
## # ... with 5,744 more rows
dplyr의 count() 함수는 해당 변수 즉 벡터를 구성하는 값들의 빈도수를 계산합니다. sort 인자는 빈도수를 내림차순을 정렬할 수 있게 합니다.
단어 빈도수가 데이터 형식으로 저장된 cv_word_count의 내용을 인덱싱
cv_word_count[1:10,]
## # A tibble: 10 x 2
## word n
## <chr> <int>
## 1 코로나 2383
## 2 백신 2284
## 3 접종 683
## 4 화이자 165
## 5 1 162
## 6 2 150
## 7 美 144
## 8 명 132
## 9 3 106
## 10 개발 102
cv_word_count[,1:2] # 데이터 프레임 인덱싱 방법, 대괄호에 쉼표 앞에 숫자 또는 그 범위는 해당 행의 범위, 쉼표 뛰는 해당 열의 범위
## # A tibble: 5,754 x 2
## word n
## <chr> <int>
## 1 코로나 2383
## 2 백신 2284
## 3 접종 683
## 4 화이자 165
## 5 1 162
## 6 2 150
## 7 美 144
## 8 명 132
## 9 3 106
## 10 개발 102
## # ... with 5,744 more rows
위의 방법으로 우리는 “코로나”와 “백신”을 포함한 기사 텍스트를 단어 단위로 토큰화한 결과의 어휘 빈도수를 확인할 수 있습니다. 여기에서 가장 많이 등장하는 단어들이 대체로 그 이유가 이해가 됩니다만, 몇 단어들은 타당하지 않거나 맥락에서 벗어나 있는 경우들도 있습니다. 또한 한자 문자열이 제거되지 않은 점도 해결해야 함.
library(wordcloud)
## Loading required package: RColorBrewer
set.seed(331)
pal <- brewer.pal(8, "Dark2")
wordcloud(words = cv_word_count$word,
freq = cv_word_count$n,
min.freq = 10,
random.order =FALSE,
rot.per = 0.1,
scale = c(3, 0.5),
colors = pal)