PROJECT/텍스트 마이닝을 활용하여 문자 대화내용 분석

konlpy 형태소 분석기 성능비교

HeyTeddy 2023. 3. 27. 22:45
반응형

보통 형태소 분석의 성능을 볼 때, 2가지를 많이 고려합니다.

 

1. 문장의 형태소 분석 품질

- 띄어쓰기가 제대로 되어있지 않은 문장

- 오탈자 때문에 불완전한 문장

 

2. 얼마나 빨리 하느냐

 

이 2가지를 고려하면서 konlpy 형태소 분석기를 만들어보겠습니다.

from konlpy.tag import Kkma
from konlpy.tag import Komoran
from konlpy.tag import Hannanum
import MeCab # 윈도우 유저들
from konlpy.tag import Okt # Twitter 형태소분석기,
import re

# 형태소 분석을 위한 객체 생성.
kkma = Kkma()
komoran = Komoran()
hannanum = Hannanum()
mecab = MeCab.Tagger()
okt = Okt()

먼저 패키지와 모듈을 불러오고, 꼬꼬마(Kkma), 코로말(Komoran), 한나눔(Hannanum), 매캡(Mecab), 오픈소스 한국어 처리기(Okt) 각각 객체를 생성합니다.

명사만 추출하는 함수를 만들어 보겠습니다.

def mecab_nouns(text):
    nouns = []
    
    # 우리가 원하는 TOKEN\tPOS의 형태를 추출하는 정규표현식.
    pattern = re.compile(".*\t[A-Z]+") 
    
    # 패턴에 맞는 문자열을 추출하여 konlpy의 mecab 결과와 같아지도록 수정.
    temp = [tuple(pattern.match(token).group(0).split("\t")) for token in mecab.parse(text).splitlines()[:-1]]
        
    # 추출한 token중에 POS가 명사 분류에 속하는 토큰만 선택.
    for token in temp:
        if token[1] == "NNG" or token[1] == "NNP" or token[1] == "NNB" or token[1] == "NNBC" or token[1] == "NP" or token[1] == "NR":
            nouns.append(token[0])
        
    return nouns

re.compile에 .*는 '전부 다'를 의미하고, \t은 '탭', [A-Z]는 알파벳 대문자 전체를 의미합니다.

splitlines을 통해 줄 단위로 문자열을 리스트로 변환하였다.

 

다음 문자열만 추출하는 함수를 만들어 보겠습니다.

def mecab_morphs(text):
    morphs = []
    
    # 우리가 원하는 TOKEN\tPOS의 형태를 추출하는 정규표현식.
    pattern = re.compile(".*\t[A-Z]+") 
    
    # 패턴에 맞는 문자열을 추출하여 konlpy의 mecab 결과와 같아지도록 수정.
    temp = [tuple(pattern.match(token).group(0).split("\t")) for token in mecab.parse(text).splitlines()[:-1]]
        
    # 추출한 token중에 문자열만 선택.
    for token in temp:
        morphs.append(token[0])
    
    return morphs

 

그 다음 파이썬 Mecab 형태소 분석 함수를 만들어 보겠습니다.

def mecab_pos(text):
    pos = []
    # 우리가 원하는 TOKEN\tPOS의 형태를 추출하는 정규표현식.
    pattern = re.compile(".*\t[A-Z]+") 
    
    # 패턴에 맞는 문자열을 추출하여 konlpy의 mecab 결과와 같아지도록 수정.
    pos = [tuple(pattern.match(token).group(0).split("\t")) for token in mecab.parse(text).splitlines()[:-1]]
        
    return pos

 

이제  만든 함수를 통해서 성능을 비교해 보겠습니다.

 

첫째로 띄어쓰기가 제대로 되어있는지?

text = "아버지가방에들어가신다"

 

꼬꼬마(kkma) 형태소 분석 결과

kkma.pos(text)
[('아버지', 'NNG'),
 ('가방', 'NNG'),
 ('에', 'JKM'),
 ('들어가', 'VV'),
 ('시', 'EPH'),
 ('ㄴ다', 'EFN')]

 

코모란(komoran) 형태소 분석 결과

komoran.pos(text)
[('아버지', 'NNG'),
 ('가방', 'NNP'),
 ('에', 'JKB'),
 ('들어가', 'VV'),
 ('시', 'EP'),
 ('ㄴ다', 'EC')]

 

한나눔(hannaum) 형태소 분석 결과

