[R] 한글 형태소 분석

반응형

형태소 추출 관련 라이브러리



RcppMeCab

library(RcppMeCab)
  • pos() 함수는 문장의 형태소를 분리해주는 역할을 하는 함수 입니다.
# 한글이 깨지는 경우 `enc2utf8()` 함수를 이용해 인코딩을 UTF-8로 변경해줍니다.
test <- c("한글 테스트 입니다.")

test %>% pos()
## $`한글 테스트 입니다.`
## [1] "한글/NNG"      "테스트/NNG"    "입니다/VCP+EF" "./SF"
  • join = FALSE argument를 사용하면 품사 태그를 제외하고 형태소만 출력합니다.
test %>% 
  pos(join = FALSE)
## $`한글 테스트 입니다.`
##      NNG      NNG   VCP+EF       SF 
##   "한글" "테스트" "입니다"      "."
  • format = "data.frame" argument를 사용하면 데이터프레임 포맷으로 출력합니다.
test %>% 
  pos(format = "data.frame")
##   doc_id sentence_id token_id  token    pos subtype
## 1      1           1        1   한글    NNG        
## 2      1           1        2 테스트    NNG    행위
## 3      1           1        3 입니다 VCP+EF        
## 4      1           1        4      .     SF
  • posParallel() 함수를 사용하면 메모리를 많이 먹지만 병렬처리로 처리속도가 빠릅니다.
test %>% 
  posParallel(format = "data.frame")
##   doc_id sentence_id token_id  token    pos subtype
## 1      1           1        1   한글    NNG        
## 2      1           1        2 테스트    NNG    행위
## 3      1           1        3 입니다 VCP+EF        
## 4      1           1        4      .     SF
  • RcppMeCab 라이브러리에는 pos() 함수와 병렬처리를 위한 posParallel() 함수 두 개 정도만 존재한다고 보시면 됩니다.



KoNLP

library(KoNLP)
## Checking user defined dictionary!
  • 딕셔너리들을 설치해줄 필요가 있습니다.
useNIADic()
## Backup was just finished!
## 1213109 words dictionary was built.
useSejongDic()
## Backup was just finished!
## 370957 words dictionary was built.
  • 한글에서 명사를 추출해주는 함수는 extractNoun() 함수 입니다.
test %>% 
  extractNoun()
## [1] "한글"   "테스트"
  • 띄어쓰기가 안되어 있는 문장들은 autoSpacing = TRUE 옵션을 argument에 주면 되지만, 사실 잘 워킹하지는 않는 것 같습니다.
c("한글테스트입니다.") %>% 
  extractNoun(autoSpacing = TRUE)
## [1] "한"             "글테스트입니다"
  • 형태소를 추출하는 함수로는 SimplePos09() 함수와 SimplePos22() 함수가 있습니다.
    • SimplePos09 함수는 한나눔 형태소 분석기 기반 9개 품사로 분류
    • SimplePos22 함수는 22개로 세부 분류
test %>% 
  SimplePos09()
## $한글
## [1] "한글/N"
## 
## $테스트
## [1] "테스트/N"
## 
## $입니다
## [1] "일/P+ㅂ니다/E"
## 
## $.
## [1] "./S"
test %>% 
  SimplePos22()
## $한글
## [1] "한글/NC"
## 
## $테스트
## [1] "테스트/NC"
## 
## $입니다
## [1] "일/PV+ㅂ니다/EF"
## 
## $.
## [1] "./SF"
  • 마찬가지로 띄어쓰기가 잘 되어 있지 않은 한글에서는 쉽게 워킹하지는 않는 것 같습니다.
c("한글테스트입니다.") %>% 
  SimplePos09(autoSpacing = TRUE)
## $한
## [1] "한/N"
## 
## $글테스트입니다
## [1] "글테스트입니다/N"
## 
## $.
## [1] "./S"
  • 띄어쓰기를 어느 정도 해결해주는 라이브러리로 KoSpacing 라이브러리가 있습니다.
library(KoSpacing)
## If you install package first fime,
## Please set_env() run before using spacing()
#set_env()
#spacing("출근하기싫고퇴근은하고싶다.")



unnest_token()와 비교

