Skip to content

Latest commit

 

History

History
340 lines (298 loc) · 16.2 KB

220118.md

File metadata and controls

340 lines (298 loc) · 16.2 KB

Day 99

파이썬으로 챗봇 만들기

Chapter 2

챗봇 구축에 필요한 자연어 처리의 기본적인 방법

개체명 인식(Named-Entity Recognition)

개체 인식(entity identification) 혹은 개체 추출(entity extraction)이라고도 하는 개체명 인식(NER, Named-Entity Recognitioin)은 주어진 문장에서 이름을 나타내는 개체를 찾아 기존에 정의된 범주로 분류하는 과정을 의미한다.

NER 성능은 추출 알고리즘 학습에 사용된 지식과 매우 밀접한 관련이 있으므로, 어떠한 데이터셋을 통해 학습되었는지에 따라 잘 동작할 수도, 동작하지 않을 수도 있게 된다.

개체는 사람, 위치, 조직, 날짜, 숫자 등과 같이 서로 다른 유형을 가질 수 있는데, spaCy에서는 doc 오브젝트의 .ents 속성을 통해 접근할 수 있다.

# 예제 1
my_string = u'Google has its headquaters in Mountain View, California having revenue amounted to 109.65 billion US dollars'
doc = nlp(my_string)

for ent in doc.ents:
    print(ent.text, ent.label_)
**수행결과**
Mountain View GPE
California GPE
109.65 billion US dollars MONEY

수행결과를 보면, spaCy 모델이 California를 지리적 개체로, 109.65 billion US dollars를 머니로 식별한 것을 볼 수 있다.

# 예제 2
my_string = u"Mark Zuckerberg born May 14, 1984 in New York is an American technology entrepreneur and philanthropist best known for co-founding and leading Facebook as its chairman and CEO."
doc = nlp(my_string)

for ent in doc.ents:
    print(ent.text, ent.label_)
**수행결과**
Mark Zuckerberg PERSON
May 14, 1984 DATE
New York GPE
American NORP
Facebook PRODUCT
# 예제 3
my_string = u'I usually wake up at 9:00 AM. 90% of my daytime goes in learning new things.'
doc = nlp(my_string)

for ent in doc.ents:
    print(ent.text, ent.label_)
**수행결과**
9:00 AM TIME
90% PERCENT
daytime TIME

시간과 퍼센트 정보도 추출한 것을 볼 수 있다.

TYPE DESCRIPTION
PERSON People, including fictional
NORP Nationalities of religious or political groups
FAC Buildings, airports, highways, bridges, etc.
ORG Companies, agencies, institutions, etc.
GPE Countries, cities, states
LOC Non-GPE locations, mountain ranges, bodies of water
PRODUCT Objects, vehicles, foods, etc.(not services)
EVENT Named hurricanes, battles, wars, sports events, etc.
WORK_OF_ART Titles of books, songs, etc.
LAW Named documents made into laws
LANGUAGE Any named language
DATE Absolute or relative dates ro periods
TIME Times smaller than a day
PERCENT Percentage, including "%"
MONEY Monetary values, including unit
QUANTITY Measurements, as of weight or distance
ORDINAL "first", "second", etc.
CARDINAL Numerals that do not fall under another type

개체명 인식을 사용하면 주요 개체를 파악하여 질문의 맥락을 파악하는 데 많은 도움을 얻을 수 있다.

my_string1 = u'Imagine Dragons are the best band.'            # Imagine Dragons는 고유명사로 밴드의 이름이다.
my_string2 = u'Imagine dragons come and take over the city.'  # Imagine은 상상하다를 의미하는 동사이고, dragons는 용을 의미하는 명사이다.

doc1 = nlp(my_string1)
doc2 = nlp(my_string2)

for ent in doc1.ents:
    print(ent.text, ent.label_)

doc1 오브젝트의 수행결과는 다음과 같다.

Imagine Dragons ORG

doc1에서 Imagine Dragons를 개체로 인식한 것을 확인할 수 있다. doc2를 봐보자.

for ent in doc2.ents:
    print(ent.text, ent.label_)

수행결과 아무것도 나오지 않는다. 개체로 인식하지 않은 것이다.

불용어(Stop Words)

불용어는 a, an, the, to와 같이 빈번하게 사용되는 단어로서, 다음 프로세스를 진행하기 전에 제거되길 희망하는 단어들을 의미한다. 불용어는 일반적으로 어휘로서 내포하고 있는 내용이 거의 없으므로 많은 의미를 지니지 못한다.

아래의 코드를 실행하면 spaCy에 정의되어 있는 모든 불용어를 확인할 수 있다.