hannanum.pos(text)
[('아버지가방에들어가', 'N'), ('이', 'J'), ('시ㄴ다', 'E')]

 

매캡(mecab) 형태소 분석 결과

mecab_pos(text)
[('아버지', 'NNG'),
 ('가', 'JKS'),
 ('방', 'NNG'),
 ('에', 'JKB'),
 ('들어가', 'VV'),
 ('신다', 'EP')]

 

오픈소스 한국어 처리기(okt) 형태소 분석 결과

okt.pos(text)
[('아버지', 'Noun'), ('가방', 'Noun'), ('에', 'Josa'), ('들어가신다', 'Verb')]

 

각각 형태소마다 조금씩 다르고 특성이 있는것으로 파악됩니다.

 

문자열만 추출하는 mecab_morphs를 사용해 보겠습니다.

mecab_morphs(text)
['아버지', '가', '방', '에', '들어가', '신다']

'아버지가 방에 들어가신다'로 해석된 듯 합니다.

 

명사만 추출하는 mecab_nouns를 사용해 보겠습니다.

mecab_nouns(text)
['아버지', '방']

정확히 명사 2개만 추출했습니다.

 

 

이제는 오탈자 때문에 불완전한 문장이 주어졌을때, 각 형태소는 어떻게 되는지 비교해 보겠습니다.

text2 = "ㄱㅐㄴㅏ리가 피어있는 동산에 누워있고싶ㄷㅏ"

 

꼬꼬마(kkma) 형태소 분석 결과

print("꼬꼬마 : %s\n" % kkma.pos(text2))
꼬꼬마 : [('ㄱㅐㄴㅏ리', 'UN'), ('가', 'JKS'), ('피', 'VV'), ('어', 'ECD'), ('있', 'VXV'), ('는', 'ETD'), ('동산', 'NNG'), ('에', 'JKM'), ('눕', 'VV'), ('어', 'ECS'), ('있', 'VV'), ('고', 'ECE'), ('싶ㄷㅏ', 'UN')]

 

코모란(komoran) 형태소 분석 결과

print("코모란 : %s\n" % komoran.pos(text2))
코모란 : [('개나리', 'NNP'), ('가', 'JKS'), ('피', 'VV'), ('어', 'EC'), ('있', 'VX'), ('는', 'ETM'), ('동산', 'NNP'), ('에', 'JKB'), ('눕', 'VV'), ('어', 'EC'), ('있', 'VX'), ('고', 'EC'), ('싶', 'VX'), ('다', 'EC')]

 

한나눔(hannaum) 형태소 분석 결과

print("한나눔 : %s\n" % hannanum.pos(text2))
한나눔 : [('ㄱㅐㄴㅏ리', 'N'), ('가', 'J'), ('피', 'P'), ('어', 'E'), ('있', 'P'), ('는', 'E'), ('동산', 'N'), ('에', 'J'), ('누워있고싶ㄷㅏ', 'N')]

 

매캡(mecab) 형태소 분석 결과

print("mecab : %s\n" % mecab_pos(text2))
mecab : [('ㄱ', 'NNG'), ('ㅐㄴㅏ리가', 'UNKNOWN'), ('피', 'VV'), ('어', 'EC'), ('있', 'VX'), ('는', 'ETM'), ('동산', 'NNG'), ('에', 'JKB'), ('누워', 'VV'), ('있', 'VX'), ('고', 'EC'), ('싶', 'VX'), ('ㄷ', 'NNG'), ('ㅏ', 'UNKNOWN')]

 

오픈소스 한국어 처리기(okt) 형태소 분석 결과

print("Okt : %s\n" % okt.pos(text2))
Okt : [('ㄱㅐㄴㅏ', 'KoreanParticle'), ('리가', 'Noun'), ('피어있는', 'Verb'), ('동산', 'Noun'), ('에', 'Josa'), ('누워있고싶', 'Verb'), ('ㄷㅏ', 'KoreanParticle')]​

 

세번째로 각 형태소 별 속도를 비교해 보겠습니다.

