bab2min / Kiwi

Kiwi(지능형 한국어 형태소 분석기)
https://lab.bab2min.pe.kr/kiwi
Other
396 stars 46 forks source link

입력 텍스트 내의 빈도 정보를 활용한 미등재어 추정 #166

Open bab2min opened 1 month ago

bab2min commented 1 month ago

핵심적인 단어, 키워드는 글 전체에서 여러 번 사용되는 경향이 있음. 핵심 키워드가 종종 미등재어나 신조어인 경우가 있는데, 이 때 글 내에서 여러 번 등장하는 키워드들이 형태소 분석 과정에서 서로 다 다른 조합으로 분해되는 경우가 많다. 이런 경우 빈도 정보를 통해 자주 반복되는 키워드를 미리 신조어 취급하여 분석하면 해당 키워드들에 대해 일관적인 결과를 얻을 수 있지 않을까?

예시: 알리오올리오가 핵심 단어인 글(총 3회 등장) 시작은 드라마 〈파스타〉였다. 많은 내 또래들이 이 드라마를 통해 ‘알리오올리오’에 입문했으리라. 드라마를 보던 당시, 나는 취업을 준비하던 백수였고 집에 올리브유와 마늘쯤은 있었다. 이름을 처음 접했던 페퍼론치노는 청양고추로 맛을 내면 될 일. 한번 따라 해 보자는 마음으로 알리오올리오를 가볍게 만들어 봤다. 역시나 맛이 없었다. 모든 재료들이 겉도는 밍밍한 맛과 이빨에 들러붙을 정도로 딱딱한 면의 식감에 고개가 갸우뚱. 제대로 된 알리오올리오는 얼마나 맛있길래

이 글을 Kiwi v0.17.1에서 분석하면 다음과 같은 결과가 나온다.

[ ...
  Token(form='통하', tag='VV', start=34, len=2),
  Token(form='어', tag='EC', start=35, len=1),
  Token(form='‘', tag='SSO', start=37, len=1),
  Token(form='알리오올리오', tag='NNG', start=38, len=6), # NNG로 추출
  Token(form='’', tag='SSC', start=44, len=1),
  Token(form='에', tag='JKB', start=45, len=1),
  Token(form='입문', tag='NNG', start=47, len=2),
  ...
  Token(form='마음', tag='NNG', start=150, len=2),
  Token(form='으로', tag='JKB', start=152, len=2),
  Token(form='알리', tag='VV', start=155, len=2), # 동사+어미로 분해
  Token(form='오', tag='EC', start=157, len=1),
  Token(form='올리', tag='VV', start=158, len=2),
  Token(form='오', tag='EC', start=160, len=1),
  Token(form='를', tag='JKO', start=161, len=1),
  Token(form='가볍', tag='VA-I', start=163, len=2),
  Token(form='게', tag='EC', start=165, len=1),
  ...
  Token(form='제대로', tag='MAG', start=239, len=3),
  Token(form='되', tag='VV', start=243, len=1),
  Token(form='ᆫ', tag='ETM', start=243, len=1),
  Token(form='알리', tag='VV', start=245, len=2), # 동사+어미로 분해
  Token(form='오', tag='EC', start=247, len=1),
  Token(form='올리', tag='VV', start=248, len=2),
  Token(form='오', tag='EC', start=250, len=1),
  Token(form='는', tag='JX', start=251, len=1),
  Token(form='얼마나', tag='MAG', start=253, len=3),
  ...],
