python-support icon indicating copy to clipboard operation
python-support copied to clipboard

Tagger API를 통해서 문장을 분석하면 원문의 띄어쓰기가 무조건 변경되어 분석의 어려움이 있습니다.

Open TaeHwan-Lee opened this issue 6 years ago • 3 comments

기초정보

  • Python 버전이 얼마입니까? 3.6
    • [ ] 3.5.x
    • [x] 3.6.x
  • KoalaNLP 버전이 얼마인가요? 2.0.9
    • [ ] 1.x
    • [x] 2.x
  • 문제의 유형은 어떤 것인가요? 개선점제안
    • [ ] 버그리포트
    • [x] 개선점제안
    • [ ] 사용법질문
    • [ ] 기타

재연을 위한 정보

  • 어떤 문장을 시도하셨습니까?
[1989년 2월 15일 여의도 농민 폭력 시위를 주도한 혐의(폭력행위등처벌에관한법률위반)으로 지명수배되었다. 1989년 3월 12일 서울지방검찰청 공안부는 임종석의 사전구속영장을 발부받았다. 같은 해 6월 30일 평양축전에 임수경을 대표로 파견하여 국가보안법위반 혐의가 추가되었다. 경찰은 12월 18일~20일 사이 서울 경희대학교에서 임종석이 성명 발표를 추진하고 있다는 첩보를 입수했고, 12월 18일 오전 7시 40분 경 가스총과 전자봉으로 무장한 특공조 및 대공과 직원 12명 등 22명의 사복 경찰을 승용차 8대에 나누어 경희대학교에 투입했다. 1989년 12월 18일 오전 8시 15분 경 서울청량리경찰서는 호위 학생 5명과 함께 경희대학교 학생회관 건물 계단을 내려오는 임종석을 발견, 검거해 구속을 집행했다. 임종석은 청량리경찰서에서 약 1시간 동안 조사를 받은 뒤 오전 9시 50분 경 서울 장안동의 서울지방경찰청 공안분실로 인계되었다.]
  • KoalaNLP를 사용한 코드 부분을 보여주세요.
from koalanlp.Util import initialize, finalize
from koalanlp.proc import *
from koalanlp import API

#초기화 합니다.
initialize(java_options="-Xmx4g -Dfile.encoding=utf-8", KMR="2.0.6", EUNJEON="2.0.6", DAON="2.0.6")

# mecab(은전한닢) 품사분석기
tagger_ej = Tagger(API.EUNJEON)

# -> return : koalanlp.data.Sentence
tt =  "1989년 2월 15일 여의도 농민 폭력 시위를 주도한 혐의(폭력행위등처벌에관한법률위반)으로 지명수배되었다. 1989년 3월 12일 서울지방검찰청 공안부는 임종석의 사전구속영장을 발부받았다. 같은 해 6월 30일 평양축전에 임수경을 대표로 파견하여 국가보안법위반 혐의가 추가되었다. 경찰은 12월 18일~20일 사이 서울 경희대학교에서 임종석이 성명 발표를 추진하고 있다는 첩보를 입수했고, 12월 18일 오전 7시 40분 경 가스총과 전자봉으로 무장한 특공조 및 대공과 직원 12명 등 22명의 사복 경찰을 승용차 8대에 나누어 경희대학교에 투입했다. 1989년 12월 18일 오전 8시 15분 경 서울청량리경찰서는 호위 학생 5명과 함께 경희대학교 학생회관 건물 계단을 내려오는 임종석을 발견, 검거해 구속을 집행했다. 임종석은 청량리경찰서에서 약 1시간 동안 조사를 받은 뒤 오전 9시 50분 경 서울 장안동의 서울지방경찰청 공안분실로 인계되었다."
position = 0
text = ''
text_encoding = ''
morp_list = []
position_list = []
lemma_list = []

#1.문장전체 파싱
tagged_ej = tagger_ej.tagSentence(tt)

#1.1.원문장 인코딩
tt_encoding = tt.encode()

