6 분 소요


형태소 분석

  • konlpy: korean natural language processing python (pip install konlpy)
  • JPype: java 라이브러리를 python에서 사용 (pip install JPype1-1.1.2-cp38-cp38-win_amd64.whl) python3.8용
In [1]:
import konlpy
konlpy.__version__
Out [1]:
'0.6.0'
In [2]:
from konlpy.tag import Okt
In [3]:
okt = Okt()
tokens = okt.morphs("나는 자연어 처리를 배우고 있어요, 너무 신기해요")
tokens
Out [3]:
['나', '는', '자연어', '처리', '를', '배우고', '있어요', ',', '너무', '신기해요']
In [4]:
"나는 자연어 처리를 배우고 있어요, 너무 신기해요".split()
Out [4]:
['나는', '자연어', '처리를', '배우고', '있어요,', '너무', '신기해요']

split()으로는 처리를, 처리가, 처리는 모두 다르게 인식하여 ‘처리’라는 단어를 구분하지 못한다.

형태소 단위로 나눔 - 조사들을 찾아서 때어냄 -> 시간이 오래 걸림

영어 형태소 분석기

In [5]:
import nltk # 영어에서 많이 사용되는 형태소 분석기
# nltk.download('punkt')

word_tokenize

In [6]:
from nltk.tokenize import word_tokenize
In [7]:
text = '''"Wagner soldiers openly advance under fire towards us even if they're littering the land with their bodies, even if out of 60 people in their platoon only 20 are left.
It's very difficult to hold against such an invasion. We weren't prepared for that, and we're learning now," Commander Skala says.'''
In [8]:
print(word_tokenize(text))
Out [8]:
['``', 'Wagner', 'soldiers', 'openly', 'advance', 'under', 'fire', 'towards', 'us', 'even', 'if', 'they', "'re", 'littering', 'the', 'land', 'with', 'their', 'bodies', ',', 'even', 'if', 'out', 'of', '60', 'people', 'in', 'their', 'platoon', 'only', '20', 'are', 'left', '.', 'It', "'s", 'very', 'difficult', 'to', 'hold', 'against', 'such', 'an', 'invasion', '.', 'We', 'were', "n't", 'prepared', 'for', 'that', ',', 'and', 'we', "'re", 'learning', 'now', ',', "''", 'Commander', 'Skala', 'says', '.']

WordPunctTokenizer

In [9]:
from nltk.tokenize import WordPunctTokenizer
from keras.preprocessing.text import text_to_word_sequence
In [10]:
print(WordPunctTokenizer().tokenize(text)) # 위와 달리 '를 분해.. 다양한 tokenize가 존재
Out [10]:
['"', 'Wagner', 'soldiers', 'openly', 'advance', 'under', 'fire', 'towards', 'us', 'even', 'if', 'they', "'", 're', 'littering', 'the', 'land', 'with', 'their', 'bodies', ',', 'even', 'if', 'out', 'of', '60', 'people', 'in', 'their', 'platoon', 'only', '20', 'are', 'left', '.', 'It', "'", 's', 'very', 'difficult', 'to', 'hold', 'against', 'such', 'an', 'invasion', '.', 'We', 'weren', "'", 't', 'prepared', 'for', 'that', ',', 'and', 'we', "'", 're', 'learning', 'now', ',"', 'Commander', 'Skala', 'says', '.']

text_to_word_sequence

In [11]:
print(text_to_word_sequence(text))
Out [11]:
['wagner', 'soldiers', 'openly', 'advance', 'under', 'fire', 'towards', 'us', 'even', 'if', "they're", 'littering', 'the', 'land', 'with', 'their', 'bodies', 'even', 'if', 'out', 'of', '60', 'people', 'in', 'their', 'platoon', 'only', '20', 'are', 'left', "it's", 'very', 'difficult', 'to', 'hold', 'against', 'such', 'an', 'invasion', 'we', "weren't", 'prepared', 'for', 'that', 'and', "we're", 'learning', 'now', 'commander', 'skala', 'says']

sent_tokenize

In [12]:
from nltk.tokenize import sent_tokenize
In [13]:
sent_tokenize(text) # 문장 단위 분리 -> 챗봇 등에 사용
Out [13]:
['"Wagner soldiers openly advance under fire towards us even if they\'re littering the land with their bodies, even if out of 60 people in their platoon only 20 are left.',
 "It's very difficult to hold against such an invasion.",
 'We weren\'t prepared for that, and we\'re learning now," Commander Skala says.']