from spacy.lang.en.stop_words import STOP_WORDS
print(STOP_WORDS)
**수행결과**
{'n‘t', 'keep', 'so', 'beforehand', 'some', 'each', 'get', 'who', 'could', 'six', 'every', 'never', 'but', 'whether', 'say', 'moreover', 'what', 'hundred', 'we', 'few', 'amongst', 'when', 'over', 'fifteen', 'four', 'therein', 'than', 'see', "'m", 'whose', 'an', 'full', 'by', 'nevertheless', 'only', 'how', 'move', '’d', 'two', "'s", 'whereafter', 'those', 'for', 'himself', '’ve', 'done', 'a', 'thru', 'mostly', 'most', 'n’t', 'serious', 'after', '’re', 'perhaps', 'whereas', 'meanwhile', 'whom', 'such', 'of', 'across', 'something', 'very', 'had', 'toward', 'always', 'again', 'make', 'less', 'none', 'must', 'then', 'elsewhere', 'third', '’s', 'forty', 'nobody', 'until', 'give', 'via', 'everyone', 'throughout', 'please', 'either', 'namely', 'will', 'into', 'while', 'eight', "'re", 'have', 'may', 'whatever', 'nowhere', 'ever', 'off', 'noone', 'various', 'latter', 'too', 'are', 'here', 'has', "'d", 'mine', 'also', 'regarding', 'side', 'anyway', 'made', "n't", 'seeming', 'where', '‘ll', 'front', 'as', 'were', 'otherwise', 'him', 'three', 'part', 'go', 'at', 'why', 'hers', 'they', 'becoming', 'amount', 'bottom', 'can', 'many', '‘re', 'this', 'all', 'everywhere', 'herein', 'due', 'thus', 'afterwards', "'ve", 'together', 'everything', 'just', 'although', 'back', 'sixty', 'well', 'herself', 'however', 'been', 'further', '’ll', 'among', 'alone', 'within', 'if', 'whereupon', 'both', 'whenever', '‘m', 'several', 'onto', 'do', 'top', 'name', 'out', '‘s', 'he', 'your', 'show', 'down', 'am', 'to', 'upon', '’m', 'whereby', 'anyone', "'ll", 'sometime', 'these', 'without', 'next', 'below', 'it', 'itself', 'using', 'often', 'others', 'in', 'not', 'still', 'doing', 'become', 'nothing', 'beyond', 'you', 'cannot', '‘ve', 'along', 'twenty', 'once', 'there', 'nine', 'whither', 'else', 'towards', 'yourselves', 'yet', 'should', 'put', 'under', 'per', 'no', 'which', 'much', 'during', 'she', 'thereby', 'rather', 'does', 'about', 'did', 'least', 'take', 'since', 'nor', 'with', 'that', 'or', 'therefore', 'ours', 'from', 'own', 'their', 'behind', 'already', 'wherever', 'hereupon', 'hereafter', 'other', 'eleven', 'call', 'us', 'another', 'former', 'twelve', 'somewhere', 'empty', 'besides', 'on', 'ourselves', 'indeed', 'whoever', 'thence', 'ca', 'hereby', 'first', 'almost', 'is', 'against', 'thereupon', 'hence', 'up', 'anyhow', 'any', 'though', 'because', 'neither', 'anything', 'yours', 'its', 'around', 'them', 'his', 'me', 'might', 'seem', '‘d', 'was', 'now', 'her', 'yourself', 'whole', 'except', 'the', 'themselves', 'seems', 'beside', 'one', 'ten', 'unless', 'i', 'last', 'my', 'through', 'formerly', 'seemed', 'would', 'above', 'fifty', 'five', 'anywhere', 'really', 'before', 'being', 'be', 'even', 'wherein', 'became', 'more', 'enough', 'somehow', 'our', 'quite', 'myself', 'thereafter', 'becomes', 'used', 'whence', 're', 'and', 'between', 'latterly', 'same', 'sometimes', 'someone'}

이 외에도 나만의 불용어를 정의할 수도 있으며, 필요시 기존 목록에 덮어쓸 수도 있다.
어떤 단어가 불용어인지 아닌지를 확인하려면 nlp 오브젝트의 is_stop 속성을 이용할 수 있다.

nlp.vocab[u'is'].is_stop    # True

nlp.vocab[u'hello'].is_stop # False

nlp.vocab[u'with'].is_stop  # True

챗봇이 사용자의 문장을 이해하고 필요한 프로세스를 수행하기 전에, 의미없는 단어들을 제거하는 불용어는 주어진 텍스트를 정제하는 데 매우 중요한 요소이다.