#2 koalanlp 파싱
for i, sentence in enumerate(tagged_ej):
  print(i+1,'번째 문장')
  print(sentence) #koalanlp.data.Sentence 
  for _, word in enumerate(sentence):
    #2.2.1 위치정보 계산
    tt_temp_encoding = tt_encoding

    word_surface = word.getSurface()
    m_word_encoding = word_surface.encode()
    print('word_surface :', word_surface)

    tt_len = len(m_word_encoding)

    print(tt_temp_encoding.decode())

    for j, _ in enumerate(tt_temp_encoding):
      if ( m_word_encoding == tt_encoding[:tt_len] ):
        text += word_surface
        tt_encoding = tt_temp_encoding[tt_len + j:]
        print('OK')
        break
      else if ( m_word_encoding == tt_encoding[:tt_len] ):
        print(j)
        print(tt_temp_encoding[j:j+1])
        text += tt_temp_encoding[j:j+1].decode()
        position += 1
        tt_encoding = tt_temp_encoding[j+1:]

    #2-2-3. 각 형태소의 위치 최종위치계산
    start_position = position
    end_position = start_position + len(word_surface.encode())
    position = end_position

    #단어의 형태소별로 처리
    print(word.surface,'=', word.singleLineString()) #koalanlp.data.Word
    morphemes_m = word.morphemes #koalanlp.data.Morpheme	
    for _, morp_pos in enumerate(morphemes_m):
      #2-2-4. 품사별로 생성처리
      morp = morp_pos.getSurface() + '/' + str(morp_pos.getTag()) + '/' + str(start_position)
      morp_list.append(morp)
      position_list.append( int(start_position) )
      lemma_list.append( morp_pos.getSurface() )
    
#2-2-5
text += tt_encoding.decode()

tt==text, morp_list, position_list, lemma_list

본문

  • 아래에 본문을 입력해주세요. 위와 같은 코드를 통해서 Tagger API를 통해 나온 문장과 원문의 문장을 순차적으로 byte비교하여 형태소/품사/원문에서의 byte 위치를 만드는 전처리를 하고 있습니다. 하지만 -> word_surface : 분경 -> 분 경 서울청량리경찰서는 호위 학생 5명과~ 원문은 '분 경'으로 띄어서 처리되어있는데, Tagger API를 통해 분석을 하고나면 '분경'으로 붙어서 처리되어 원문에서의 위치를 찾을 수가 없습니다. Tagger API 통해 분석된 문장이 기존의 띄어쓰기를 유지할 수 있는 option이 있었으면 좋겠습니다.

TaeHwan-Lee avatar Jul 27 '19 08:07 TaeHwan-Lee

말씀하신 문제는 인지하고 있습니다만 몇가지 구현상의 문제가 있습니다.

  • 일부 분석기(예: 한나눔)는 단어를 분해해서 다시 결합합니다. 적당한 예시는 아니지만, '적당 하지아니 한것'을 '적당하지 아니한 것'으로 변경하는데 이는 어절의 경계를 넘나들어서 형태소가 결합하게 되어('하지아니 -> '+하지, 아니+') 어절 단위가 꼬이는 문제가 발생합니다.
  • 어절 단위가 꼬이는 것을 무시하고 진행할 수는 있겠지만, 그 경우 형태소 배치가 이상한 경우가 발생합니다. 흔한 경우가 인식 오류로 인해 접두어로 분리된 문자가, 원본 문장에서 다른 어절에 붙어있었던 경우, 접두어가 다른 어절 뒤에 붙어있는 이상한 경우를 발생시킬 수 있습니다.

당분간 약 한달 정도는 제가 작업이 어려워서, 조금 시일이 걸릴 것 같은데, 임시 방편으로 원래 문장을 저장하신 다음 글자 단위로 순회하면서 index를 찾으시는 건 가능할지요? 제가 기억하고 있는 것이 맞다면, 은전한닢의 경우는 띄어쓰기 이외의 음절 구조는 대체로 유지하는 것으로 알고 있습니다.

  • (참고) 일부 분석기(예: 코모란)의 경우는 원문을 전부 분해하여 어절을 무시하는 터라, 어절 복원 기능이 있긴 합니다만 온전한 복원이 일어나지는 않습니다.

bgnkim avatar Jul 30 '19 00:07 bgnkim

무슨 말씀이신지 이해 했습니다. 원문을 순회하며 처리하는 방식으로 진행해보겠습니다. 빠쁘신일 끝나시면 적용 부탁드리겠습니다.

TaeHwan-Lee avatar Aug 11 '19 22:08 TaeHwan-Lee

@TaeHwan-Lee 예상보다 늦어져서 죄송합니다. 원문에 있는 띄어쓰기를 복원하는 방법이 여러개가 있어서, 원하시는 기능이 어떤 것인지 다시 확인해보고자 합니다. 다음 두 가지 중 어떤 구현을 생각하고 계신건지요? 예시 문장: "아버지가방에 들어가셨다"

  • 원문의 띄어쓰기와 동일하게 보존: "아버지가방에 들어가셨다"
  • 원문의 띄어쓰기는 보존하면서 필요한 경우 추가적인 띄어쓰기 가능: "아버지가 방에 들어가셨다"

bgnkim avatar Dec 04 '19 02:12 bgnkim