text <- c("이른 아침 작은 새들 노랫소리 들려오면
언제나 그랬듯 아쉽게 잠을 깬다
창문 하나 햇살 가득 눈부시게 비쳐오고
서늘한 냉기에 재채기할까 말까 음
눈 비비며 빼꼼히 창밖을 내다보니
삼삼오오 아이들은 재잘대며 학교 가고
산책 갔다 오시는 아버지의 양손에는
효과를 알 수 없는 약수가 하나 가득 음
딸각딸각 아침 짓는 어머니의 분주함과
엉금엉금 냉수 찾는 그 아들의 게으름이
상큼하고 깨끗한 아침의 향기와
구수하게 밥 뜸드는 냄새가 어우러진
가을 아침 내겐 정말 커다란 기쁨이야
가을 아침 내겐 정말 커다란 행복이야
응석만 부렸던 내겐
파란 하늘 바라보며 커다란 숨을 쉬니
드높은 하늘처럼 내 마음 편해지네
텅 빈 하늘 언제 왔나 고추잠자리 하나가
잠 덜 깬 듯 엉성히 돌기만 비잉비잉 음
토닥토닥 빨래하는 어머니의 분주함과
동기동기 기타 치는 그 아들의 한가함이
심심하면 쳐대는 괘종시계 종소리와
시끄러운 조카들의 울음소리 어우러진
가을 아침 내겐 정말 커다란 기쁨이야
가을 아침 내겐 정말 커다란 행복이야
응석만 부렸던 내겐
가을 아침 내겐 정말 커다란 기쁨이야
가을 아침 내겐 정말 커다란 행복이야
뜬구름 쫓았던 내겐
이른 아침 작은 새들 노랫소리 들려오면
언제나 그랬듯 아쉽게 잠을 깬다
창문 하나 햇살 가득 눈부시게 비쳐오고
서늘한 냉기에 재채기할까 말까 음")

형태소 미분류

method_1 <- tibble(lyrics = text) %>% 
  unnest_tokens(
    input = lyrics,
    output = "word"
  ) %>% 
  filter(str_length(word) > 1) %>% 
  count(word, sort = TRUE) %>% 
  head(20)

method_1
## # A tibble: 20 x 2
##    word         n
##    <chr>    <int>
##  1 내겐         9
##  2 아침         9
##  3 커다란       7
##  4 가을         6
##  5 정말         6
##  6 가득         3
##  7 기쁨이야     3
##  8 하나         3
##  9 행복이야     3
## 10 그랬듯       2
## 11 깬다         2
## 12 냉기에       2
## 13 노랫소리     2
## 14 눈부시게     2
## 15 들려오면     2
## 16 말까         2
## 17 부렸던       2
## 18 분주함과     2
## 19 비쳐오고     2
## 20 새들         2
method_1 %>% glimpse()
## Rows: 20
## Columns: 2
## $ word <chr> "내겐", "아침", "커다란", "가을", "정말", "가득", "기쁨이야", "하…
## $ n    <int> 9, 9, 7, 6, 6, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2

 

RcppMeCabpos() 함수 적용

method_2 <- text %>% 
  pos(format = "data.frame") %>% 
  select(word = token, pos) %>% 
  filter(str_length(word) > 1) %>% 
  count(word, sort = TRUE) %>% 
  tibble() %>% 
  head(20)

method_2
## # A tibble: 20 x 2
##    word         n
##    <chr>    <int>
##  1 아침        10
##  2 내겐         9
##  3 커다란       7
##  4 가을         6
##  5 정말         6
##  6 하나         4
##  7 가득         3
##  8 기쁨         3
##  9 하늘         3
## 10 행복         3
## 11 그랬         2
## 12 깬다         2
## 13 냉기         2
## 14 노랫소리     2
## 15 눈부시       2
## 16 동기         2
## 17 들려오       2
## 18 부렸         2
## 19 분주         2
## 20 비쳐         2
method_2 %>% glimpse()
## Rows: 20
## Columns: 2
## $ word <chr> "아침", "내겐", "커다란", "가을", "정말", "하나", "가득", "기쁨",…
## $ n    <int> 10, 9, 7, 6, 6, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2

 

# KoNLP의 SimplePos09() 함수는 바로 적용되지 않습니다.
# 따라서 아래와 같이 list 포맷의 형태를 벡터로 변형한 후 적절한 형태로 가공하여 확인해야 합니다.
method_3 <- tibble(lyrics = text) %>% 
  SimplePos09() %>% 
  flatten_dfc() %>%  # list to vector
  pivot_longer(
    cols = everything(),
    names_to = "words",
    values_to = "value"
  ) %>% 
  separate_rows(value, sep = "\\+") %>% 
  separate(value, into = c("word", "pos"), sep = "/") %>% 
  filter(str_length(word) > 1) %>% 
  count(word, sort = TRUE) %>% 
  head(20)
## New names:
## * 이른 -> 이른...1
## * 아침 -> 아침...2
## * 작은 -> 작은...3
## * 새들 -> 새들...4
## * 노랫소리 -> 노랫소리...5
## * ...
method_3
## # A tibble: 20 x 2
##    word         n
##    <chr>    <int>
##  1 아침        10
##  2 내겐         9
##  3 커다랗       7
##  4 정말         6
##  5 ㄹ까         4
##  6 하나         4
##  7 가득         3
##  8 기쁘         3
##  9 하늘         3
## 10 행복         3
## 11 그렇         2
## 12 ㄴ다         2
## 13 냉기         2
## 14 노랫소리     2
## 15 눈부시       2
## 16 들리         2
## 17 부리         2
## 18 분주함       2
## 19 비치         2
## 20 새들         2
method_3 %>% glimpse()
## Rows: 20
## Columns: 2
## $ word <chr> "아침", "내겐", "커다랗", "정말", "ㄹ까", "하나", "가득", "기쁘",…
## $ n    <int> 10, 9, 7, 6, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2

 

비교

bind_rows(
  method_1 %>% mutate(method = "unnest_tokens()"),
  method_2 %>% mutate(method = "RcppMeCab"),
  method_3 %>% mutate(method = "KoNLP")
) %>% 
  ggplot(aes(x = reorder(word, n), y = n, fill = method)) +
  geom_bar(stat = "identity", colour = "black") +
  facet_wrap(~ method, nrow = 1, scales = "free") +
  coord_flip() +
  labs(x = "word", y = NULL)

반응형
TAGS.

Comments