A A
[NLP] Thesaurus(μ‹œμ†ŒλŸ¬μŠ€), Co-occurence Matrix(λ™μ‹œλ°œμƒ ν–‰λ ¬)
  • μ˜€λžœλ§Œμ— NLP κ΄€λ ¨ 글을 μ“°λ„€μš”.. μ‹œκ°„ λ‚˜λŠ”λŒ€λ‘œ μ—΄μ‹¬νžˆ μ“°κ³  올렀 보도둝 ν•˜κ² μŠ΅λ‹ˆλ‹€.

 

Thesaursus - μ‹œμ†ŒλŸ¬μŠ€

μ‹œμ†ŒλŸ¬μŠ€(Thesaurus)λŠ” 단어와 κ·Έ 의미λ₯Ό μ—°κ²°μ‹œμΌœμ£ΌλŠ” λ„κ΅¬μž…λ‹ˆλ‹€.
주둜 νŠΉμ • 단어와 의미적으둜 μœ μ‚¬ν•œ 단어(λ™μ˜μ–΄)와 λ°˜λŒ€ 의미λ₯Ό 가진 단어(λ°˜μ˜μ–΄)λ₯Ό μ œκ³΅ν•˜μ—¬, 글을 μ“°κ±°λ‚˜ 말을 ν•  λ•Œ λ‹€μ–‘ν•œ ν‘œν˜„μ„ μ‚¬μš©ν•  수 μžˆλ„λ‘ λ•μŠ΅λ‹ˆλ‹€.
  • λ‹€λ₯Έ 의미둜 λ§ν•˜λ©΄, μœ μ˜μ–΄ μ‚¬μ „μœΌλ‘œ '뜻이 같은 단어(λ™μ˜μ–΄)'λ‚˜ '뜻이 λΉ„μŠ·ν•œ 단어(μœ μ˜μ–΄)'κ°€ ν•œ 그룹으둜 λΆ„λ₯˜λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

λ™μ˜μ–΄μ˜ μ˜ˆμ‹œμž…λ‹ˆλ‹€. 'car', 'automobile'은 'μžλ™μ°¨'λ₯Ό λœ»ν•˜λŠ” λ™μ˜μ–΄ μž…λ‹ˆλ‹€.

  • λ˜ν•œ NLPμ—μ„œ μ΄μš©λ˜λŠ” μ‹œμ†ŒλŸ¬μŠ€μ—μ„œλŠ” 단어 μ‚¬μ΄μ˜ 'μƒμœ„, ν•˜μœ„' ν˜Ήμ€ '전체, λΆ€λΆ„'λ“± 더 μ„Έμ„Έν•œ κ΄€κ³„κΉŒμ§€ μ •μ˜ν•΄λ‘” κ²½μš°κ°€ μžˆμŠ΅λ‹ˆλ‹€.
  • 예λ₯Ό λ“€μ–΄μ„œ μ•„λž˜μ˜ κ·Έλž˜ν”„ 처럼 관계λ₯Ό μ •μ˜ν•©λ‹ˆλ‹€.

λ‹¨μ–΄λ“€μ˜ 의미λ₯Ό 상, ν•˜μœ„ 관계에 κΈ°μ΄ˆν•΄ κ·Έλž˜ν”„λ‘œ ν‘œν˜„

  • 이처럼 λͺ¨λ“  단어에 λ°ν•œ μœ μ˜μ–΄ 집합을 λ§Œλ“ λ‹€μŒ, λ‹¨μ–΄λ“€μ˜ 관계λ₯Ό κ·Έλž˜ν”„λ‘œ ν‘œν˜„ν•˜μ—¬, 단어 μ‚¬μ΄μ˜ 연결을 μ •μ˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

WordNet

NLPλΆ„μ•Όμ—μ„œ κ°€μž₯ 유λͺ…ν•œ μ‹œμ†ŒλŸ¬μŠ€λŠ” WordNetμž…λ‹ˆλ‹€.

  • WordNet은 ν”„λ¦°μŠ€ν„΄ λŒ€ν•™κ΅μ—μ„œ 개발된 μ˜μ–΄ μ–΄νœ˜ λ°μ΄ν„°λ² μ΄μŠ€μž…λ‹ˆλ‹€.
  • μ‚¬λžŒμ˜ μ–Έμ–΄ 이해λ₯Ό 돕기 μœ„ν•΄ λ§Œλ“€μ–΄μ‘ŒμœΌλ©°, 단어 κ°„μ˜ 의미 관계λ₯Ό μ€‘μ‹¬μœΌλ‘œ κ΅¬μ„±λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.
    • μ–΄νœ˜ 관계망: WordNet은 단어λ₯Ό λ™μ˜μ–΄ 집합(synset)으둜 κ·Έλ£Ήν™”ν•˜μ—¬, 각 그룹이 νŠΉμ • κ°œλ…μ„ λ‚˜νƒ€λ‚΄λ„λ‘ ν•©λ‹ˆλ‹€. 이λ₯Ό 톡해 같은 의미λ₯Ό κ°€μ§€λŠ” λ‹€μ–‘ν•œ 단어듀을 μ‰½κ²Œ 찾을 수 μžˆμŠ΅λ‹ˆλ‹€.
    • 의미 관계: 단어듀 κ°„μ˜ λ‹€μ–‘ν•œ 의미 관계λ₯Ό μ •μ˜ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, μƒμœ„μ–΄/ν•˜μœ„μ–΄(hypernym/hyponym), λ°˜μ˜μ–΄(antonym), λΆ€λΆ„/전체 관계(meronym/holonym) 등을 ν¬ν•¨ν•©λ‹ˆλ‹€.
    • λ™μ˜μ–΄μ™€ μ •μ˜: 각 λ™μ˜μ–΄ μ§‘ν•©μ—λŠ” κ·Έ 의미λ₯Ό μ„€λͺ…ν•˜λŠ” μ •μ˜(gloss)κ°€ ν¬ν•¨λ˜μ–΄ μžˆμ–΄, λ‹¨μ–΄μ˜ μ •ν™•ν•œ 의미λ₯Ό νŒŒμ•…ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    • 닀쀑 감각: ν•˜λ‚˜μ˜ 단어가 μ—¬λŸ¬ 가지 의미λ₯Ό κ°€μ§ˆ 수 μžˆλŠ” 경우, WordNet은 각 의미λ₯Ό λ³„λ„λ‘œ μ •μ˜ν•˜κ³  κ΄€λ ¨ 단어λ₯Ό μ—°κ²°ν•˜μ—¬ μ œκ³΅ν•©λ‹ˆλ‹€.
  • 그리고, WordNet을 μ‚¬μš©ν•˜λ©΄ 'μœ μ˜μ–΄'λ₯Ό μ–»κ±°λ‚˜ '단어 λ„€νŠΈμ›Œν¬'λ₯Ό μ΄μš©ν•˜μ—¬ 단어 μ‚¬μ΄μ˜ μœ μ‚¬λ„λ₯Ό ꡬ할 수 μžˆμŠ΅λ‹ˆλ‹€.

 

Thesaursus(μ‹œμ†ŒλŸ¬μŠ€)의 문제점