전체 분석 결과 ```python [Token(form='시작', tag='NNG', start=0, len=2), Token(form='은', tag='JX', start=2, len=1), Token(form='드라마', tag='NNG', start=4, len=3), Token(form='〈', tag='SSO', start=8, len=1), Token(form='파스타', tag='NNG', start=9, len=3), Token(form='〉', tag='SSC', start=12, len=1), Token(form='이', tag='VCP', start=13, len=1), Token(form='었', tag='EP', start=13, len=1), Token(form='다', tag='EF', start=14, len=1), Token(form='.', tag='SF', start=15, len=1), Token(form='많', tag='VA', start=17, len=1), Token(form='은', tag='ETM', start=18, len=1), Token(form='나', tag='NP', start=20, len=1), Token(form='의', tag='JKG', start=20, len=1), Token(form='또래', tag='NNG', start=22, len=2), Token(form='들', tag='XSN', start=24, len=1), Token(form='이', tag='JKS', start=25, len=1), Token(form='이', tag='MM', start=27, len=1), Token(form='드라마', tag='NNG', start=29, len=3), Token(form='를', tag='JKO', start=32, len=1), Token(form='통하', tag='VV', start=34, len=2), Token(form='어', tag='EC', start=35, len=1), Token(form='‘', tag='SSO', start=37, len=1), Token(form='알리오올리오', tag='NNG', start=38, len=6), Token(form='’', tag='SSC', start=44, len=1), Token(form='에', tag='JKB', start=45, len=1), Token(form='입문', tag='NNG', start=47, len=2), Token(form='하', tag='XSV', start=49, len=1), Token(form='었', tag='EP', start=49, len=1), Token(form='으리라', tag='EF', start=50, len=3), Token(form='.', tag='SF', start=53, len=1), Token(form='드라마', tag='NNG', start=55, len=3), Token(form='를', tag='JKO', start=58, len=1), Token(form='보', tag='VV', start=60, len=1), Token(form='던', tag='ETM', start=61, len=1), Token(form='당시', tag='NNG', start=63, len=2), Token(form=',', tag='SP', start=65, len=1), Token(form='나', tag='NP', start=67, len=1), Token(form='는', tag='JX', start=68, len=1), Token(form='취업', tag='NNG', start=70, len=2), Token(form='을', tag='JKO', start=72, len=1), Token(form='준비', tag='NNG', start=74, len=2), Token(form='하', tag='XSV', start=76, len=1), Token(form='던', tag='ETM', start=77, len=1), Token(form='백수', tag='NNG', start=79, len=2), Token(form='이', tag='VCP', start=81, len=1), Token(form='었', tag='EP', start=81, len=1), Token(form='고', tag='EC', start=82, len=1), Token(form='집', tag='NNG', start=84, len=1), Token(form='에', tag='JKB', start=85, len=1), Token(form='올리브유', tag='NNG', start=87, len=4), Token(form='와', tag='JC', start=91, len=1), Token(form='마늘', tag='NNG', start=93, len=2), Token(form='쯤', tag='XSN', start=95, len=1), Token(form='은', tag='JX', start=96, len=1), Token(form='있', tag='VV', start=98, len=1), Token(form='었', tag='EP', start=99, len=1), Token(form='다', tag='EF', start=100, len=1), Token(form='.', tag='SF', start=101, len=1), Token(form='이름', tag='NNG', start=103, len=2), Token(form='을', tag='JKO', start=105, len=1), Token(form='처음', tag='NNG', start=107, len=2), Token(form='접하', tag='VV', start=110, len=2), Token(form='었', tag='EP', start=111, len=1), Token(form='던', tag='ETM', start=112, len=1), Token(form='페퍼론치노', tag='NNP', start=114, len=5), Token(form='는', tag='JX', start=119, len=1), Token(form='청양고추', tag='NNG', start=121, len=4), Token(form='로', tag='JKB', start=125, len=1), Token(form='맛', tag='NNG', start=127, len=1), Token(form='을', tag='JKO', start=128, len=1), Token(form='내', tag='VV', start=130, len=1), Token(form='면', tag='EC', start=131, len=1), Token(form='되', tag='VV', start=133, len=1), Token(form='ᆯ', tag='ETM', start=133, len=1), Token(form='일', tag='NNG', start=135, len=1), Token(form='.', tag='SF', start=136, len=1), Token(form='한번', tag='MAG', start=138, len=2), Token(form='따르', tag='VV', start=141, len=2), Token(form='어', tag='EC', start=142, len=1), Token(form='하', tag='VV', start=144, len=1), Token(form='어', tag='EC', start=144, len=1), Token(form='보', tag='VX', start=146, len=1), Token(form='자는', tag='ETM', start=147, len=2), Token(form='마음', tag='NNG', start=150, len=2), Token(form='으로', tag='JKB', start=152, len=2), Token(form='알리', tag='VV', start=155, len=2), Token(form='오', tag='EC', start=157, len=1), Token(form='올리', tag='VV', start=158, len=2), Token(form='오', tag='EC', start=160, len=1), Token(form='를', tag='JKO', start=161, len=1), Token(form='가볍', tag='VA-I', start=163, len=2), Token(form='게', tag='EC', start=165, len=1), Token(form='만들', tag='VV', start=167, len=2), Token(form='어', tag='EC', start=169, len=1), Token(form='보', tag='VX', start=171, len=1), Token(form='었', tag='EP', start=171, len=1), Token(form='다', tag='EF', start=172, len=1), Token(form='.', tag='SF', start=173, len=1), Token(form='역시', tag='MAG', start=175, len=2), Token(form='나', tag='JX', start=177, len=1), Token(form='맛', tag='NNG', start=179, len=1), Token(form='이', tag='JKS', start=180, len=1), Token(form='없', tag='VA', start=182, len=1), Token(form='었', tag='EP', start=183, len=1), Token(form='다', tag='EF', start=184, len=1), Token(form='.', tag='SF', start=185, len=1), Token(form='모든', tag='MM', start=187, len=2), Token(form='재료', tag='NNG', start=190, len=2), Token(form='들', tag='XSN', start=192, len=1), Token(form='이', tag='JKS', start=193, len=1), Token(form='겉돌', tag='VV', start=195, len=2), Token(form='는', tag='ETM', start=197, len=1), Token(form='밍밍', tag='XR', start=199, len=2), Token(form='하', tag='XSA', start=201, len=1), Token(form='ᆫ', tag='ETM', start=201, len=1), Token(form='맛', tag='NNG', start=203, len=1), Token(form='과', tag='JC', start=204, len=1), Token(form='이빨', tag='NNG', start=206, len=2), Token(form='에', tag='JKB', start=208, len=1), Token(form='들러붙', tag='VV', start=210, len=3), Token(form='을', tag='ETM', start=213, len=1), Token(form='정도', tag='NNG', start=215, len=2), Token(form='로', tag='JKB', start=217, len=1), Token(form='딱딱', tag='XR', start=219, len=2), Token(form='하', tag='XSA', start=221, len=1), Token(form='ᆫ', tag='ETM', start=221, len=1), Token(form='면', tag='NNG', start=223, len=1), Token(form='의', tag='JKG', start=224, len=1), Token(form='식감', tag='NNG', start=226, len=2), Token(form='에', tag='JKB', start=228, len=1), Token(form='고개', tag='NNG', start=230, len=2), Token(form='가', tag='JKS', start=232, len=1), Token(form='갸우뚱', tag='MAG', start=234, len=3), Token(form='.', tag='SF', start=237, len=1), Token(form='제대로', tag='MAG', start=239, len=3), Token(form='되', tag='VV', start=243, len=1), Token(form='ᆫ', tag='ETM', start=243, len=1), Token(form='알리', tag='VV', start=245, len=2), Token(form='오', tag='EC', start=247, len=1), Token(form='올리', tag='VV', start=248, len=2), Token(form='오', tag='EC', start=250, len=1), Token(form='는', tag='JX', start=251, len=1), Token(form='얼마나', tag='MAG', start=253, len=3), Token(form='맛있', tag='VA', start=257, len=2), Token(form='길래', tag='EC', start=259, len=2)], ```

구체적으로 다음과 같은 조건을 사용하여 핵심 키워드인 미등재어를 추출할 수 있지 않을까?

이를 구현하기 위해서는 입력 텍스트 내의 모든 substring의 빈도를 조사해야하는데 이는 suffix-array 기반의 FM-index를 구축하면 빠르게 처리할 수 있다.