#!/usr/bin/env python # coding: utf-8 # # **자연어 처리 바이블** # - **[정규표현식 시작하기](https://wikidocs.net/4308) | [정규표현식 고급편](https://wikidocs.net/4309)** # # ```java # pip install konlpy # pip install pororo # bash <(curl -s https://raw.githubusercontent.com/konlpy/konlpy/master/scripts/mecab.sh) # ``` # ## **1 구문분석** # ### **Tokeninzer** # In[1]: from konlpy.tag import Kkma from konlpy.tag import Okt from konlpy.tag import Mecab Mecab().pos("아이들이 케이크를 먹었다") # In[2]: from pororo import Pororo Pororo.available_models("collocation") ner = Pororo(task="ner", lang="ko") ner("마이클 제프리 조던(영어: Michael Jeffrey Jordan, 1963년 2월 17일 ~ )농구선수이다.") # ## **2 NLTK 를 활용한 구조 구문분석** # ### **01 NLTK 패키지를 활용한 규칙기반 구조 구문분석** # In[3]: import nltk grammar = nltk.CFG.fromstring(""" S -> NP VP NP -> NN XSN JK | NN JK VP -> NP VP | VV EP EF NN -> '아이' | '케이크' XSN -> '들' JK -> '이' | '를' VV -> '먹' EP -> '었' EF -> '다' """) parser = nltk.ChartParser(grammar) parser # In[4]: texts = "아이들이 케이크를 먹었다" from konlpy.tag import Mecab tokens = Mecab().pos("아이들이 케이크를 먹었다") sentence = [_[0] for _ in tokens] print(", ".join(sentence)) for tree in parser.parse(sentence): print(tree) # ### **02 Spacy 를 이용한 의존 구문 분석** # ```r # ! pip install spacy # ! python -m spacy download en # ``` # - Spacy 모델은 문장을 token들로 구성된 document로 처리한다. # - 각 token에는 품사, 의존 관계, 개체명 정보 등이 태깅된다. # - token.text: token 문자열 # - token.dep_: token과 token의 지배소 간의 의존 관계 유형 # - token.head: 지배소 token # # # In[5]: import spacy # 영어 multi-task 통계 모델 nlp = spacy.load('en_core_web_sm') doc = nlp('The fat cat sat on the mat') for token in doc: print(token.text, token.dep_, token.head.text) # In[6]: from spacy import displacy # Jupyter, Colab 등에서 동작 displacy.render(doc, style='dep', jupyter=True) # ## **3 단어 의미 중의성 문제의 해결** # ### **01 Lesk 알고리즘을 이용한 단어 중의성 해소** # In[7]: import nltk nltk.download('wordnet') nltk.download('punkt') nltk.download('stopwords') from nltk.corpus import wordnet from nltk import word_tokenize from nltk.corpus import stopwords import sys # In[8]: # 단어와 문장에 나타난 단어에 대해 Best Sense 추출 def disambiguate(word, sentence, stopwords): # Best sense 를 얻기위한 Lesk 알고리즘을 작성 word_senses = wordnet.synsets(word) # Assume that first sense is most freq best_sense = word_senses[0] max_overlap = 0 context = set(word_tokenize(sentence)) for sense in word_senses: signature = tokenized_gloss(sense) overlap = compute_overlap(signature, context, stopwords) if overlap > max_overlap: max_overlap = overlap best_sense = sense return best_sense # In[9]: # sense의 definition에 대한 모든 token 추출 def tokenized_gloss(sense): tokens = set(word_tokenize(sense.definition())) for example in sense.examples(): tokens.union(set(word_tokenize(example))) return tokens # In[10]: # 겹치는 단어의 비교 def compute_overlap(signature, context, stopwords): gloss = signature.difference(stopwords) return len(gloss.intersection(context)) # In[11]: # NLTK에서 지정한 영어 불용어 처리 # ex) i, my, they stopwords = set(stopwords.words('english')) sentence = ("They eat a meal") context = set(word_tokenize(sentence)) word = 'eat' print("Word :", word) syn = wordnet.synsets('eat')[1] print("Sense :", syn.name()) print("Definition :", syn.definition()) print("Sentence :", sentence) signature = tokenized_gloss(syn) print(signature) print(compute_overlap(signature, context, stopwords)) print("Best sense: ", disambiguate(word, sentence, stopwords)) # ## **4 NLTK를 이용한 개체명 인식** # ### **01 Lesk 알고리즘을 이용한 단어 중의성 해소** # In[12]: # -*- coding:utf-8 -*- import nltk nltk.download('punkt') nltk.download('words') nltk.download('averaged_perceptron_tagger') nltk.download('maxent_ne_chunker') # In[13]: sentence = "Prime Minister Boris Johnson had previously said the UK would leave by 31 October." tokens = nltk.word_tokenize(sentence) print(tokens) # In[14]: tagged = nltk.pos_tag(tokens) print(tagged) # In[15]: entities = nltk.chunk.ne_chunk(tagged) print(entities) # ## **5 N-Gram 언어 모델로 문장 생서하기** # ### **01 Lesk 알고리즘을 이용한 단어 중의성 해소** # In[22]: texts = "마이클 제프리 조던(Michael Jeffrey Jordan) 농구선수이다." from konlpy.tag import Mecab from nltk.util import ngrams tokens = Mecab().pos(texts) tokens = ["/".join(_) for _ in tokens] # 토큰을 N-gram의 형태로 바꾸어준다. # ngrams 함수의 두 번째 인자로 N값을 지정할 수 있다. trigram = ngrams(tokens, 3) [_ for _ in trigram] # In[23]: # padding 을 통해 입력 데이터에 문장의 시작과 끝을 알리는 토큰을 추가 bigram = ngrams( tokens, 2, pad_left=True, left_pad_symbol="", pad_right=True, right_pad_symbol="" ) print("bigrams with padding: ") for b in bigram: print(b) # In[25]: # 다운로드 받은 데이터셋을 읽고 인덱스와 라벨을 제외한 텍스트 부분만 가져온다. # codecs 패키지는 대용량 파일을 조금씩 읽을 수 있게 해준다. import codecs with codecs.open("data/ratings_train.txt", encoding='utf-8') as f: data = [line.split('\t') for line in f.read().splitlines()] # \n 제외 data = data[1:] # header 제외 # 총 15만개의 문장으로 이루어진 데이터셋임을 알 수 있다. docs = [row[1] for row in data] # 텍스트 부분만 가져옴 print(f"데이터셋: {data[:10]}\n텍스트 데이터: {docs[:5]}\n문장 개수: {len(docs)}") # In[28]: from tqdm import tqdm # 토큰화한 텍스트 데이터의 bigram을 모두 리스트에 추가한다. sentences = [] for _ in tqdm(docs): tokens = ["/".join(_) for _ in _] bigram = ngrams(tokens, 2, pad_left=True, pad_right=True, left_pad_symbol="", right_pad_symbol="") sentences += [t for t in bigram] print(sentences[:5])