WordNetκ³Ό 같은 Thesaursus(μ‹œμ†ŒλŸ¬μŠ€)μ—λŠ” μˆ˜λ§Žμ€ 단어에 λ°ν•œ λ™μ˜μ–΄, 계측 κ΅¬μ‘°λ“±μ˜ 관계가 μ •μ˜λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.
  • 그리고 이 Thesaursus(μ‹œμ†ŒλŸ¬μŠ€)λ₯Ό μ΄μš©ν•˜λ©΄ 'λ‹¨μ–΄μ˜ 의미'λ₯Ό (κ°„μ ‘μ μœΌλ‘œλΌλ„) 컴퓨터에 전달할 수 μžˆμŠ΅λ‹ˆλ‹€.
  • ν•˜μ§€λ§Œ 이처럼 μ‚¬λžŒμ΄ μˆ˜μž‘μ—…μœΌλ‘œ labelingν•˜λŠ” λ°©μ‹μ—λŠ” ν¬λ‚˜ν° 결점이 μ‘΄μž¬ν•©λ‹ˆλ‹€.

 

μ‹œλŒ€ 변화에 λŒ€μ‘ν•˜κΈ° μ–΄λ ΅μŠ΅λ‹ˆλ‹€.

  • μš°λ¦¬κ°€ μ‚¬μš©ν•˜λŠ” 말은 λ•Œλ•Œλ‘œ μƒˆλ‘œμš΄ 단어가 μƒκ²¨λ‚˜κ³ , μ˜›λ§μ€ μ–Έμ  κ°€ μžŠν˜€μ§‘λ‹ˆλ‹€. λ˜ν•œ μ‹œλŒ€μ— 따라 μ–Έμ–΄μ˜ μ˜λ―Έκ°€ λ³€ν•˜κΈ°λ„ μžˆμŠ΅λ‹ˆλ‹€.
  • 이런 λ‹¨μ–΄μ˜ 변화에 λŒ€μ‘ν•˜λ €λ©΄ Thesaursus(μ‹œμ†ŒλŸ¬μŠ€)λ₯Ό μ‚¬λžŒμ΄ μˆ˜μž‘μ—…μœΌλ‘œ λŠμž„μ—†μ΄ κ°±μ‹ ν•΄μ•Ό ν•©λ‹ˆλ‹€.

 

μ‚¬λžŒμ„ μ“°λŠ” λΉ„μš©μ€ 크닀

  • Thesaursus(μ‹œμ†ŒλŸ¬μŠ€)λ₯Ό λ§Œλ“œλŠ” λ°λŠ” μ—„μ²­λ‚œ 인적 λΉ„μš©μ΄ λ°œμƒν•©λ‹ˆλ‹€.
  • μ˜μ–΄λ₯Ό 예둜 λ“€λ©΄, ν˜„μ‘΄ν•˜λŠ” μ˜μ–΄ λ‹¨μ–΄μ˜ μˆ˜λŠ” 1,000만 κ°œκ°€ λ„˜λŠ”λ‹€κ³  ν•©λ‹ˆλ‹€. λ”°λΌμ„œ μ΄μƒμ μœΌλ‘œλŠ” 이 λ°©λŒ€ν•œ 단어듀 λͺ¨λ‘μ— λŒ€ν•΄ 단어 μ‚¬μ΄μ˜ 관계λ₯Ό μ •μ˜ν•΄μ€˜μ•Ό ν•©λ‹ˆλ‹€.
  • 참고둜 WordNet에 λ“±λ‘λœ λ‹¨μ–΄λŠ” 20만 개 μ΄μƒμž…λ‹ˆλ‹€.

 

λ‹¨μ–΄μ˜ λ―Έλ¬˜ν•œ 차이λ₯Ό ν‘œν˜„ν•  수 μ—†λ‹€.

  • Thesaursus(μ‹œμ†ŒλŸ¬μŠ€)λŠ” λœ»μ΄ λΉ„μŠ·ν•œ 단어듀을 λ¬ΆμŠ΅λ‹ˆλ‹€.
  • κ·ΈλŸ¬λ‚˜ μ‹€μ œλ‘œ λΉ„μŠ·ν•œ 단어듀이라도 λ―Έλ¬˜ν•œ 차이가 μžˆμŠ΅λ‹ˆλ‹€. μ˜ˆμ»¨λŒ€λΉˆν‹°μ§€[vintage, λ‚‘κ³  였래된 것]’μ™€λ ˆνŠΈλ‘œ[retro, 볡고]’λŠ” μ˜λ―Έκ°€ κ°™μ§€λ§Œ, μš©λ²•μ€ λ‹€λ¦…λ‹ˆλ‹€.
  • Thesaursus(μ‹œμ†ŒλŸ¬μŠ€)μ—μ„œλŠ” μ΄λŸ¬ν•œ λ―Έλ¬˜ν•œ 차이λ₯Ό ν‘œν˜„ν•  수 μ—†μŠ΅λ‹ˆλ‹€. κ·Έλ ‡λ‹€κ³  이λ₯Ό μˆ˜μž‘μ—…μœΌλ‘œ ν‘œν˜„ν•˜λ €λ©΄ 맀우 κ³€λž€ν•©λ‹ˆλ‹€.
이처럼 μ‹œμ†ŒλŸ¬μŠ€λ₯Ό μ‚¬μš©ν•˜λŠ” 기법(λ‹¨μ–΄μ˜ 의미λ₯Ό μ‚¬λžŒμ΄ μ •μ˜ν•˜λŠ” 기법)μ—λŠ” μ»€λ‹€λž€ λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€.
이 문제λ₯Ό ν”Όν•˜κΈ° μœ„ν•΄, μ‚¬μš©ν•˜λŠ” ‘톡계 기반 기법’ κ³Ό 신경망을 μ‚¬μš©ν•œ ‘μΆ”λ‘  기반 기법’ 에 λ°ν•˜μ—¬ μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€.

톡계 기반 기법

μš°λ¦¬λŠ” 톡계 기반 기법을 μ‚¬μš©ν•˜λ©΄μ„œ Corpus(λ§λ­‰μΉ˜)λ₯Ό μ΄μš©ν• κ²λ‹ˆλ‹€.
  • CorpusλŠ” κ°„λ‹¨νžˆ λ§ν•˜λ©΄ λŒ€λŸ‰μ˜ Test Dataμž…λ‹ˆλ‹€.
  • λ‹€λ§Œ CorpusλŠ” NLPμ—°κ΅¬μ—μ„œμ˜ 염두λ₯Ό 두고 μˆ˜μ§‘λœ Test Dataλ₯Ό 일반적으둜 "Corpus(말λͺ½μΉ˜)" 라고 ν•©λ‹ˆλ‹€.
  • λ˜ν•œ 톡계 기반 κΈ°λ²•μ˜ λͺ©ν‘œλŠ” 이처럼 μ‚¬λžŒμ˜ μ§€μ‹μœΌλ‘œ κ°€λ“ν•œ Corpus(λ§λ­‰μΉ˜)μ—μ„œ μžλ™μœΌλ‘œ, 효율적으둜 κ·Έ 핡심을 μΆ”μΆœν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.