kss

In [14]:
import kss
In [15]:
text = "딥러닝 자연어 처리는 흥미롭습니다. 그런데 재미는 없을 수도 있습니다. 특히 일상 언어는 너무 복잡합니다."
kss.split_sentences(text)
Out [15]:
[Kss]: Because there's no supported C++ morpheme analyzer, Kss will take pecab as a backend. :D
For your information, Kss also supports mecab backend.
We recommend you to install mecab or konlpy.tag.Mecab for faster execution of Kss.
Please refer to following web sites for details:
- mecab: https://cleancode-ws.tistory.com/97
- konlpy.tag.Mecab: https://uwgdqo.tistory.com/363


['딥러닝 자연어 처리는 흥미롭습니다.', '그런데 재미는 없을 수도 있습니다.', '특히 일상 언어는 너무 복잡합니다.']
  • tokenizer 선택 기준: 원하는 파싱(Parsing) 결과가 나오는가? 처리 속도는 적절한가?

한국어 형태소 분석기

mecab: 속도는 빠르나 윈도우 환경과 호환성이 좋지않음(colab에서 사용 권장)

In [16]:
from konlpy.tag import Okt, Kkma, Komoran
In [17]:
okt = Okt()
kkma = Kkma()
kom = Komoran()
In [18]:
text = '열심히 코딩한 당신, 잠도 잘 자고 일하세요'

Okt

In [19]:
print('---- OKT ----') # 활용형에 취약 - 동사, 형용사에서 주로... 명사를 다루는데 문제 없음
print('형태소 분석: ', okt.morphs(text))
print('품사 태깅: ', okt.pos(text))
print('명사 분석: ', okt.nouns(text))
Out [19]:
---- OKT ----
형태소 분석:  ['열심히', '코딩', '한', '당신', ',', '잠도', '잘', '자고', '일', '하세요']
품사 태깅:  [('열심히', 'Adverb'), ('코딩', 'Noun'), ('한', 'Josa'), ('당신', 'Noun'), (',', 'Punctuation'), ('잠도', 'Noun'), ('잘', 'Verb'), ('자고', 'Noun'), ('일', 'Noun'), ('하세요', 'Verb')]
명사 분석:  ['코딩', '당신', '잠도', '자고', '일']

In [20]:
print('---- OKT ----') # norm: 단어들을 정규화 # stem: 오타도 수정
print('형태소 분석: ', okt.morphs(text, norm=True, stem=True))
print('품사 태깅: ', okt.pos(text, norm=True, stem=True))
print('명사 분석: ', okt.nouns(text))
Out [20]:
---- OKT ----
형태소 분석:  ['열심히', '코딩', '한', '당신', ',', '잠도', '자다', '자고', '일', '하다']
품사 태깅:  [('열심히', 'Adverb'), ('코딩', 'Noun'), ('한', 'Josa'), ('당신', 'Noun'), (',', 'Punctuation'), ('잠도', 'Noun'), ('자다', 'Verb'), ('자고', 'Noun'), ('일', 'Noun'), ('하다', 'Verb')]
명사 분석:  ['코딩', '당신', '잠도', '자고', '일']

Kkma

In [21]:
print('---- KKMA ----')
print('형태소 분석: ', kkma.morphs(text))
print('품사 태깅: ', kkma.pos(text))
print('명사 분석: ', kkma.nouns(text))
Out [21]:
---- KKMA ----
형태소 분석:  ['열심히', '코딩', '하', 'ㄴ', '당신', ',', '잠', '도', '잘', '자', '고', '일하', '세요']
품사 태깅:  [('열심히', 'MAG'), ('코딩', 'NNG'), ('하', 'XSV'), ('ㄴ', 'ETD'), ('당신', 'NP'), (',', 'SP'), ('잠', 'NNG'), ('도', 'JX'), ('잘', 'MAG'), ('자', 'VV'), ('고', 'ECE'), ('일하', 'VV'), ('세요', 'EFN')]
명사 분석:  ['코딩', '당신', '잠']

Komoran