text3 = """5G 이동통신망을 빌려 사용하는 ‘5G 알뜰폰’이 올해 도입되고, 내년부터는 의무화된다.
정부는 알뜰폰 사업자(MNVO)가 통신사(MNO)에 통신망을 빌리는 비용(도매대가)을 지난해보다 큰 폭으로 낮춰, 알뜰폰 요금 인하를 유도하기로 했다. 하지만 줄어드는 알뜰폰 시장을 살릴 수 있을지는 지켜봐야 하는 상황이다.
과학기술정보통신부는 알뜰폰 활성화 추진대책을 25일 발표했다. 알뜰폰 가입자는 800만명으로 이동통신 시장의 12%를 차지한다. 2011년 출시 뒤 저렴한 요금제로 통신비 부담을 낮춰왔다. 하지만 지난해 5월 통신 3사가 준보편제 요금을 내놓은 이후 알뜰폰 이탈 현상이 지속되고 있다.
우선 올해 안에 3개 이상의 5G 알뜰폰이 시장에 나온다. 통신사가 5G망을 알뜰폰 사업자에게 도매 제공할지 여부는 통신사 자율로 정한다. 앞서 LG유플러스는 오는 10월 알뜰폰 사업을 시작하는 KB국민은행에 5G망을 제공한다고 밝힌 바 있다. SK텔레콤와 KT도 특정 제휴사를 선택해 올해 안에 5G 알뜰폰을 내놓기로 했다.
내년부터는 5G 알뜰폰 제공이 의무화된다. 지난 22일자로 종료된 도매제공 의무제도의 유효기간을 2022년 9월22일까지 연장하는 전기통신사업법 개정안이 국회에서 통과되면, 관련 고시를 개정해 SK텔레콤의 5G망 도매제공을 의무화하겠다는 것이다.
과기정통부 관계자는 “SK텔레콤이 자사와 계약을 맺은 13개 알뜰폰 사업자에게 5G망을 의무 제공하면, 그 외 31개의 알뜰폰 사업자들이 경쟁에서 밀릴 것을 우려해 KT와 LG유플러스도 5G망을 제공하게 될 것”이라고 내다봤다.
알뜰폰 사업자가 상품을 만드는 방식 크게 2가지다. 하나는 통신사로부터 음성·문자·데이터를 도매로 사들인 뒤 이를 바탕으로 통신사보다 저렴한 요금제를 내놓는 방식(종량제 도매제공)이다. 이를 위해 정부는 도매대가 인하율을 음성 17.8%, 데이터 19.2%, 단문메시지 1.15%로, 지난해 음성 15.1%, 데이터 19.1%, 단문메시지 1.13%에 비해 높여 잡았다.
또 다른 방식은 일정비용을 통신사에 내고 통신사의 정액 요금제를 그대로 판매하면서, 그 차액의 범위에서 저렴한 요금제를 내놓는 방식(수익배분 도매제공)이다. 정부는 SK텔레콤의 준보편 요금제인 ‘T플랜 요금제’를 알뜰폰 사업자가 재판매할 수 있게 했다. 기존에 SK텔레콤이 도매제공했던 ‘밴드데이터 요금제’의 최고구간의 대가도 1.5%포인트 낮췄다.
알뜰폰 업계는 대체로 반기는 분위기지만, 알뜰폰 시장을 살릴 수 있을지에는 의구심을 갖고 있다. 업계 관계자는 “도매대가 인하율이 크고, 5G망을 제공하는 것은 긍정적”이라면서도 “수익배분 도매제공의 의무화, 설비를 가진 업체에 대한 접속료 정산 도입 등의 제도적 개선이 필요하다”고 말했다."""
%%time
print(kkma.pos(text3)[:5])

[('5', 'NR'), ('G', 'OL'), ('이동', 'NNG'), ('통신망', 'NNG'), ('을', 'JKO')]
Wall time: 555 ms

 

%%time
print(komoran.pos(text3)[:5])

[('5', 'SN'), ('G', 'SL'), ('이동', 'NNG'), ('통신망', 'NNG'), ('을', 'JKO')]
Wall time: 143 ms

 

%%time
print(hannanum.pos(text3)[:5])

[('5G', 'N'), ('이동통신망', 'N'), ('을', 'J'), ('빌리', 'P'), ('어', 'E')]
Wall time: 169 ms

 

%%time
print(mecab_pos(text3)[:5])

[('5', 'SN'), ('G', 'SL'), ('이동', 'NNG'), ('통신망', 'NNG'), ('을', 'JKO')]
Wall time: 189 ms

 

%%time
print(okt.pos(text3)[:5])

[('5', 'Number'), ('G', 'Alpha'), ('이', 'Determiner'), ('동', 'Modifier'), ('통신망', 'Noun')]
Wall time: 286 ms

코모란 형태소 속도가 가장 빠르게 나왔다

반응형