1. 단어의 의미¶
단어와 의미의 관계¶
- 단어는 겉으로 보이는 형태인 표제어 안에 여러 의미를 담고 있음
- 한 가지 형태의 단어에 여러 의미가 포함되어 생기는 '중의성'문제는 자연어 처리에서 매우 중요한 위치를 가짐
동형어와 다의어¶
- 형태는 같으나 뜻이 서로 다른 단어를 동형어라고 함(예: 차)
- 동형어와 다의어의 차이점은, 다의어의 경우 한 형태의 단어가 여러 의미를 지니면서도 그 의미들이 서로 관련이 있는 듯을 갖는다는 것
- 그와 달리, 동형어는 아예 어원이 다른 의미들이 같은 형태를 띄는 단어
- 이렇게 한 형태 내에서 여러 의미를 지니는 동형어 또는 다의어의 경우에는 단어 중의성 해소(WSD)라는 방법을 통해 단어의 의미를 더 명확히 하는 과정이 필요함.
- 단어의 중의성을 해소하고자 주변 문맥을 통해 원래 단어의 의미를 파악하는 방법을 가장 많이 사용
- 현재는 단어 중의성 해소에 대한 필요도가 낮아짐. 그러나 단어의 모호한 의미로 인해 해결이 어려운 경우가 많아 풀지 못한 숙제 중 하나
- 사용 빈도가 높은 대부분의 단어는 동형어 또는 다의어일 가능성이 높음
동의어¶
- 다른 형태이지만 의미가 같은 단어
상위어와 하위어¶
- 상위 개념을 가리키는 단어를 상위어라 하고, 하위 개념을 표현하는 단어를 하위어라고 함
- 단어들의 어휘 분류에 따라 단어 간 관계 구조를 계층화할 수 있음. 계층화된 단어 간의 관계를 활용하면 자연어 처리에도 유용하게 사용 가능.
모호성 해소¶
- 텍스트가 내포한 진짜 의미를 파악하는 과정이 필요함. 단어의 겉 형태인 텍스트만으로는 모호성이 매우 높음
- 단어가 가지는 모호성을 제거하는 과정을 단어 중의성 해소(WSD)라고 함
2. 원핫인코딩¶
pass
3. 시소러스를 활용한 단어 의미 파악¶
- 원핫벡터로는 단어 의미의 특징을 잘 반영할 수 없음.
- 따라서 계층 구조를 잘 분석하고 분류하여 데이터베이스로 구축한다면 자연어 처리 시 도움이 됨
- 이런 용도로 구축된 데이터베이스를 시소러스(어휘분류사전)라고 함.
- 워드넷이 시소러스의 대표격
- 사전을 구축하는데 너무 큰 비용과 시간이 소요됨. 또한 상의어와 하위어가 잘 반영된 사전인지 검증도 되어야함. 사전에 기반한 유사도를 구하는 방식은 비교적 정확한 값을 구할 수 있으나 그 한계가 뚜렷함
워드넷¶
- 단어에 대한 상위어와 하위어 정보를 구축함으로써, 유향 비순환 그래프(directed acyclic graph/ DAG)를 이루게 됨.
- 하나의 노드가 여러 상위 노드를 가질 수 있으므로 트리구조는 아님
- 단어별 여러가지 가능한 의미를 미리 정의하고 번호를 매겨놓았고, 의미별로 비슷한 뜻의 동의러를 링크해 동의어 집합을 제공함
- 이는 단어 중의성 해소에 큰 도움을 주는 레이블 데이터
- 워드넷이 제공하는 데이터를 바탕으로 지도학습을 통해 단어 중의성 해소 문제를 해결할 수 있음
한국어 워드넷¶
- 지속적으로 발전하는 중
- KorLex, Korean WordNet(KWN)
5. 특징추출: TF-IDF¶
- 출현 빈도를 사용하여 어떤 단어 w가 문서 d 내에서 얼마나 중요한지를 나타내는 수치
- 이 수치가 높을수록 w는 d를 대표하는 성질을 띄게 된다고 볼 수 있음
In [1]:
import pandas as pd
doc1 = '''
지능 지수 라는 말 들 어 보 셨 을 겁니다 . 여러분 의 지성 을 일컫 는 말 이 죠 . 그런데 심리 지수 란 건 뭘까요 ? 사람 들 이 특정 한 식 으로 행동 하 는 이유 에 대해 여러분 은 얼마나 알 고 계시 나요 ? 또 타인 이나 심지어 여러분 의 행동 을 예측 하 는 일 은 얼마나 잘 하 시 나요 ? 또 , 심리학 에 대해 갖춘 지식 중 에서 어느 정도 나 잘못 된 것 일까요 ? 심리학 에 관한 열 가지 신화 를 통해 잘못 된 것 들 을 알아보 도록 하 죠 . 여러분 은 한 번 쯤 들 어 보 셨 을 법 한 것 은 자신 들 의 심리학 에 대해 고려 할 때 , 거의 항상 남자 는 화성 에서 왔 고 , 여자 는 금성 에서 온 것 같 다고 합니다 . 하지만 실제로 남자 와 여자 는 얼마나 다른 걸까요 ? 이 를 알아보 기 위해 , 일단 남녀 사이 에 확실 하 게 차이 나 는 것 을 살펴보 고 심리학 적 인 성별 간 의 차이점 을 동일 한 척도 상 에서 대비 해 보 도록 하 겠 습니다 . 남자 와 여자 간 에 실제로 차이 나 는 능력 중 하나 는 그 들 이 공 을 얼마나 멀리 던질 수 있 느냐 하 는 것 입니다 . 여기 남자 들 의 데 이타 를 보 시 면 , 정상 분포 곡선 이 라는 걸 볼 수 있 습니다 . 남자 들 소수 는 정말 멀리 던지 고 , 남자 들 소수 는 멀리 던지 지 못하 지만 , 남자 들 대부분 은 평균 적 인 거리 를 던졌 습니다 . 여자 들 도 역시 비슷 한 분포 상태 를 보입니다 만 사실 남녀 사이 엔 커다란 차이 가 있 습니다 . 사실 , 평균 수준 의 남자 라면 모든 여성 중 대략 98 % 보다 더 멀리 던질 수 있 거든요 . 이 와 동일 하 게 표준 화 된 척도 상 에서 심리학 에서 말 하 는 성별 간 의 차이 를 살펴 봅시다 . 심리학자 라는 여러분 에게 말 하 길 남자 들 의 공간 지각 능력 이 여자 들 보다 뛰어나 다고 할 겁니다 . 예 를 들 어 , 지도 읽 는 능력 같 은 건데 , 맞 는 말 입니다 . 하지만 그 차이 의 정도 를 살펴봅시다 . 아주 작 죠 . 두 선 이 너무 근접 해서 거의 겹칠 정도 입니다 .
'''
doc2 = '''
최상 의 제시 유형 은 학습 자 에 좌우 되 는 것 이 아니 라 학습 해야 할 내용 에 따라 좌우 됩니다 . 예 를 들 어 여러분 이 운전 하 기 를 배울 때 실제로 몸 으로 체감 하 는 경험 없이 누군가 가 어떻게 할 지 이야기 하 는 것 을 듣 는 것 만 으로 배울 수 있 습니까 ? 연립 방정식 을 풀 어야 하 는데 종이 에 쓰 지 않 고 머리 속 에서 말 하 는 것 으로 풀 수 가 있 을까요 ? 또는 만일 여러분 이 체감 형식 의 학습 자 유형 이 라면 , 건축학 시험 을 해석 적 춤 을 이용 하 여 수정 할 수 있 을까요 ? 아니 죠 ! 배워야 할 내용 을 제시 된 유형 에 맞추 어야 합니다 , 당신 에게 맞추 는 게 아니 라요 . 여러분 들 상당수 가 " A " 급 의 우등 생 이 라는 걸 아 는데 , 조만간 중등 학력 인증 시험 ( GCSE ) 결과 를 받 게 되 시 겠 네요 . 그런데 , 만일 , 여러분 들 이 희망 했 던 성적 을 받 지 못하 게 된다 해도 여러분 들 의 학습 방식 을 탓 해서 는 안 되 는 겁니다 . 여러분 이 비난 할 수 있 는 한 가지 는 바로 유전자 입니다 . 이건 최근 에 런던 대학교 ( UCL ) 에서 수행 했 던 연구 결과 는 여러 학생 들 과 그 들 의 중등 학력 인증 시험 결과 사이 의 차이 중 58 % 는 유전 적 인 요인 으로 좁혀졌 습니다 . 매우 정밀 한 수치 처럼 들립니다 . 그러면 어떻게 알 수 있 을까요 ? 유전 적 요인 과 환경 적 요인 의 상대 적 기여 도 를 알 고 싶 을 때 우리 가 사용 할 수 있 는 방식 은 바로 쌍둥이 연구 입니다 . 일 란 성 쌍생아 의 경우 환경 적 요인 과 유전 적 요인 모두 를 100 % 똑같이 공유 하 게 되 지만 이란 성 쌍생아 의 경우 는 100 % 동일 한 환경 을 공유 하 지만 유전자 의 경우 여타 의 형제자매 들 처럼 50 % 만 공유 하 게 됩니다 . 따라서 일 란 성 쌍둥이 와 이란 성 쌍둥이 사이 의 인증 시험 결과 가 얼마나 비슷 한지 비교 해 보 고 여기 에 약간 의 수학 적 계산 을 더하 게 되 면 그 수행 능력 의 차이 중 어느 정도 가 환경 적 요인 의 탓 이 고 어느 정도 가 유전자 탓 인지 를 알 수 있 게 됩니다 .
'''
doc3 = '''
그러나 이 이야기 는 세 가지 이유 로 인해 신화 입니다 . 첫째 , 가장 중요 한 건 실험실 가운 은 흰색 이 아니 라 회색 이 었 다 라는 점 이 죠 . 둘째 , 참 여자 들 은 실험 하 기 전 에 와 참여 자 들 이 걱정 을 표현 할 때 마다 상기 시키 는 말 을 들 었 는데 , 전기 충격 이 고통 스럽 기 는 하 지만 , 치명 적 이 지 는 않 으며 실제로 영구 적 인 손상 을 남기 는 일 은 없 을 거 라는 것 이 었 습니다 . 셋째 , 참 여자 들 은 단지 가운 을 입 은 사람 이 시켜 전기 충격 을 주지 는 않 았 죠 . 실험 이 끝나 고 그 들 의 인터뷰 를 했 을 때 모든 참여 자 들 은 강한 신념 을 밝혔 는데 , ' 학습 과 처벌 ' 연구 가 과학 적 으로 가치 있 는 목적 을 수행 했 기 때문 에 비록 동료 참여 자 들 에게 가해진 순간 적 인 불편 함 에 반해서 과학 을 위해서 오래 남 을 성과 를 얻 을 것 이 라고 말 이 죠 . 그러 다 보 니 제 가 이야기 를 한 지 벌써 12 분 이 되 었 습니다 . 여러분 들 중 에 는 아마 거기 앉 아서 제 이야기 를 들으시는 동안 저 의 말투 와 몸짓 을 분석 하 면서 제 가 말 하 는 어떤 것 을 인지 해야 할까 해결 하 려고 하 셨 을 겁니다 , 제 가 진실 을 이야기 하 는 지 , 또는 거짓말 을 하 고 있 는 것 인지 말 이 죠 . 만일 그러 셨 다면 , 아마 지금 쯤 완전히 실패 하 셨 을 겁니다 . 왜냐하면 우리 모두 가 사람 이 말 하 는 패턴 과 몸짓 으로 도 거짓말 여부 를 알아내 는 것 이 가능 하 다고 생각 하 지만 , 오랜 세월 수백 회 에 걸쳐 행해진 실제 심리 검사 의 결과 를 보 면 우리 들 모두 는 , 심지어 경찰관 이나 탐정 들 을 포함 해서 도 기본 적 으로 몸짓 과 언어 적 패턴 으로 거짓말 을 탐지 하 는 것 은 운 에 맞 길 수 밖 에 는 없 는 것 입니다 . 흥미 롭 게 도 한 가지 예외 가 있 는데요 : 실종 된 친척 을 찾 아 달 라고 호소 하 는 TV 홍보 입니다 .
'''
특정 문서가 주어졌을 때, 문서 내의 단어들의 출현 빈도를 세는 함수¶
In [2]:
def get_term_frequency(document, word_dict=None):
if word_dict is None:
word_dict = {}
words = document.split()
for w in words:
word_dict[w] = 1 + (0 if word_dict.get(w) is None else word_dict[w])
return pd.Series(word_dict).sort_values(ascending=False)
get_term_frequency(doc1)
Out[2]:
문서들이 주어졋을 때 각 단어가 몇 개의 문서에서 나타났는지 세는 함수¶
In [3]:
def get_document_frequency(documents):
dicts = []
vocab = set([])
df = {}
for d in documents:
tf = get_term_frequency(d)
dicts += [tf]
vocab = vocab | set(tf.keys())
for v in list(vocab):
df[v] = 0
for dict_d in dicts:
if dict_d.get(v) is not None:
df[v] += 1
return pd.Series(df).sort_values(ascending=False)
get_document_frequency([doc1, doc2])
Out[3]:
TF-IDF¶
In [4]:
def get_tfidf(docs):
vocab = {}
tfs = []
for d in docs:
vocab = get_term_frequency(d, vocab)
tfs += [get_term_frequency(d)]
df = get_document_frequency(docs)
from operator import itemgetter
import numpy as np
stats = []
for word, freq in vocab.items():
tfidfs = []
for idx in range(len(docs)):
if tfs[idx].get(word) is not None:
tfidfs += [tfs[idx][word] * np.log(len(docs) / df[word])]
else:
tfidfs += [0]
stats.append((word, freq, *tfidfs, max(tfidfs)))
return pd.DataFrame(stats, columns=('word',
'frequency',
'doc1',
'doc2',
'doc3',
'max')).sort_values('max', ascending=False)
get_tfidf([doc1, doc2, doc3])
Out[4]:
In [5]:
def get_tf(docs):
vocab = {}
tfs = []
for d in docs:
vocab = get_term_frequency(d, vocab)
tfs += [get_term_frequency(d)]
from operator import itemgetter
import numpy as np
stats = []
for word, freq in vocab.items():
tf_v = []
for idx in range(len(docs)):
if tfs[idx].get(word) is not None:
tf_v += [tfs[idx][word]]
else:
tf_v += [0]
stats.append((word, freq, *tf_v))
return pd.DataFrame(stats, columns=('word',
'frequency',
'doc1',
'doc2',
'doc3')).sort_values('frequency', ascending=False)
get_tf([doc1, doc2, doc3])
Out[5]:
- 예를 들어, '는'이라는 단어는 [15,14,18]이라는 특징 벡터를 가짐
- 여기서 문제는 문서가 지나치게 많으면 벡터의 차원 역시 지나치게 커지고, 대부분이 0으로 채워짐
- 희소벡터의 각 차원은 대부분이 0이므로 유의미한 특정 통계를 얻는데 큰 걸림돌이 됨
- 또한, 단순히 문서에서의 출현 횟수만으로 특징 벡터를 구성하여 많은 정보가 유실됨
Context Window로 함께 출현한 단어들의 정보 활용하기¶
- 함께 나타나는 동시발생 단어들을 활용한 방법
- 함께 나타나는 단어들을 조사하기 위해 윈도잉을 실행함
- 윈도잉이란 윈도우를 움직이며 그 안에 있는 유닛들의 정보를 취합하는 방법이며, 이 때 사용되는 윈도우를 Context Window라고 함
- 이 방법은 단어별로 윈도우 내에 속해 있는 이웃 단어들의 출현 빈도를 세어 행렬로 나타내는 것
- TF로 특징베거를 구성한 방식보다 더 정확하지만 windosw size라는 하이퍼 파라미터가 추가되므로 그 값을 정해야 함
In [6]:
from collections import defaultdict
import pandas as pd
def get_context_counts(lines, w_size=2):
co_dict = defaultdict(int)
for line in lines:
words = line.split()
for i, w in enumerate(words):
for c in words[i - w_size:i + w_size]:
if w != c:
co_dict[(w, c)] += 1
return pd.Series(co_dict)
동시 발생정보 벡터를 만드는 코드
In [7]:
def co_occurrence(co_dict, vocab):
data = []
for word1 in vocab:
row = []
for word2 in vocab:
try:
count = co_dict[(word1, word2)]
except KeyError:
count = 0
row.append(count)
data.append(row)
return pd.DataFrame(data, index=vocab, columns=vocab)
7. 벡터 유사도 구하기¶
In [8]:
import torch
L1 distance: 맨해튼 거리¶
- 파이토치 텐서를 입력으로 받고 l1 거리를 반환해주는 코드
In [9]:
def get_l1_distance(x1, x2):
return ((x1 - x2).abs()).sum()
L2 distance: 유클리디안 거리¶
In [10]:
def get_l2_distance(x1, x2):
return ((x1 - x2)**2).sum()**.5
Infinity Norm: 차원별 값의 차이 중 가장 큰 값을 나타냄¶
In [11]:
def get_infinity_distance(x1, x2):
return ((x1 - x2).abs()).max()
코사인 유사도¶
In [12]:
def get_cosine_similarity(x1, x2):
return (x1 * x2).sum() / ((x1**2).sum()**.5 * (x2**2).sum()**.5)
자카드 유사도: 두 집합 간의 유사도를 구하는 방법¶
- 두 집합의 교집합 크기가 있고, 이를 밑변에서 두 집하븨 합집합 크기로 나눔
In [13]:
def get_jaccard_similarity(x1, x2):
return torch.stack([x1, x2]).min(dim=0)[0].sum() / torch.stack([x1, x2]).max(dim=0)[0].sum()
문서 간 유사도 구하기¶
- 단어처럼 문서 또한 문서에 대해 특징을 추출하여 문서간의 유사도를 구할 수 있음
8. 단어 중의성 해소(WSD)¶
- 하나의 단어는 여러 가지 의미를 지닐 수 있음. 서로 비슷한 의미의 다의어인 경우에는 비교적 문제가 크진 않음
- 동형어의 경우에는 문제가 달라지므로 단어가 주어졌을 때 그 의미의 모호성을 없애고 해석하는 단어 중의성해소(WSD)가 매우 중요함
시소러스 기반의 중의성 해소: Lesk algorithm(레스크 알고리즘)¶
- 가장 간단한 사전 기반 중의성 해소 방법. 주어진 문장에서 특정 단어의 의미를 명확히 할 때 사용가능
- 먼저, 중의성을 해소하고자 하는 단어에 대해 사전(주로 워드넷)의 의미별 설명과, 주어진 문장 내에 등장한 단어의 사전에서 의미별 설명 사이의 유사도를 구함
- 이후, 문장 내 단어들의 의미별 설명과 가장 유사도가 높은 의미를 선택함
- 워드넷과 같이 잘 분류된 사전이 있다면, 쉽고 빠르게 중의성 해소 문제를 해결할 수 있음
- 하지만 단어 및 의미에 관한 설명에 크게 의존하고, 설명이 부실하거나 주어진 문장에 큰 특징이 없는 경우 단어 중의성 해소 능력이 크게 떨어짐. 또한, 사전에 존재하지 않는 단어의 경우 알고리즘 수행 자체가 어려움
선택 선호도¶
- 문장은 여러 단어의 시퀀스로 이루어짐. 따라서 각 단어는 문장 내 주변의 단어들에 따라 그 의미가 정해짐
- 선택 선호도는 이를 수치화하여 나타냄 (ex) '마시다'에 대한 목적어는 '음료' 클래스에 속하는 단어가 올 확률이 높음
- 따라서 '차'라는 단어가 '음료' 클래스에 속하는지 '교통수단' 클래스에 속하는지 쉽게 알 수 있음
- 이런 성질을 이용하여 단어 중의성 해소를 해결할 수 있음
선택 선호도 강도¶
- 술어 동사(주어의 동작이나 상태를 나타내는 말로, 동사가 쓰임)가 주어졌을 대, 목적어 관계에 있는 (보통은 명사인) 표제어 단어들의 분포는 평소 문서 내에 해당 명사가 나올 분포와는 다를 것. 그 분포의 차이가 크면 클수록 해당 술어는 더 강력한 선택 선호도를 가질 것.
- 이것을 선택 서노도 강도라고 명명하고 쿨백-라이블러 발산을 사용하여 정의함
- 즉, 술어가 표제어로 특정 클래스를 얼마나 선택적으로 선호하는 지에 대한 수치
- 예를 들어, '음식' 클래스의 단어는 '공구' 클래스의 단어보다 나타날 확률이 훨씬 높을 것. 이 때, '사용하다'라는 동사 술어가 주어진다면, 동사-목적어 관계에 있는 표제어로서의 '음식' 클래스의 확률은 '공구'클래스의 확률보다 낮아질 것
선택 관련도¶
- 선택 선호도 강도가 낮아서, 해당 술어는 클래스에 대한 선택적 선호 강도가 낮음에도 불구하고 특정 클래스만 유독 술어에 영향을 많이 받아서 선택 관련도의 수치도 커지게 만듦
선택 선호도와 WSD¶
- '마시다'라는 동사에 '차' 라는 목적어가 함께 있을 때, 선택 선호도를 통해서 '차'는 '음료' 클래스에 속한다고 말할 수 있음.
- 만약 단어가 어떤 클래스에 속하는지 미리 알고있따면 단어들의 출현빈도를 세어 클래스의 확률 분포를 추정할 수 있음. 결국 이를 위해서는 사전에 정의된 지식 또는 데이터셋이 필요함
워드넷 기반의 선택선호도¶
- 이 때 워드넷이 위력을 발휘함
유사 어휘를 통한 선택 선호도 평가¶
- 유사어휘는 두 개의 단어가 인위적으로 합성되어 만들어진 단어를 말함. 이를 활용하여 선택 선호도를 평가할 수 있음.
유사도 기반의 선택 선호도¶
- 카트린 어크는 단어간의 유사도를 통해 시소러스에 의존하지 않고 데이터를 기반으로 간단하게 선택 선호도를 구하는 방법을 제시함
- 하지만 코퍼스에 따라 유사도를 구할 수 있는 대상이 달라지므로 그에 따른 커버리지 문제가 발생할 수 있음
유사도 기반의 선택 선호도 예제¶
- 코퍼스를 받아 문장 내에서 술어(동사, W)와 표제어(명사, NNG)를 찾아 $Seen_k(w)$ 함수를 구성함
In [14]:
from konlpy.tag import Kkma
def count_seen_headwords(lines, predicate='VV', headword='NNG'):
tagger = Kkma()
seen_dict = {}
for line in lines:
pos_result = tagger.pos(line)
word_h = None
word_p = None
for word, pos in pos_result:
if pos == predicate or pos[:3] == predicate + '+':
word_p = word
break
if pos == headword:
word_h = word
if word_h is not None and word_p is not None:
seen_dict[word_p] = [word_h] + ([] if seen_dict.get(word_p) is None else seen_dict[word_p])
return seen_dict
- 그럼 주어진 술어와 표제어에 대해서 선택 관련도 점수를 구하는 함수를 다음과 같이 구현할 수 있음
- 단어 사이의 유사도를 구하기 위해, 이전에 구성한 특징 벡터들을 담은 pandas dataframe을 받음.
- 그 후 metric으로 주어진 함수를 통해 유사도를 계산
In [15]:
def get_selectional_association(predicate, headword, lines, dataframe, metric):
v1 = torch.FloatTensor(dataframe.loc[headword].values)
seens = seen_headwords[predicate]
total = 0
for seen in seens:
try:
v2 = torch.FloatTensor(dataframe.loc[seen].values)
total += metric(v1, v2)
except:
pass
return total
- 위 함수들을 이용하여 주어진 술어에 대해서 올바른 headword를 고르는 wsd 함수는 아래와 같음
In [16]:
def wsd(predicate, headwords):
selectional_associations = []
for h in headwords:
selectional_associations += [get_selectional_association(predicate, h, lines, co, get_cosine_similarity)]
print(selectional_associations)
- 많은 코퍼스를 가지고 있고, 정확한 특징 벡터를 구성할수록 정확한 유사도 계산이 가능해져 점점 더 좋은 성능의 중의성 해소가 가능함
- 이것이 기존의 시소러스 기반의 레스크 알고리즘과 다른 데이터 기반 알고리즘의 장점
In [ ]:
'자연어, 비전' 카테고리의 다른 글
카카오톡 대화 내용으로 개인별 워드클라우드(wordcloud) 그리기 (1) | 2022.06.22 |
---|---|
transformer 구현 및 설명 (0) | 2021.06.03 |
시퀀스 모델링 (0) | 2020.11.10 |
워드 임베딩 (0) | 2020.11.10 |
자연어 처리를 위한 전처리 과정 정리 (0) | 2020.11.06 |