python-support
python-support copied to clipboard
Tagger API를 통해서 문장을 분석하면 원문의 띄어쓰기가 무조건 변경되어 분석의 어려움이 있습니다.
기초정보
- 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이 있었으면 좋겠습니다.
말씀하신 문제는 인지하고 있습니다만 몇가지 구현상의 문제가 있습니다.
- 일부 분석기(예: 한나눔)는 단어를 분해해서 다시 결합합니다. 적당한 예시는 아니지만, '적당 하지아니 한것'을 '적당하지 아니한 것'으로 변경하는데 이는 어절의 경계를 넘나들어서 형태소가 결합하게 되어('하지아니 -> '+하지, 아니+') 어절 단위가 꼬이는 문제가 발생합니다.
- 어절 단위가 꼬이는 것을 무시하고 진행할 수는 있겠지만, 그 경우 형태소 배치가 이상한 경우가 발생합니다. 흔한 경우가 인식 오류로 인해 접두어로 분리된 문자가, 원본 문장에서 다른 어절에 붙어있었던 경우, 접두어가 다른 어절 뒤에 붙어있는 이상한 경우를 발생시킬 수 있습니다.
당분간 약 한달 정도는 제가 작업이 어려워서, 조금 시일이 걸릴 것 같은데, 임시 방편으로 원래 문장을 저장하신 다음 글자 단위로 순회하면서 index를 찾으시는 건 가능할지요? 제가 기억하고 있는 것이 맞다면, 은전한닢의 경우는 띄어쓰기 이외의 음절 구조는 대체로 유지하는 것으로 알고 있습니다.
- (참고) 일부 분석기(예: 코모란)의 경우는 원문을 전부 분해하여 어절을 무시하는 터라, 어절 복원 기능이 있긴 합니다만 온전한 복원이 일어나지는 않습니다.
무슨 말씀이신지 이해 했습니다. 원문을 순회하며 처리하는 방식으로 진행해보겠습니다. 빠쁘신일 끝나시면 적용 부탁드리겠습니다.
@TaeHwan-Lee 예상보다 늦어져서 죄송합니다. 원문에 있는 띄어쓰기를 복원하는 방법이 여러개가 있어서, 원하시는 기능이 어떤 것인지 다시 확인해보고자 합니다. 다음 두 가지 중 어떤 구현을 생각하고 계신건지요? 예시 문장: "아버지가방에 들어가셨다"
- 원문의 띄어쓰기와 동일하게 보존: "아버지가방에 들어가셨다"
- 원문의 띄어쓰기는 보존하면서 필요한 경우 추가적인 띄어쓰기 가능: "아버지가 방에 들어가셨다"