의존 구문 분석(Dependency Parsing)

spaCy는 단어(또는 복합 단어) 사이의 부모 자식 관계를 설명하고, 단어가 발생하는 순서와 무관한 구문 분석 트리를 제공한다.

# 예제 1
doc = nlp(u'Book me a flight from Bangalore to Goa')
blr, goa = doc[5], doc[7]
list(blr.ancestors)
**수행결과**
[from, flight, Book]

수행결과로부터 사용자가 Bangalore에서 Goa로 출발하는 항공편을 예약하려고 한다는 것을 알 수 있다.

goa.ancestors 오브젝트를 통해 goa의 ancestor 목록은 다음과 같다.

list(goa.ancestors)
**수행결과**
[to, flight, Book]

수행결과로부터 사용자가 고아로 가는 항공편을 예약하려 하는 것을 알 수 있다.

의존 구문 분석에서 Ancestors란 무엇인가?
Ancestors는 한 문장에서, 특정 토큰과 문맥적으로 관련 있는 토큰들 중에 가장 우측에 위치한 토큰을 의미한다. doc 오브젝트의 ancestors 속성을 이용하면 ancestors 목록을 출력할 수 있다.

list(doc[4].ancestors)
**수행결과**
[flight, Book]

doc 오브젝트의 어떤 단어가 다른 단어의 ancestor인지 여부를 확인하기 위해서는 is_ancestor를 사용하면 된다.

doc[3].is_ancestor(doc[5]) # True

doc[3]인 flight가 doc[5]인 Bangalore의 ancestor이기 때문에 True를 반환한다.

# 예제 1
doc = nlp(u'Book a table at the restaurant and the taxi to the hotel')
tasks = doc[2], doc[8]         # (table, taxi)
tasks_target = doc[5], doc[11] # (restaurant, hotel)

for task in tasks_target:
    for tok in task.ancestors:
        if tok in tasks:
            print('Booking of {} belongs to {}'.format(tok, task))
            break
**수행결과**
Booking of table belongs to restaurant
Booking of taxi belongs to hotel

레스토랑에 한 자리 예약과, 호텔로 가는 택시 예약을 잘 처리한 것을 볼 수 있다.

의존 구문 분석에서 Children이란 무엇인가?
Children은 특정 토큰이 문맥적으로 의존하고 있는 단어들을 의미한다. children 속성을 이용하면 특정 단어의 children을 파악할 수 있다.

의존 구문 분석의 인터렉티브(interactive) 시각화
spaCy는 Doc 또는 Doc 오브젝트 목록을 displayCy에 전달하고 관련 웨 서버를 기동할 수 있는 시각화 모듈을 갖고 있다.

from spacy import displacy
doc = nlp(u'Book a table at the restaurant and the taxi to the hotel')
displacy.serve(doc, style='dep')

위의 코드를 수행하고 http://localhost:5000/ 으로 이동하면 시각화된 의존 구문 분석을 볼 수 있다.

Dependency_Parsing_visualize

"What are some places to visit in Berlin and stay in Lubeck?" 이 질문에 대한 의존 구문 분석을 해보자

doc = nlp(u'What are some places to visit in Berlin and stay in Lubeck')

places = doc[7], doc[11] # (Berlin, Lubeck)
actions = doc[5], doc[9] # (visit, stay)

for place in places:
    for tok in place.ancestors:
        if tok in actions:
            print('User is referring : {} to {}'.format(place, tok))
            break
**수행결과**
User is referring : Berlin to visit
User is referring : Lubeck to stay

의존 구문 분석은 사용자 질문의 인텐트를 이해하기 쉽게 만들고, 그것을 바탕으로 다음에 필요한 사항을 예상하고 질문에 대한 응답을 형성하는데 도움을 준다.

챗봇이 의존 구문 분석이 필요한 이유는 무엇인가?
사용자가 챗봇을 통해 입력한 질문의 의미를 파악하는 것은 매우 중요하다. 챗봇이 학습하지 못한 질문에 대해서도 그 의미를 잘 파악해야만, 엉뚱한 대답을 하는 일이 없을 것이기 때문이다.

의존 구문 분석의 이점은 다음과 같다.

  • 문법적으로 올바른 문장의 단어들 간의 관계를 찾을 수 있다.
  • 문장 경계 탐지에 이용할 수 있다.
  • 사용자가 두 가지 내용을 한 번에 말하고 있는지 확인할 때 매우 유용하다.

Noun Chunks