In [22]:
print('---- Komoran ----')
print('형태소 분석: ', kom.morphs(text))
print('품사 태깅: ', kom.pos(text))
print('명사 분석: ', kom.nouns(text))
Out [22]:
---- Komoran ----
형태소 분석:  ['열심히', '코', '딩', '하', 'ㄴ', '당신', ',', '잠도', '잘', '자', '고', '일', '하', '시', '어요']
품사 태깅:  [('열심히', 'MAG'), ('코', 'NNG'), ('딩', 'MAG'), ('하', 'XSV'), ('ㄴ', 'ETM'), ('당신', 'NNP'), (',', 'SP'), ('잠도', 'NNP'), ('잘', 'MAG'), ('자', 'VV'), ('고', 'EC'), ('일', 'NNG'), ('하', 'XSV'), ('시', 'EP'), ('어요', 'EC')]
명사 분석:  ['코', '당신', '잠도', '일']

한국어 전처리 패키지

자동 띄어쓰기

In [23]:
# !pip install git+https://github.com/haven-jeon/PyKospacing --user
# tensorflow 2.9.3 설치됨
In [24]:
from pykospacing import Spacing
In [25]:
text = '''대한(大寒)보다 더 춥다는 소한(小寒)이자 금요일인 6일 오후부터 토요일인 7일까지 눈이 내리겠다. 강원권에서는 최대 10㎝, 수도권에는 최대 8㎝가 쌓이겠다. 서해안과 남해안에는 비가 함께 내릴 수 있다. 눈은 7일 낮 대부분 그칠 전망이다.'''
In [26]:
new_text = text.replace(' ', '')
new_text
Out [26]:
'대한(大寒)보다더춥다는소한(小寒)이자금요일인6일오후부터토요일인7일까지눈이내리겠다.강원권에서는최대10㎝,수도권에는최대8㎝가쌓이겠다.서해안과남해안에는비가함께내릴수있다.눈은7일낮대부분그칠전망이다.'
In [27]:
s = Spacing()
recon_text = s(new_text)
print(text)
print(recon_text)
Out [27]:
1/1 [==============================] - 1s 821ms/step
대한(大寒)보다 더 춥다는 소한(小寒)이자 금요일인 6일 오후부터 토요일인 7일까지 눈이 내리겠다. 강원권에서는 최대 10㎝, 수도권에는 최대 8㎝가 쌓이겠다. 서해안과 남해안에는 비가 함께 내릴 수 있다. 눈은 7일 낮 대부분 그칠 전망이다.
대한(大寒)보다 더 춥다는 소한(小寒)이 자금요일인 6일 오후부터 토요일인 7일까지 눈이 내리겠다. 강원권에서는 최대 10㎝, 수도권에는 최대 8㎝가 쌓이겠다. 서해안과 남해안에는 비가 함께 내릴 수 있다. 눈은 7일 낮 대부분 그칠 전망이다.

In [28]:
import tensorflow as tf
tf.__version__
Out [28]:
'2.9.3'

맞춤법 검사

In [29]:
# !pip install git+https://github.com/ssut/py-hanspell.git
# 또는 !pip install py-hanspell
In [30]:
from hanspell import spell_checker
In [31]:
text_kr = "마춤법 틀리면 외 않되? 내맘대로 쓰면돼지! 이따가 시간되?"
text_ok = spell_checker.check(text_kr)
text_ok.checked
Out [31]:
'맞춤법 틀리면 왜 안돼? 내 맘대로 쓰면 되지! 이따가 시간 돼?'

이모티콘 축약

반복문자 정제

In [32]:
# !pip install soynlp
In [33]:
from soynlp.normalizer import *
In [34]:
text = '앜ㅋㅋㅋㅋㅋㅋㅋㅋ이김밥존맛탱ㅋㅋㅋㅋ쿠쿠쿠ㅜㅜㅋㅋ쿠쿠루삥뽕'
emoticon_normalize(text)
Out [34]:
'아ㅋㅋ김밥존맛ㅋㅋㅜ쿠쿠ㅜㅜㅋㅋㅋㅜ쿠루삥뽕'
In [35]:
emoticon_normalize(text, num_repeats=3)
Out [35]:
'아ㅋㅋㅋ김밥존맛ㅋㅋㅋㅜ쿠쿠ㅜㅜㅋㅋㅋㅜ쿠루삥뽕'

불용어(Stopwords) 처리

영어 불용어