μžμ—°μ–΄ μ²˜λ¦¬μ— μ‚¬μš©λ˜λŠ” λ§λ­‰μΉ˜μ—λŠ” ν…μŠ€νŠΈ 데이터에 λŒ€ν•œ μΆ”κ°€ 정보가 ν¬ν•¨λ˜λŠ” κ²½μš°κ°€ 있 μŠ΅λ‹ˆλ‹€
μ˜ˆμ»¨λŒ€ ν…μŠ€νŠΈ λ°μ΄ν„°μ˜ 단어 각각에 ‘ν’ˆμ‚¬’κ°€ λ ˆμ΄λΈ”λ§λ  수 μžˆμŠ΅λ‹ˆλ‹€
이럴 경우 λ§λ­‰μ°¨λŠ” 컴퓨터가 닀루기 μ‰¬μš΄ ν˜•νƒœ 트리 ꡬ쑰둜 κ°€κ³΅λ˜μ–΄ μ£Όμ–΄μžλŠ” 것이 μΌλ°˜μ μž…λ‹ˆλ‹€
이 κΈ€μ—μ„œλŠ” λ‹¨μˆœν•œ ν…μŠ€νŠΈ λ°μ΄ν„°ν•˜λ‚˜μ˜ 큰 ν…μŠ€νŠΈ 파일)둜 μ£Όμ–΄μ‘Œλ‹€κ³  κ°€μ •ν•©λ‹ˆλ‹€

 

 

Corpus(λ§λ­‰μΉ˜) μ „μ²˜λ¦¬ ν•˜κΈ° by Python

μžμ—°μ–΄ μ²˜λ¦¬μ—λŠ” λ‹€μ–‘ν•œ λ§λ­‰μΉ˜κ°€ μ‚¬μš©λ©λ‹ˆλ‹€
  • 유λͺ…ν•œ κ²ƒμœΌλ‘œλŠ” μœ„ν‚€λ°±κ³ΌWikipedia와 ꡬ글 λ‰΄μŠ€Google News λ“±μ˜ ν…μŠ€νŠΈ 데이터λ₯Ό λ“€ 수 있죠
  • λ˜ν•œ μ…°μ΅μŠ€ν”Όμ–΄λ‚˜ λ‚˜μ“°λ©” μ†Œμ„Έν‚€ 같은 λŒ€λ¬Έν˜Έ 의 μž‘ν’ˆλ“€λ„ λ§λ­‰μΉ˜λ‘œ μ΄μš©λ©λ‹ˆλ‹€
  • μ΄λ²ˆμ—λŠ” λ¬Έμž₯ ν•˜λ‚˜λ‘œ 이뀄진 λ‹¨μˆœν•œ ν…μŠ€νŠΈλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. ν•œλ²ˆ ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.
text = 'You say goodbye and I say hello.'

 

  • 이처럼 λ¬Έμž₯ ν•˜λ‚˜λ‘œ 이뀄진 ν…μŠ€νŠΈλ₯Ό Corpus(λ§λ­‰μΉ˜)둜 μ΄μš©ν•©λ‹ˆλ‹€.
  • 싀전이라면 이 text에 수천 ,만 κ°œκ°€ λ„˜λŠ” λ¬Έμž₯이 (연이어) 담겨 μžˆμ„ κ²ƒμž…λ‹ˆλ‹€.
  • λ‹€λ§Œ, μ‰½κ²Œ μ„€λͺ…ν•˜κΈ° μœ„ν•΄μ„œ 이 μž‘μ€ ν…μŠ€νŠΈ 데이터 만으둜 μ „μ²˜λ¦¬λ₯Ό ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.
  • λ¨Όμ € textλ₯Ό 단어 λ‹¨μœ„λ‘œ λ‚˜λˆ λ³΄κ² μŠ΅λ‹ˆλ‹€.