Noun Chunks 혹은 NP-chunking는 기본적으로 명사 구(pharases)를 말한다. 명사를 포함하는 어떠한 구를 의미할 수도 있으며, 어떤 고유한 명사를 설명할 수 있는 단어들의 집합이라고도 할 수 있다.

# 예제 1
doc = nlp(u'Boston Dynamics is gearing up to produce thousands of robot dogs')
list(doc.noun_chunks)
**수행결과**
[Boston Dynamics, thousands, robot dogs]

Noun Chunk를 확인하는 것 외에도 Spacy는 속성을 이용하여 부가적인 기능들을 제공한다.

# 예제 2
doc = nlp(u'Deep learning cracks the code of messenger RNAs and protein-coding potential')
for chunk in doc.noun_chunks:
    print(chunk.text, chunk.root.text, chunk.root.dep_, chunk.root.head.text)

수행결과

TEXT ROOT.TEXT ROOT.DEP_ ROOT.HEAD.TEXT
Deep learning cracks cracks ROOT
the code code dobj cracks
messengerRNAs RNAs pobj of
protein-coding potential potential conj RNAs

각 컬럼의 값들이 의미하는 것

Column 의미
Text Text of the original noun chunk
Root text Text of the original word that connects the noun chunk with remaining parse
Root dep Dependency relation that connects the root to its head
Root head text Text of the root token's head

유사도 확인(Finding Similarity)

두 단어가 얼마나 유사한지를 찾는 것이 중요한 경우가 있는데, 그때는 두 단어의 형태적 유사성뿐 아니라, 논리적으로 두 단어가 얼마만큼 관계가 있는지도 고려해야 한다.

spaCy는 GloVe(Global Vectors for Word Representation) 알고리즘을 통해 얻어낸 단어 벡터 값을 이용하여 두 단어 사이의 유사성을 찾는다.

토큰의 vector 속성을 이용하여 볼 수 있다.

doc = nlp(u'How are you doing today?')
for token in doc:
    print(token.text, token.vector[:5])
**수행결과**
How [ 1.6213789  -0.67405385 -1.2062876  -0.45594382  0.7263222 ]
are [-1.202954   -0.23346642 -0.5003196  -0.8712524   0.28610075]
you [ 0.22592056  0.05933985  0.2325799  -1.6726606   0.867588  ]
doing [-0.5363278   1.4226953  -0.05632719  1.3783768   0.41547692]
today [0.18322621 0.61413527 0.5293835  0.9042445  1.2848973 ]
? [-0.06557187 -0.21330678  0.04028244 -0.02445459 -1.6477726 ]

각각의 벡터값들이 그 단어를 고유하게 표현하는 매우 의미있는 값이다.

유사도 확인을 위해선 .similarity()를 사용하면 된다.

여기서부터 모델을 en_core_web_sm에서 en_core_web_lg로 변경했다.

# 예제
hello_doc = nlp('hello')
hi_doc = nlp('hi')
hella_doc = nlp('hella')
print(hello_doc.similarity(hi_doc))
print(hello_doc.similarity(hella_doc))
0.7628511777339915
0.2623687664967382

hello라는 단어를 보면 hella와 a라는 단어 차이만 있을 뿐이지만, hi라는 단어와 더 연관성이 있고 유사한 것을 확인할 수 있다.

문장의 예시

# 예제
GoT_str1 = nlp('When will next season of Game of Thrones be releasing?')
GoT_str2 = nlp('Game of Thrones next season release date?')
GoT_str1.similarity(GoT_str2)
**수행결과**
0.9440999059835806

두 문장 사이의 유사성은 94% 정도인데 매우 높은 것을 알 수 있다. 유사도 확인은 챗봇 구현 중 커스텀 코드를 작성하는 데에도 많은 도움이 된다.

# 예제
example_doc = nlp('car truck google')

for t1 in example_doc:
    for t2 in example_doc:
        similarity_perc = int(t1.similarity(t2) * 100)
        print('Word {} is {}% similar to word {}'.format(t1.text, similarity_perc, t2.text))
**수행결과**
Word car is 100% similar to word car
Word car is 71% similar to word truck
Word car is 23% similar to word google
Word truck is 71% similar to word car
Word truck is 100% similar to word truck
Word truck is 15% similar to word google
Word google is 23% similar to word car
Word google is 15% similar to word truck
Word google is 100% similar to word google

챗봇을 만들 떄 유사성을 찾는 것은 다음과 같은 상황에 매우 유용할 수 있다.

  • 추천을 위한 챗봇을 구축할 때
  • 중복을 제거할 때
  • 철자 오류 확인 기능을 개발할 때