데이터 분석/자연어처리

4. 자연어 처리 - Word Embedding(WordNet)

Jerry Jun 2021. 2. 3. 15:45
728x90

Word Sense

한글 단어들은 동음이의어가 참 많다.

'차' 를 예로 들어보자.

  • 잎이나 뿌리 등을 우려 마시는 것
  • 바퀴가 달린 운송수단
  • 짐을 실어 그 분량을 세는 단위
  • 장기 말 중 '車'
  • 빼기의 다른 말
  • 몇 주차... 등의 기간을 나타내는 말 etc...

이 때문에 우리는 다의어(Polysemy)와 동형어(Homonym)를 알아야 한다.

  • 다의어(Polysemy) : 근본의미 이외에도 다른 뜻으로도 쓰는 단어
  • 동형어(Homonym) : 단어의 형태만 같을 뿐 서로 전혀 다른 의미를 지님

이런 경우를 처리하기 위해 필요한 것이 Word Sense Disambiguation(WSD) 이다.

 


WordNet

  • 어휘 분류 사전
  • 상위어(Hypernym)나 하위어(Hyponym)에 대한 것이 잘 정리되어 있는 것이 특징
  • NLTK Library OR Download(http://wordnetweb.princeton.edu/perl/webwn) - english
  • KorLex(korlex.pusan.ac.kr) OR Korean WordNet(wordnet.kaist.ac.kr) - korean

WordNet 은 계층 구조를 가지고 있다. 예를 들어 Person(사람) 이라는 단어의 하위 계층에 Student(학생) 이나 Singer(가수) 등이 있을 것입니다. 이러한 계층 구조를 통해 각 두 단어들의 거리를 계산하여 유사도를 확인할 수 있습니다.

 

이제 간단한 WordNet 실습을 해보겠습니다.

!pip install nltk==3.2.5

import nltk
nltk.download('wordnet')

from nltk.corpus import wordnet as wn

저의 경우에는 nltk 3.2.5 버전을 설치하였습니다. 그리고 다음과 같이 wordnet을 다운받고 선언하였습니다.

 

 

wn.synsets('people')
------------------------------------
[Synset('people.n.01'),
 Synset('citizenry.n.01'),
 Synset('people.n.03'),
 Synset('multitude.n.03'),
 Synset('people.v.01'),
 Synset('people.v.02')]

예시 단어 'people' 에 대한 동의어 집합을 출력하였습니다.

 

wn.synsets('people')[0].hypernyms()
-----------------------------------------
[Synset('group.n.01')]

hypernyms( )을 통해 상위 계층을 불러왔습니다. 결국 group > people 이라는 의미입니다.

그렇다면 최상위계층까지 가는 단계들을 한 번에 보기 위해 함수를 만들어 보겠습니다.

 

 

def hypernyms(word):
    current_pos = wn.synsets(word)[0]
    yield current_pos
    
    while 1:
        try:
            current_pos = current_pos.hypernyms()[0]
            yield current_pos
        except:
            break

for _ in hypernyms('firefighter'):
    print(_)
-----------------------------------------------
Synset('fireman.n.04')
Synset('defender.n.01')
Synset('preserver.n.03')
Synset('person.n.01')
Synset('causal_agent.n.01')
Synset('physical_entity.n.01')
Synset('entity.n.01')

hypernyms 라는 함수를 만들어서 단어를 적용시키면 상위 모든 계층들이 나오는 것을 알 수 있었다.

 

 

for _ in hypernyms('mailman'):
    print(_)
-----------------------------------------
Synset('mailman.n.01')
Synset('deliveryman.n.01')
Synset('employee.n.01')
Synset('worker.n.01')
Synset('person.n.01')
Synset('causal_agent.n.01')
Synset('physical_entity.n.01')
Synset('entity.n.01')

'mailman' 을 적용시켜도 정상적으로 나오는 것을 보였다.

그렇다면 'firefighter' 와 'mailman' 사이의 거리를 측정해 유사도를 판별할 수 있지 않을까?

 

 

# 단어 간 거리 측정하기

def distance(word1, word2):
    word1_hypernyms = [_ for _ in hypernyms(word1)]
    
    for i, word2_hypernyms in enumerate(hypernyms(word2)):
        try:
            return i + word1_hypernyms.index(word2_hypernyms)
        except:
            continue

distance('firefighter', 'mailman')
-----------------------------------
7

hypernyms( ) 함수를 통해서 word1_hypernyms 에 word1 단어의 전 상위 계층을 담는다. 

그리고 index 4번째 'person' 에서 firefighter 의 인덱스 3에 있는 'person' 과 만나 7이 측정되었다.

 

 

# 유사도 측정

import numpy as np

def similarity(word1, word2):
    return -np.log(distance(word1, word2))

print(similarity('firefighter', 'mailman'))
-----------------------------------------------
-1.9459101490553132

이로써 'firefighter' 와 'mailman' 사이의 유사도는 약 -1.946 이 나오게 되었다.

 


Word Feature Vectors

  • 위의 WordNet은 사전에 대한 의존도가 높아 시간이 지날수록 정확도나 활용도가 떨어질 수 있음.

@ TF-IDF

  • d 라는 문서 내에서 w 라는 단어가 있을 때, w 는 d 내에서 얼마나 중요한지 나타내는 수치
  • 텍스트 마이닝에서 중요하게 사용됨.
  • TF(Term Frequency)
    • w 가 문서 내에 출현한 횟수
    • 하지만, of, the, for 같은 단어도 TF 가 클 것임을 알고 있어야 함. (무시)
  • IDF(Inverse Document Frequency)
    • w 라는 단어가 몇 개의 문서에 나왔는지에 대한 횟수의 역수
    • 이 방법을 통해 of, the, for 과 같은 단어에 대한 영향을 줄여줌
300x250