text = text.lower()
text = text.replace('.’, '.')
text

'you say goodbye and i say hello.'
words = text.split(' ')
words
['you','say','goodbye', ‘and’, 'i', 'say', 'hello', '.']

 

  • lower() Methodλ₯Ό μ‚¬μš©ν•˜μ—¬ 문자λ₯Ό μ†Œλ¬Έμžλ‘œ λ³€ν™˜ν•©λ‹ˆλ‹€.
  • 그리고 split() Methodλ₯Ό μ΄λ™ν•˜μ—¬ 곡백을 κΈ°μ€€μœΌλ‘œ λΆ„ν• ν•©λ‹ˆλ‹€.
  • 이제 μ›λž˜μ˜ λ¬Έμž₯을 단어 λͺ©λ‘ ν˜•νƒœλ‘œ μ΄μš©ν•  수 있게 λ˜μ—ˆμŠ΅λ‹ˆλ‹€.
  • 단어 λ‹¨μœ„λ‘œ λΆ„ν• λ˜μ–΄ 닀루기가 μ‰¬μ›Œμ§„ 것은 μ‚¬μ‹€μ΄μ§€λ§Œ, 단어λ₯Ό ν…μŠ€νŠΈ κ·ΈλŒ€λ‘œ μ‘°μž‘ν•˜κΈ°λž€ μ—¬λŸ¬ λ©΄μ—μ„œ λΆˆνŽΈν•©λ‹ˆλ‹€.
  • κ·Έλž˜μ„œ 단어에 IDλ₯Ό λΆ€μ—¬ν•˜κ³ , ID의 리슀트둜 μ΄μš©ν•  수 μžˆλ„λ‘ ν•œ 번 더 μ†μ§ˆν•©λ‹ˆλ‹€.
  • 이λ₯Ό μœ„ν•œ 사전 μ€€λΉ„λ‘œ, 파이썬의 λ”•μ…”λ„ˆλ¦¬λ₯Ό μ΄μš©ν•˜μ—¬ 단어 ID와 단어λ₯Ό μ§μ§€μ–΄μ£ΌλŠ” λŒ€μ‘ν‘œλ₯Ό μž‘μ„±ν•©λ‹ˆλ‹€.
>>> word_to_id = {}
>>> id_to_word = {}

>>> for word in words:
...     if word not in word_to_id:
...         new_id = len(word_to_id)
...         word_to_id[word] = new_id
...         id_to_word[new_id] = word

 

  • 단어 IDμ—μ„œ λ‹¨μ–΄λ‘œμ˜ λ³€ν™˜μ€ id_to_wordκ°€ λ‹΄λ‹Ήν•˜λ©°(ν‚€κ°€ 단어 ID, 값이 단어), λ‹¨μ–΄μ—μ„œ 단어 ID둜의 λ³€ν™˜μ€ word_to_idκ°€ λ‹΄λ‹Ήν•©λ‹ˆλ‹€.
  • μ•žμ˜ μ½”λ“œλŠ” 단어 λ‹¨μœ„λ‘œ λΆ„ν• λœ words의 각 μ›μ†Œλ₯Ό μ²˜μŒλΆ€ν„° ν•˜λ‚˜μ”© μ‚΄νŽ΄λ³΄λ©΄μ„œ, 단어가 word_to_id에 λ“€μ–΄ μžˆμ§€ μ•ŠμœΌλ©΄ word_to_id와 id_to_word 각각에 μƒˆλ‘œμš΄ ID와 단어λ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€.
  • λ˜ν•œ μΆ”κ°€ μ‹œμ μ˜ λ”•μ…”λ„ˆλ¦¬ 길이가 μƒˆλ‘œμš΄ λ‹¨μ–΄μ˜ ID둜 μ„€μ •λ˜κΈ° λ•Œλ¬Έμ— 단어 IDλŠ” 0, 1, 2, … μ‹μœΌλ‘œ μ¦κ°€ν•©λ‹ˆλ‹€.
  • μ•„λž˜λŠ” 단어 ID와 λ‹¨μ–΄μ˜ λŒ€μ‘ν‘œμž…λ‹ˆλ‹€.
>>> id_to_word
{0: 'you', 1: 'say', 2: 'goodbye', 3: 'and', 4: 'i', 5: 'hello', 6: '.'}
>>> word_to_id
{'you': 0, 'say': 1, 'goodbye': 2, 'and': 3, 'i': 4, 'hello': 5, '.': 6}

 

  • 이처럼 λ”•μ…”λ„ˆλ¦¬λ₯Ό μ‚¬μš©ν•˜λ©΄ 단어λ₯Ό 가지고 단어 IDλ₯Ό κ²€μƒ‰ν•˜κ±°λ‚˜, λ°˜λŒ€λ‘œ 단어 IDλ₯Ό 가지고 단어λ₯Ό 검색할 수 μžˆμŠ΅λ‹ˆλ‹€.
>>> id_to_word[1]
'say'
>>> word_to_id['hello']
5

 

  • 그럼 λ§ˆμ§€λ§‰μœΌλ‘œ ‘단어 λͺ©λ‘’을 ‘단어 ID λͺ©λ‘’으둜 λ³€κ²½ν•΄λ΄…μ‹œλ‹€.
  • λ‹€μŒ μ½”λ“œμ—μ„œλŠ” 파이썬의 내포 comprehension ν‘œκΈ°λ₯Ό μ‚¬μš©ν•˜μ—¬ 단어 λͺ©λ‘μ—μ„œ 단어 ID λͺ©λ‘μœΌλ‘œ λ³€ν™˜ν•œ λ‹€μŒ, λ‹€μ‹œ λ„˜νŒŒμ΄ λ°°μ—΄λ‘œ λ³€ν™˜ν–ˆμŠ΅λ‹ˆλ‹€.
λ‚΄ν¬λž€ λ¦¬μŠ€νŠΈλ‚˜ λ”•μ…”λ„ˆλ¦¬ λ“±μ˜ 반볡문 처리λ₯Ό κ°„λ‹¨ν•˜κ²Œ μ“°κΈ° μœ„ν•œ κΈ°λ²•μž…λ‹ˆλ‹€.
>>> import numpy as np
>>> corpus = [word_to_id[w] for w in words]
>>> corpus = np.array(corpus)
>>> corpus
array([0, 1, 2, 3, 4, 1, 5, 6])

 

  • μ΄κ²ƒμœΌλ‘œ Corups(λ§λ­‰μΉ˜)λ₯Ό μ΄μš©ν•˜κΈ° μœ„ν•œ 사전 μ€€λΉ„λ₯Ό λ§ˆμ³€μŠ΅λ‹ˆλ‹€.
  • μ΄λŸ¬ν•œ 처리λ₯Ό ν•œ 데 λͺ¨μ•„ preprocess()λΌλŠ” ν•¨μˆ˜λ‘œ κ΅¬ν˜„ν•΄ λ³΄κ² μŠ΅λ‹ˆλ‹€.
def preprocess(text):
    text = text.lower()
    text = text.replace('.', ' .')
    words = text.split(' ')

    word_to_id = {}
    id_to_word = {}
    for word in words:
        if word not in word_to_id:
            new_id = len(word_to_id)
            word_to_id[word] = new_id
            id_to_word[new_id] = word

    corpus = np.array([word_to_id[w] for w in words])

    return corpus, word_to_id, id_to_word
  • 이 ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ Corpus(λ§λ­‰μΉ˜) μ „μ²˜λ¦¬λ₯Ό λ‹€μŒκ³Ό 같이 μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
>>> text = 'You say goodbye and I say hello.'
>>> corpus, word_to_id, id_to_word = preprocess(text)
  • μ΄κ²ƒμœΌλ‘œ λ§λ­‰μΉ˜ μ „μ²˜λ¦¬κ°€ λλ‚¬μŠ΅λ‹ˆλ‹€.
  • corpusλŠ” 단어 ID λͺ©λ‘, word_to_idλŠ” λ‹¨μ–΄μ—μ„œ 단어 ID둜의 λ”•μ…”λ„ˆλ¦¬, id_to_wordλŠ” 단어 IDμ—μ„œ λ‹¨μ–΄λ‘œμ˜ λ”•μ…”λ„ˆλ¦¬λ₯Ό λœ»ν•©λ‹ˆλ‹€.
  • μ΄μƒμœΌλ‘œ λ§λ­‰μΉ˜λ₯Ό λ‹€λ£° μ€€λΉ„λ₯Ό λ§ˆμ³€μŠ΅λ‹ˆλ‹€.

 

λ‹¨μ–΄μ˜ λΆ„μ‚° ν‘œν˜„

  • μ„Έμƒμ˜ λ‹€μ–‘ν•œ 색을 κ³ μœ ν•œ μ΄λ¦„μœΌλ‘œ λΆ€λ₯Ό μˆ˜λ„ μžˆμ§€λ§Œ, RGB와 같은 λ²‘ν„°λ‘œ ν‘œν˜„ν•˜λ©΄ 더 μ •ν™•ν•˜κ³  κ°„κ²°ν•˜κ²Œ ν‘œν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • 이와 λ§ˆμ°¬κ°€μ§€λ‘œ, 단어도 Vector(벑터)둜 ν‘œν˜„ν•˜μ—¬ κ·Έ 의미λ₯Ό μ •λŸ‰ν™”ν•˜κ³  관련성을 νŒŒμ•…ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • μ΄λŸ¬ν•œ λ‹¨μ–΄μ˜ 벑터 ν‘œν˜„μ„ 'λΆ„μ‚° ν‘œν˜„'이라고 ν•˜λ©°, μ΄λŠ” μžμ—°μ–΄ 처리 λΆ„μ•Όμ—μ„œ λ‹¨μ–΄μ˜ 의미λ₯Ό 효과적으둜 νŒŒμ•…ν•˜κΈ° μœ„ν•΄ μ€‘μš”ν•œ λ°©λ²•μž…λ‹ˆλ‹€.

 

Distributional Hypothesis - 뢄포 κ°€μ„€

졜근의 NLP 연ꡬ듀을 μ‚΄νŽ΄λ³΄λ©΄, μ€‘μš”ν•œ 기법듀이 ν•˜λ‚˜μ˜ κ°„λ‹¨ν•œ 아이디어에 κΈ°λ°˜ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.
λ°”λ‘œ 'λ‹¨μ–΄μ˜ μ˜λ―ΈλŠ” μ£Όλ³€ 단어에 μ˜ν•΄ ν˜•μ„±λœλ‹€' λΌλŠ” κ²ƒμž…λ‹ˆλ‹€. 이λ₯Ό 뢄포 κ°€μ„€ distributional hypothesis 이라고 ν•©λ‹ˆλ‹€.

 

  • 뢄포 가섀이 λ§ν•˜κ³ μž ν•˜λŠ” λ°”λŠ” 맀우 κ°„λ‹¨ν•©λ‹ˆλ‹€.
  • 단어 μžμ²΄μ—λŠ” μ˜λ―Έκ°€ μ—†κ³ , κ·Έ 단어가 μ‚¬μš©λœ ‘λ§₯락’(context)이 의미λ₯Ό ν˜•μ„±ν•œλ‹€λŠ” 것이죠.
  • λ¬Όλ‘  μ˜λ―Έκ°€ 같은 단어듀은 같은 λ§₯λ½μ—μ„œ 더 많이 λ“±μž₯ν•©λ‹ˆλ‹€.
  • 예λ₯Ό λ“€μ–΄ "I drink beer"와 "We drink wine"처럼 "drink"의 μ£Όλ³€μ—λŠ” μŒλ£Œκ°€ λ“±μž₯ν•˜κΈ° μ‰¬μšΈ κ²ƒμž…λ‹ˆλ‹€. 
  • μ•„λž˜μ˜ 그림은 쒌우의 두 단어씩이 'λ§₯락'에 ν•΄λ‹Ήν•©λ‹ˆλ‹€.

window 크기가 2인 'λ§₯랡'의 예. 단어 'goodbye'에 μ£Όλͺ©ν•œλ‹€λ©΄, κ·Έ 쒌우의 두 단어(총 4단어)λ₯Ό λ§₯락으둜 μ΄μš©ν•œλ‹€.

  • λ§₯락’μ΄λž€ νŠΉμ • 단어λ₯Ό 쀑심에 λ‘” κ·Έ μ£Όλ³€ 단어λ₯Ό λ§ν•©λ‹ˆλ‹€.
  • 그리고 λ§₯락의 크기(μ£Όλ³€ 단어λ₯Ό λͺ‡ κ°œλ‚˜ 포함할지)λ₯Όμœˆλ„μš° 크기’(window size)라고 ν•©λ‹ˆλ‹€.
  • μœˆλ„μš° 크기가 1이면 쒌우 ν•œ 단어씩이, μœˆλ„μš° 크기가 2이면 쒌우 두 단어씩이 λ§₯락에 ν¬ν•¨λ©λ‹ˆλ‹€.

 

Co-occurence Matrix - λ™μ‹œλ°œμƒ ν–‰λ ¬

Co-occurence Matrix(λ™μ‹œ λ°œμƒ ν–‰λ ¬)은 μ–΄λ–€ 단어λ₯Ό μ£Όλͺ©ν–ˆμ„λ•Œ, κ·Έ μ£Όλ²ˆμ— μ–΄λ–€ 단어가 λͺ‡ λ²ˆμ΄λ‚˜ λ“±μž₯ν•˜λŠ”μ§€λ₯Ό μ„Έμ–΄ μ§‘κ³„ν•˜λŠ” λ°©λ²•μž…λ‹ˆλ‹€.
  • ν•œλ²ˆ μ½”λ“œλ‘œ μ‚΄νŽ΄ λ³΄κ² μŠ΅λ‹ˆλ‹€.
import sys
sys.path.append('..')
import numpy as np
from common.util import preprocess

text = 'You say goodbye and I say hello.'
corpus, word_to_id, id_to_word = preprocess(text)

print(corpus)
# [0 1 2 3 4 1 5 6]

print(id_to_word)
# {0: 'you', 1: 'say', 2: 'goodbye', 3: 'and', 4: 'i', 5: 'hello', 6: '.'}
  • preprocess ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ ν…μŠ€νŠΈ 데이터λ₯Ό μ „μ²˜λ¦¬ν•©λ‹ˆλ‹€.
  • λ¨Όμ €, ν•„μš”ν•œ λͺ¨λ“ˆμ„ μž„ν¬νŠΈν•˜κ³  preprocess ν•¨μˆ˜λ₯Ό μ •μ˜ν•œ ν›„, 예제 ν…μŠ€νŠΈλ₯Ό μ „μ²˜λ¦¬ν•˜μ—¬ 단어 ID둜 λ³€ν™˜λœ λ§λ­‰μΉ˜μ™€ 단어-ID 맀핑 λ”•μ…”λ„ˆλ¦¬λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€.
  • 이λ₯Ό 톡해 ν…μŠ€νŠΈ 데이터λ₯Ό 벑터 ν˜•νƒœλ‘œ λ³€ν™˜ν•©λ‹ˆλ‹€.
  • κ²°κ³Όλ₯Ό 보면 λ‹¨μ–΄μˆ˜κ°€ 7κ°œμž„μ„ μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.

 

  • μ΄λ²ˆμ—λŠ” ν•œλ²ˆ 각 λ‹¨μ–΄μ˜ λ§₯λž΅μ— ν•΄λ‹Ήν•˜λŠ” λ‹¨μ–΄μ˜ λΉˆλ„λ₯Ό μ„Έμ–΄λ³΄κ² μŠ΅λ‹ˆλ‹€.
  • Window ν¬κΈ°λŠ” 1둜 ν•˜κ³ , 단어 IDκ°€ 0인 "you"λΆ€ν„° λ³΄κ² μŠ΅λ‹ˆλ‹€.

단어 "you" 의 λ§₯락을 μ„Έμ–΄λ΄…λ‹ˆλ‹€.

  • μœ„μ˜ κ·Έλ¦Όμ—μ„œ λ³Ό 수 μžˆλ“―, 단어 "you"의 λ§₯λž΅μ€ "say" ν•˜λ‚˜ λΏμž…λ‹ˆλ‹€. 이λ₯Ό ν‘œλ‘œ ν‘œν˜„ν•˜λ©΄ μ•„λž˜μ™€ ν‘œ 처럼 λ‚˜μ˜΅λ‹ˆλ‹€.

단어 "you"에 λ§₯λž΅μ— ν¬ν•¨λ˜λŠ” λ‹¨μ–΄μ˜ λΉˆλ„λ₯Ό ν‘œλ‘œ μ •λ¦¬ν•œλ‹€.

  • 단어 "you"의 λ§₯랡으둜써 λ™μ‹œμ— λ°œμƒ(λ“±μž₯)ν•˜λŠ” λ‹¨μ–΄μ˜ λΉˆλ„λ₯Ό λ‚˜νƒ€λ‚΄μ—ˆμŠ΅λ‹ˆλ‹€.
  • 그리고 이λ₯Ό λ°”νƒ•μœΌλ‘œ "you"λΌλŠ” 단어λ₯Ό [0, 1, 0, 0, 0, 0. 0]μ΄λΌλŠ” λ²‘ν„°λ‘œ ν‘œν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • 그리고 IDκ°€ 1인 "say"에 λŒ€ν•΄μ„œλ„ 같은 μž‘μ—…μ„ μˆ˜ν–‰ν•©λ‹ˆλ‹€. κ²°κ³ΌλŠ” μ•„λž˜μ—μ„œ λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

단어 "say"의 λ§₯λž΅μ— ν¬ν•¨λ˜λŠ” λ‹¨μ–΄μ˜ λΉˆλ„λ₯Ό ν‘œλ‘œ μ •λ¦¬ν•œκ²ƒ μž…λ‹ˆλ‹€.

  • μ΄λ ‡κ²Œ "say"λΌλŠ” λ‹¨μ–΄λŠ” Vector [1, 0, 1, 0, 1, 1, 0]으둜 ν‘œν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • 이 λͺ¨λ“  μž‘μ—…μ„ μˆ˜ν–‰ν•œ κ²°κ³ΌλŠ” μ•„λž˜μ˜ ν‘œκ³Ό κ°™μŠ΅λ‹ˆλ‹€.
  • 이 ν‘œλŠ” λͺ¨λ“  단어에 데해 λ™μ‹œλ°œμƒν•˜λŠ” 단어λ₯Ό ν‘œμ— μ •λ¦¬ν•œ κ²ƒμž…λ‹ˆλ‹€. 이 ν‘œμ˜ 각 행은 ν•΄λ‹Ή 단어λ₯Ό ν‘œν˜„ν•œ Vectorκ°€ λ©λ‹ˆλ‹€.
  • 그리고 이 ν‘œκ°€ Matrix(ν–‰λ ¬)의 ν˜•νƒœλ₯Ό λ€λ‹€λŠ” λœ»μ—μ„œ Co-occurence Matrix(λ™μ‹œλ°œμƒ ν–‰λ ¬)이라고 ν•©λ‹ˆλ‹€. ν•œλ²ˆ Python으둜 κ΅¬ν˜„ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.
C = np.array([
    [0, 1, 0, 0, 0, 0, 0],
    [1, 0, 1, 0, 1, 1, 0],
    [0, 1, 0, 1, 0, 0, 0],
    [0, 0, 1, 0, 1, 0, 0],
    [0, 1, 0, 1, 0, 1, 0],
    [0, 1, 0, 0, 1, 0, 1],
], dtype=np.int32)

 

  • 이 Co-occurence Matrix(λ™μ‹œλ°œμƒ ν–‰λ ¬)을 μ‚¬μš©ν•˜λ©΄ λ‹€μŒκ³Ό 같은 λ°©μ‹μœΌλ‘œ 각 λ‹¨μ–΄μ˜ Vectorλ₯Ό 얻을 수 μžˆμŠ΅λ‹ˆλ‹€.
print(C[0])  # IDκ°€ 0인 λ‹¨μ–΄μ˜ 벑터 ν‘œν˜„
# [0 1 0 0 0 0 0]

print(C[4])  # IDκ°€ 4인 λ‹¨μ–΄μ˜ 벑터 ν‘œν˜„
# [0 1 0 1 0 1 0]

print(C[word_to_id['goodbye']])  # "goodbye"의 벑터 ν‘œν˜„
# [0 1 0 1 0 1 0]

 

  • Co-occurence Matrix(λ™μ‹œλ°œμƒ ν–‰λ ¬)을 ν™œμš©ν•˜λ©΄ 단어λ₯Ό Vector둜 λ‚˜νƒ€λ‚Ό 수 μžˆμŠ΅λ‹ˆλ‹€.
  • 그리고 Co-occurence Matrix(λ™μ‹œλ°œμƒ ν–‰λ ¬)을 μžλ™ν™”ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.
  • 그러면 Corpus(λ§λ­‰μΉ˜)λ‘œλΆ€ν„° λ™μ‹œλ°œμƒ 행렬을 λ§Œλ“€μ–΄μ£ΌλŠ” ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•΄λ΄…μ‹œλ‹€.
  • μΈμˆ˜λ“€μ€ μ°¨λ‘€λ‘œ 단어 ID의 corpus(리슀트), vocab_size(μ–΄νœ˜ 수), window_size=1(μœˆλ„μš° 크기)λ₯Ό λ‚˜νƒ€λƒ…λ‹ˆλ‹€.
def create_co_matrix(corpus, vocab_size, window_size=1):
    # λ§λ­‰μΉ˜(corpus)의 크기λ₯Ό 계산
    corpus_size = len(corpus)
    # λ™μ‹œλ°œμƒ 행렬을 0으둜 μ΄ˆκΈ°ν™”. ν¬κΈ°λŠ” (μ–΄νœ˜ 수, μ–΄νœ˜ 수)
    co_matrix = np.zeros((vocab_size, vocab_size), dtype=np.int32)

    # λ§λ­‰μΉ˜μ˜ 각 단어에 λŒ€ν•΄ 반볡
    for idx, word_id in enumerate(corpus):
        # ν˜„μž¬ λ‹¨μ–΄μ˜ 쒌우 window_size λ²”μœ„ λ‚΄μ˜ 단어듀을 확인
        for i in range(1, window_size + 1):
            left_idx = idx - i
            right_idx = idx + i

            # 쒌츑 μœˆλ„μš° μΈλ±μŠ€κ°€ 0 이상일 경우
            if left_idx >= 0:
                # 쒌츑 λ‹¨μ–΄μ˜ IDλ₯Ό 가져와 λ™μ‹œλ°œμƒ 행렬을 μ—…λ°μ΄νŠΈ
                left_word_id = corpus[left_idx]
                co_matrix[word_id, left_word_id] += 1

            # 우츑 μœˆλ„μš° μΈλ±μŠ€κ°€ λ§λ­‰μΉ˜ 크기보닀 μž‘μ„ 경우
            if right_idx < corpus_size:
                # 우츑 λ‹¨μ–΄μ˜ IDλ₯Ό 가져와 λ™μ‹œλ°œμƒ 행렬을 μ—…λ°μ΄νŠΈ
                right_word_id = corpus[right_idx]
                co_matrix[word_id, right_word_id] += 1

    # μ΅œμ’… λ™μ‹œλ°œμƒ ν–‰λ ¬ λ°˜ν™˜
    return co_matrix

 

  • 이 ν•¨μˆ˜λŠ” λ¨Όμ € co_matrixλ₯Ό 0으둜 μ±„μ›Œμ§„ 2차원 Array둜 μ΄ˆκΈ°ν™”ν•©λ‹ˆλ‹€.
  • κ·Έλ‹€μŒμ€ Corpus의 λͺ¨λ“  단어 각각에 λŒ€ν•˜μ—¬ Window에 ν¬ν•¨λœ μ£Όλ³€ 단어λ₯Ό μ„Έμ–΄λ‚˜κ°‘λ‹ˆλ‹€.
  • μ΄λ•Œ Corpus의 μ™Όμͺ½ 끝과 였λ₯Έμͺ½ 끝 경계λ₯Ό λ²—μ–΄λ‚˜μ§€ μ•ŠλŠ”μ§€λ„ ν™•μΈν•©λ‹ˆλ‹€.

 

Vectorκ°„ μœ μ‚¬λ„

ν•œλ²ˆ Vector μ‚¬μ΄μ˜ μœ μ‚¬λ„λ₯Ό μΈ‘μ •ν•˜λŠ” 방법을 μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.
  • Vector(벑터) μ‚¬μ΄μ˜ μœ μ‚¬λ„λ₯Ό ν‘œν˜„ν•  λ•ŒλŠ” Cosine Similarity(코사인 μœ μ‚¬λ„)λ₯Ό 자주 μ΄μš©ν•©λ‹ˆλ‹€.
  • 두 벑터 π‘₯=(π‘₯1,π‘₯2,π‘₯3,β‹― ,π‘₯𝑛)κ³Ό 이 μžˆλ‹€λ©΄, 코사인 μœ μ‚¬λ„λŠ” λ‹€μŒ μ‹μœΌλ‘œ μ •μ˜λ©λ‹ˆλ‹€.

  • λΆ„μžμ—λŠ” Vector(벑터)의 내적이, λΆ„λͺ¨μ—λŠ” 각 Vector(벑터)의 노름(norm)이 λ“±μž₯ν•©λ‹ˆλ‹€.
  • 노름은 Vector(벑터)의 크기λ₯Ό λ‚˜νƒ€λ‚Έ κ²ƒμœΌλ‘œ, μ—¬κΈ°μ„œλŠ” 노름을 κ³„μ‚°ν•©λ‹ˆλ‹€ ( 노름은 λ²‘ν„°μ˜ 각 μ›μ†Œλ₯Ό μ œκ³±ν•΄ λ”ν•œ ν›„ λ‹€μ‹œ μ œκ³±κ·Όμ„ ꡬ해 κ³„μ‚°ν•©λ‹ˆλ‹€).
  • μ΄μ‹μ˜ 핡심은 Vector(벑터)λ₯Ό μ •κ·œν™”ν•˜κ³  내적을 κ΅¬ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.
코사인 μœ μ‚¬λ„λ₯Ό μ§κ΄€μ μœΌλ‘œ ν’€μ–΄λ³΄μžλ©΄ ‘두 벑터가 κ°€λ¦¬ν‚€λŠ” λ°©ν–₯이 μ–Όλ§ˆλ‚˜ λΉ„μŠ·ν•œκ°€’μž…λ‹ˆλ‹€.
두 λ²‘ν„°μ˜ λ°©ν–₯이 μ™„μ „νžˆ κ°™μœΌλ©΄ 코사인 μœ μ‚¬λ„κ°€ 1이 되며, μ™„μ „νžˆ λ°˜λŒ€λΌλ©΄ -1이 λ©λ‹ˆλ‹€.

 

  • 그러면 이제 Cosine Similarity(코사인 μœ μ‚¬λ„)λ₯Ό Python ν•¨μˆ˜λ‘œ κ΅¬ν˜„ν•΄ λ³΄κ² μŠ΅λ‹ˆλ‹€.
def cos_similarity(x, y):
    nx = x / np.sqrt(np.sum(x**2))  # x의 μ •κ·œν™”
    ny = y / np.sqrt(np.sum(y**2))  # y의 μ •κ·œν™”
    return np.dot(nx, ny)

 

  • ν•¨μˆ˜λŠ” λ¨Όμ € 벑터 x와 yλ₯Ό μ •κ·œν™”ν•œ ν›„ 두 Vector(벑터)의 내적을 κ΅¬ν–ˆμŠ΅λ‹ˆλ‹€.
  • μ΄λ ‡κ²Œλ§Œ 해도 Cosine Similarity(코사인 μœ μ‚¬λ„)λ₯Ό ꡬ할 수 μžˆμŠ΅λ‹ˆλ‹€λ§Œ, 사싀 이 κ΅¬ν˜„μ—λŠ” λ¬Έμ œκ°€ ν•˜λ‚˜ μžˆμŠ΅λ‹ˆλ‹€.
  • 인수둜 Zero Vector(제둜 벑터 - μ›μ†Œκ°€ λͺ¨λ‘ 0인 Vector)κ°€ λ“€μ–΄μ˜€λ©΄ 0으둜 λ‚˜λˆ„κΈ°(divide by zero) 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€.
  • 이 문제λ₯Ό ν•΄κ²°ν•˜λŠ” 전톡적인 방법은 λ‚˜λˆ—μ…ˆ λΆ„λͺ¨μ— μž‘μ€ 값을 λ”ν•΄μ£ΌλŠ” κ²ƒμž…λ‹ˆλ‹€. μ•„λž˜λŠ” κ°œμ„ λœ μ½”λ“œ μž…λ‹ˆλ‹€.
def cos_similarity(x, y, eps=1e-8):
    nx = x / (np.sqrt(np.sum(x ** 2)) + eps)
    ny = y / (np.sqrt(np.sum(y ** 2)) + eps)
    return np.dot(nx, ny)

 

  • μ•„λž˜λŠ” μ΅œμ’…μ μœΌλ‘œ 단어 "you"와 "i"의 μœ μ‚¬λ„λ₯Ό κ΅¬ν•˜λŠ” μ½”λ“œμž…λ‹ˆλ‹€.
import sys
sys.path.append('..')
from common.util import preprocess, create_co_matrix, cos_similarity

text = 'You say goodbye and I say hello.'
corpus, word_to_id, id_to_word = preprocess(text)
vocab_size = len(word_to_id)
C = create_co_matrix(corpus, vocab_size)

c0 = C[word_to_id['you']]  # "you"의 단어 벑터
c1 = C[word_to_id['i']]  # "i"의 단어 벑터
print(cos_similarity(c0, c1))
# 0.7071067691154799
μ‹€ν–‰ κ²°κ³Ό "you"와 "i"의 코사인 μœ μ‚¬λ„λŠ” 0.70...으둜 λ‚˜μ™”μŠ΅λ‹ˆλ‹€
코사인 μœ μ‚¬λ„ 값은 -1μ—μ„œ 1 μ‚¬μ΄μ΄λ―€λ‘œ, 이 값은 비ꡐ적 λ†’λ‹€(μœ μ‚¬μ„±μ΄ 크닀)κ³  말할 수 μžˆμŠ΅λ‹ˆλ‹€.

μœ μ‚¬ λ‹¨μ–΄μ˜ λž­ν‚Ή ν‘œμ‹œ

μ–΄λ–€ 단어가 κ²€μƒ‰μ–΄λ‘œ 주어지면, κ·Έ 검색어와 λΉ„μŠ·ν•œ 단어λ₯Ό μœ μ‚¬λ„ 순으둜 좜λ ₯ν•˜λŠ” ν•¨μˆ˜λŠ” μ–΄λ–¨κΉŒμš”?
κ·Έ ν•¨μˆ˜ 이름은 most_similar()둜 ν•˜κ³ , λ‹€μŒ μΈμˆ˜λ“€μ„ μž…λ ₯받도둝 κ΅¬ν˜„ν•΄λ΄…μ‹œλ‹€.
most_similar(query, word_to_id, id_to_word, word_matrix, top=5)
  • most_similar() ν•¨μˆ˜μ˜ 인수
인수λͺ… μ„€λͺ…
query 검색어(단어)
word_to_id λ‹¨μ–΄μ—μ„œ 단어 ID둜의 λ”•μ…”λ„ˆλ¦¬
id_to_word 단어 IDμ—μ„œ λ‹¨μ–΄λ‘œμ˜ λ”•μ…”λ„ˆλ¦¬
word_matrix 단어 벑터듀을 ν•œλ° λͺ¨μ€ ν–‰λ ¬. 각 ν–‰μ—λŠ” λŒ€μ‘ν•˜λŠ” λ‹¨μ–΄μ˜ 벑터가 μ €μž₯λ˜μ–΄ μžˆλ‹€κ³  κ°€μ •ν•œλ‹€.
top μƒμœ„ λͺ‡ κ°œκΉŒμ§€ 좜λ ₯할지 μ„€μ •
  • most_similar() ν•¨μˆ˜μ˜ κ΅¬ν˜„μ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.
def most_similar(query, word_to_id, id_to_word, word_matrix, top=5):
    # 1. 검색어λ₯Ό κΊΌλ‚Έλ‹€.
    if query not in word_to_id:
        print('%s(을)λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€.' % query)
        return

    print('\n[query] ' + query)
    query_id = word_to_id[query]
    query_vec = word_matrix[query_id]

    # 2. 코사인 μœ μ‚¬λ„ 계산
    vocab_size = len(id_to_word)
    similarity = np.zeros(vocab_size)
    for i in range(vocab_size):
        similarity[i] = cos_similarity(word_matrix[i], query_vec)

    # 3. 코사인 μœ μ‚¬λ„λ₯Ό κΈ°μ€€μœΌλ‘œ λ‚΄λ¦Όμ°¨μˆœμœΌλ‘œ 좜λ ₯
    count = 0
    for i in (-1 * similarity).argsort():
        if id_to_word[i] == query:
            continue
        print(' %s: %s' % (id_to_word[i], similarity[i]))

        count += 1
        if count >= top:
            return
  • 이 μ½”λ“œμ˜ λ™μž‘μˆœμ„œλŠ” μ•„λž˜μ™€ 같이 λ™μž‘ν•©λ‹ˆλ‹€.
  1. κ²€μƒ‰μ–΄μ˜ 단어 벑터λ₯Ό κΊΌλƒ…λ‹ˆλ‹€.
  2. κ²€μƒ‰μ–΄μ˜ 단어 벑터와 λ‹€λ₯Έ λͺ¨λ“  단어 λ²‘ν„°μ™€μ˜ 코사인 μœ μ‚¬λ„λ₯Ό 각각 κ΅¬ν•©λ‹ˆλ‹€.
  3. κ³„μ‚°ν•œ 코사인 μœ μ‚¬λ„ κ²°κ³Όλ₯Ό κΈ°μ€€μœΌλ‘œ 값이 높은 μˆœμ„œλŒ€λ‘œ 좜λ ₯ν•©λ‹ˆλ‹€.

 

  • 3번째 μ½”λ“œμ— 뢀뢄에 λ°ν•œ μ„€λͺ…을 쑰금만 덧뢙이면, similarity 배열에 λ‹΄κΈ΄ μ›μ†Œμ˜ 인덱슀λ₯Ό λ‚΄λ¦Όμ°¨μˆœμœΌλ‘œ μ •λ ¬ν•œ ν›„ μƒμœ„ μ›μ†Œλ“€μ„ 좜λ ₯ν•©λ‹ˆλ‹€.
  • μ΄λ•Œ λ°°μ—΄ 인덱슀의 정렬을 λ°”κΎΈλŠ” 데 μ‚¬μš©ν•œ argsort() λ©”μ„œλ“œλŠ” λ„˜νŒŒμ΄ λ°°μ—΄μ˜ μ›μ†Œλ₯Ό μ˜€λ¦„μ°¨μˆœμœΌλ‘œ μ •λ ¬ν•©λ‹ˆλ‹€.
  • μ•„λž˜λŠ” argsort() Method의 μ‚¬μš© μ˜ˆμ‹œ μž…λ‹ˆλ‹€.
>>> x = np.array([100, -20, 2])
>>> x.argsort()
array([1, 2, 0])
  • 이처럼 argsort()λ₯Ό μ‚¬μš©ν•˜λ©΄ λ‹¨μ–΄μ˜ μœ μ‚¬λ„κ°€ 높은 μˆœμ„œλ‘œ 좜λ ₯ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • 이것이 most_similar() ν•¨μˆ˜μ˜ κ΅¬ν˜„μž…λ‹ˆλ‹€. ν•œλ²ˆ "you"λ₯Ό κ²€μƒ‰μ–΄λ‘œ 지정해 μœ μ‚¬ν•œ 단어듀을 좜λ ₯ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.
import sys
sys.path.append('..')  # μƒμœ„ 디렉토리λ₯Ό λͺ¨λ“ˆ 검색 κ²½λ‘œμ— μΆ”κ°€
from common.util import preprocess, create_co_matrix, most_similar  # ν•„μš”ν•œ ν•¨μˆ˜λ“€ μž„ν¬νŠΈ

# μž…λ ₯ ν…μŠ€νŠΈ
text = 'You say goodbye and I say hello.'

# ν…μŠ€νŠΈ μ „μ²˜λ¦¬: 단어 λͺ©λ‘κ³Ό 단어-인덱슀 맀핑, 인덱슀-단어 맀핑 생성
corpus, word_to_id, id_to_word = preprocess(text)

# μ–΄νœ˜ μ‚¬μ „μ˜ 크기
vocab_size = len(word_to_id)

# λ™μ‹œλ°œμƒ ν–‰λ ¬ 생성
C = create_co_matrix(corpus, vocab_size)

# νŠΉμ • 단어와 μœ μ‚¬ν•œ 단어듀을 μ°Ύκ³  좜λ ₯ (μ—¬κΈ°μ„œλŠ” 'you'와 μœ μ‚¬ν•œ 단어듀)
most_similar('you', word_to_id, id_to_word, C, top=5)
  • μ•„λž˜μ˜ μ½”λ“œμ˜ μ‹€ν–‰ κ²°κ³Ό μž…λ‹ˆλ‹€.
[query] you
goodbye: 0.7071067691154799
i: 0.7071067691154799
hello: 0.7071067691154799
say: 0.0
and: 0.0
  • 이 κ²°κ³ΌλŠ” 검색어 "you"와 μœ μ‚¬ν•œ 단어λ₯Ό μƒμœ„ 5개만 좜λ ₯ν•œ κ²ƒμž…λ‹ˆλ‹€.
  • Cosine Similarity(코사인 μœ μ‚¬λ„)λŠ” ν•΄λ‹Ή λ‹¨μ–΄μ˜ 였λ₯Έμͺ½μ—μ„œ λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.
  • κ²°κ³Όλ₯Ό 보면 "you"에 κ°€μž₯ κ°€κΉŒμš΄ λ‹¨μ–΄λŠ” 총 3개인데, μ°¨λ‘€λ‘œ "goodbye", "i(=λ‚˜)", "hello"μž…λ‹ˆλ‹€.
  • ν™•μ‹€νžˆ "i"와 "you" λͺ¨λ‘ μΈμΉ­λŒ€λͺ…μ‚¬μ΄λ―€λ‘œ λ‘˜μ΄ λΉ„μŠ·ν•˜λ‹€λŠ” 건 납득이 λ©λ‹ˆλ‹€.
  • ν•˜μ§€λ§Œ "goodbye"와 "hello"의 Cosine Similarity(코사인 μœ μ‚¬λ„)κ°€ λ†’λ‹€λŠ” 것은 우리의 μ§κ΄€κ³ΌλŠ” 거리가 λ©€μ£ .
  • μ΄μœ λŠ” μ§€κΈˆμ€ Corpus(λ§λ­‰μΉ˜), 즉 λ°μ΄ν„°μ…‹μ˜ 크기가 λ„ˆλ¬΄ μž‘λ‹€λŠ” 것이 원인이라고 λ³Ό 수 μžˆμ„κ²ƒ κ°™μŠ΅λ‹ˆλ‹€.

Summary

WordNet λ“±μ˜ Thesaursusλ₯Ό μ΄μš©ν•˜λ©΄ μœ μ˜μ–΄λ₯Ό μ–»κ±°λ‚˜ 단어 μ‚¬μ΄μ˜ μœ μ‚¬λ„λ₯Ό μΈ‘μ •ν•˜λŠ” λ“± μœ μš©ν•œ μž‘μ—…μ„ ν•  수 μžˆλ‹€.
Thesaursus 기반 기법은 Thesaursusλ₯Ό μž‘μ„±ν•˜λŠ” 데 μ—„μ²­λ‚œ 인적 μžμ›μ΄ λ“ λ‹€κ±°λ‚˜ μƒˆλ‘œμš΄ 단어에 λŒ€μ‘ν•˜κΈ° μ–΄λ ΅λ‹€λŠ” λ¬Έμ œκ°€ μžˆλ‹€.
ν˜„μž¬λŠ” Corpus(λ§λ­‰μΉ˜)λ₯Ό μ΄μš©ν•΄ 단어λ₯Ό Vectorν™”ν•˜λŠ” 방식이 주둜 쓰인닀.
졜근의 단어 Vectorν™” 기법듀은 λŒ€λΆ€λΆ„ 'λ‹¨μ–΄μ˜ μ˜λ―ΈλŠ” μ£Όλ³€ 단어에 μ˜ν•΄ ν˜•μ„±λœλ‹€'λŠ” 뢄포 가섀에 κΈ°μ΄ˆν•œλ‹€.
톡계 기반 기법은 Corpus(λ§λ­‰μΉ˜) μ•ˆμ˜ 각 단어에 λŒ€ν•΄μ„œ κ·Έ λ‹¨μ–΄μ˜ μ£Όλ³€ λ‹¨μ–΄μ˜ λΉˆλ„λ₯Ό μ§‘κ³„ν•œλ‹€ (Co-Occurance Matrix).