In [36]:
import nltk
# nltk.download("stopwords")
# nltk.download("punkt")
In [37]:
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from konlpy.tag import Okt
In [38]:
# 영어에서 불용어 처리되는 단어들
stop_words_list = stopwords.words("english")
len(stop_words_list)
Out [38]:
179
In [39]:
stop_words_list[:10]
Out [39]:
['i', 'me', 'my', 'myself', 'we', 'our', 'ours', 'ourselves', 'you', "you're"]
In [40]:
test = "Tottenham head coach Antonio Conte says he is happy that Harry Kane & Son Heung-min both scored in his side's 4-0 victory over Crystal Palace in the Premier League."
test = test.lower()
token_1 = word_tokenize(test)
print(token_1)
Out [40]:
['tottenham', 'head', 'coach', 'antonio', 'conte', 'says', 'he', 'is', 'happy', 'that', 'harry', 'kane', '&', 'son', 'heung-min', 'both', 'scored', 'in', 'his', 'side', "'s", '4-0', 'victory', 'over', 'crystal', 'palace', 'in', 'the', 'premier', 'league', '.']

In [41]:
# 불용어 제거
token_2 = []
for word in token_1:
    if word not in stop_words_list:
        token_2.append(word)
print(token_2)
Out [41]:
['tottenham', 'head', 'coach', 'antonio', 'conte', 'says', 'happy', 'harry', 'kane', '&', 'son', 'heung-min', 'scored', 'side', "'s", '4-0', 'victory', 'crystal', 'palace', 'premier', 'league', '.']

In [42]:
my_stop_words = ['antonio', 'conte']
In [43]:
# 커스텀 불용어 제거
token_3 = []
for word in token_2:
    if word not in my_stop_words:
        token_3.append(word)
print(token_3)
Out [43]:
['tottenham', 'head', 'coach', 'says', 'happy', 'harry', 'kane', '&', 'son', 'heung-min', 'scored', 'side', "'s", '4-0', 'victory', 'crystal', 'palace', 'premier', 'league', '.']

  • 욕설 불용어 처리
In [44]:
test = "Drop your weapon. Fuck you ass hole. go the hell mother fucker"
test = test.lower()
token_1 = word_tokenize(test)
print(token_1)

token_2 = []
for word in token_1:
    if word not in stop_words_list:
        token_2.append(word)
print(token_2)

my_stop_words = ['fuck', 'ass', 'hole', 'fucker']

token_3 = []
for word in token_2:
    if word not in my_stop_words:
        token_3.append(word)
print(token_3)
Out [44]:
['drop', 'your', 'weapon', '.', 'fuck', 'you', 'ass', 'hole', '.', 'go', 'the', 'hell', 'mother', 'fucker']
['drop', 'weapon', '.', 'fuck', 'ass', 'hole', '.', 'go', 'hell', 'mother', 'fucker']
['drop', 'weapon', '.', '.', 'go', 'hell', 'mother']

한국어 불용어

In [45]:
okt = Okt()
text = '이 따위 물건을 팔고도 돈을 처먹냐 그냥 줘도 아깝다. 하자 있는 물건을 어떻게 쓰냐. 병신아'
word_token = okt.morphs(text)
print(word_token)
Out [45]:
['이', '따위', '물건', '을', '팔고', '도', '돈', '을', '처', '먹냐', '그냥', '줘도', '아깝다', '.', '하자', '있는', '물건', '을', '어떻게', '쓰냐', '.', '병신', '아']

In [46]:
len('이'), len('물건')
Out [46]:
(1, 2)
In [47]:
token_ko_2 = []
for word in word_token:
    if len(word) > 1:
        token_ko_2.append(word)
print(token_ko_2)
Out [47]:
['따위', '물건', '팔고', '먹냐', '그냥', '줘도', '아깝다', '하자', '있는', '물건', '어떻게', '쓰냐', '병신']

In [48]:
word_token_nouns = okt.nouns(text)
print(word_token_nouns)
Out [48]:
['이', '따위', '물건', '팔고', '돈', '처', '그냥', '하자', '물건', '병신']

In [49]:
my_stop_words_ko = ['병신']
In [50]:
token_ko_3 = []
for word in token_ko_2:
    if word not in my_stop_words_ko:
        token_ko_3.append(word)
print(token_ko_3)
Out [50]:
['따위', '물건', '팔고', '먹냐', '그냥', '줘도', '아깝다', '하자', '있는', '물건', '어떻게', '쓰냐']

In [51]:
word_token_nouns_2 = []
for word in word_token_nouns:
    if word not in my_stop_words_ko:
        word_token_nouns_2.append(word)
print(word_token_nouns_2)
Out [51]:
['이', '따위', '물건', '팔고', '돈', '처', '그냥', '하자', '물건']

Reference

태그: ,

카테고리:

업데이트:

댓글남기기