1월 말에 새로운 팀으로 이동해서 적응한지 6개월이 지났다. 하반기 새로운 서비스를 준비하면서 필요에 의해 텍스트 분석의 전처리 과정에 대해 깊이 파고드는 중이다. 기존에 운영 중인 서비스의 텍스트 데이터 수집 - 전처리 - 분석 - 집계 - 대시보드 시각화하는 파이프라인을 그대로 따른다고 생각하면 그리 큰 일은 아니다. 하지만 실무자의 관점에서 자세히 들여다보니 고려할 부분들이 많다는 생각이 슬슬 들고 있다.
텍스트 전처리에 대해 많은 블로그 글들이 다루고 있지만, 개인적인 필요에 의해 전체적인 큰그림을 정리해보고자 한다. 진행 중인 프로젝트는 아직 기획 단계에 있으므로, 이 글은 전체 프로세스를 경험하기 전 단계의 부족함이 반영되어 있음을 감안해주시기 바란다.

1. 전처리 - 클린징

수집된 데이터 중 불필요한 내용을 제거하는 과정이다. 기사의 경우 대표적인 예로 아래와 같은 내용이 포함되어 있을 수 있다.

- 이메일 패턴
- 전화번호 패턴
- 기사 앞머리에 오는 매체명/기자명
  - [데일리한국 OOO 기자] 카카오가 현재 유료로 운영되고 있는 ‘챗봇’ 서비스의 이용 요금을...
- 기사 뒷머리에 붙는 내용
  - ... 상생 방안을 모색할 계획이다”고 전했다. 저작권자 © 데이터넷 무단전재 및 재배포 금지


2. 형태소분석

전에 다른 글에서도 언급했듯 텍스트 데이터는 다른 정량적인 데이터와 달리 평균, 표준편차 등의 숫자로 깔끔하게 집계되지 않는다. 따라서 전체 내용을 효율적으로 파악하기 위해 많이 출현한 단어들의 랭킹 테이블을 1차적으로 확인할 수 있다. 이를 위해 형태소분석기를 이용해 단어를 의미 단위로 짤라서 추출하게 된다.

이 키워드 랭킹 테이블을 만들려면 문서/문장 내의 단어들이 잘 뽑혀나와야 한다. 예를 들어 아래 기사 제목들은 명사만 추출해서 다음과 같은 키워드 테이블로 집계할 수 있다.

- 카카오, '챗봇' 서비스 무료 전환...'소상공인' 지원 강화  
- 카카오, 소상공인 돕는 카카오톡 채널 챗봇 서비스 무료 전환
- 9월부터 카카오톡 채널 '챗봇' 일반상품 이용 요금 무료 
- 카카오, 내달부터 카톡 채널 '챗봇' 일반 상품 무료 제공 
from konlpy.tag import Okt
from collections import Counter
okt = Okt()

noun = okt.nouns(text)
count = Counter(noun)

noun_list = count.most_common(30)
for n in noun_list:
    print(n)
[결과]
('카카오', 5)
('챗봇', 4)
('무료', 4)
('채널', 3)
('서비스', 2)
('전환', 2)
('소상', 2)
('공인', 2)
('톡', 2)
('일반', 2)
('상품', 2)
('지원', 1)
('강화', 1)
('이용', 1)
('요금', 1)
('내달', 1)
('카톡', 1)
('제공', 1)


그런데 언어는 계속 진화하기 때문에 그 어떤 형태소분석기도 완벽하게 우리 입맛에 맞게 단어를 짤라주지는 못한다. 심지어 뉴스 기사처럼 굉장히 정형화되고, 기자가 맞춤법에 꼭 맞는 언어를 구사하는 경우에도 그렇다.

위의 단어들을 살펴보면 2가지 문제가 있다.

2-1. 잘못 짤리는 복합명사 / 고유명사

먼저 기사는 4개인데 ‘카카오’는 5번 출현하고 있다. 바로 ‘카카오톡’이 하나의 명사로 인식되지 않고 ‘카카오’와 ‘톡’으로 짤렸기 때문이다. 마찬가지로 ‘소상공인’도 ‘소상’과 ‘공인’으로 짤린 것을 볼 수 있다.

이렇게 형태소가 잘못 분석되는 문제 때문에 사용자 사전을 만들고 관리하게 된다. ‘카카오톡’을 사전에 등록해 놓고 형태소 분석 과정을 거치더라도 원형을 보존해 ‘카카오톡’으로 최종 표시되게끔 하는 것이다.

문제는 배치(batch)성으로 한번만 데이터를 전처리하고 분석하고 끝내는 경우가 아니라, 파이프라인을 따라 지속적으로 데이터가 수집되고 처리/분석되어 사용자에게 제공되는 경우다. 문제를 발견하여 사용자 사전에 ‘카카오톡’을 등록하면 이후로 들어오는 데이터는 올바르게 처리되지만, 이전에 수집된 데이터는 이미 ‘카카오’와 ‘톡’으로 처리하여 저장된 상태다. 따라서 키워드 랭킹 테이블에는 여전히 ‘톡’이 노출되는 문제가 남아있게 된다.

물론 일정 주기로 기존 데이터에 대한 재처리를 해주는 방법이 있으나, 데이터량이 방대해지면 이것도 쉬운 일은 아닐 것이다. 그래서 가급적이면, 서비스 도메인에 관련된 중요한 단어들은 초반에 파악해서 사전을 만들어두는 게 서비스 품질을 위해 필요한 부분인 것 같다.

2-2. 동의어

위의 키워드 목록에서 형태소가 잘못 짤리는 것 외에 또 하나의 문제가 있다. 바로 동의어가 따로 집계되는 문제다. ‘카카오톡’을 사용자 사전에 등록해 정확히 표기하게 되었더라도, 1회 출현한 ‘카톡’과는 따로 집계되고 있는 것이다.

이런 경우, 실제로는 상위에 랭킹되어야 하는 키워드가 2~3개로 쪼개져 랭킹 아래쪽에 위치하는 문제가 생기게 된다.

동의어는 수집된 문서를 검색할 때도 문제가 된다. 사용자가 ‘카카오톡’으로 검색했을 때, ‘카카오톡’이 아닌 ‘카톡’만으로 표현하고 있는 문서는 검색이 되질 않는 것이다.

따라서 서비스 흐름의 어느 시점에 어떤 방법을 써서든 동의어는 치환 처리가 되어야 한다. 가장 간단한 방법은 본문을 복제하면서 ‘카톡’을 ‘카카오톡’으로 치환하는 방법도 있겠지만, 텍스트라는 특성상 맥락을 파악하기 위해 원문의 보존은 필요하고 어떤 컬럼을 어떻게 활용할지 복합적으로 고려가 되어야 할 것이다. 이 부분은 나도 아직 실무를 통해 배워나가는 중이므로 자세한 내용은 나중에 정리할 기회가 있을 것 같다.

3. 후처리 - 불용어

위의 테이블은 명사만 뽑았기 때문에 깔끔한 편이지만, 모든 품사를 포함해 키워드 테이블을 뽑아보면 정제가 필요한 경우가 있다.

아래는 기사 본문으로부터 명사를 뽑아본 것이다.

  • 기사 : <카카오, 유료운영 챗봇 서비스 무료 전환>, 디지털타임스 ``` (‘챗봇’, 10) (‘카카오’, 9) (‘서비스’, 9) (‘상품’, 6) (‘톡’, 5) (‘채널’, 5) (‘비즈니스’, 4) (‘활용’, 4) (‘일반’, 4) (‘이용’, 4) (‘무료’, 3) (‘제공’, 3) (‘답변’, 3) (‘파트너’, 3) (‘수’, 3) (‘현재’, 2) (‘운영’, 2) (‘등’, 2) (‘대화’, 2) (‘인터페이스’, 2) (‘이용자’, 2) (‘개설’, 2) (‘초과’, 2) (‘건’, 2) (‘부과’, 2) (‘사업자’, 2) …

``` 한 글자짜리 ‘수’, ‘등’, ‘건’과 같은 의존명사들이 눈에 띈다. 이러한 의존명사는 어떤 문서에서나 보편적으로 등장하며, 구체적인 의미를 전달하지 않으므로 내용 파악에 도움이 되지 않는다. 따라서 통상적으로는 2글자 이상의 키워드만 사용하는 경우가 많은 것 같다. 물론 도메인에 따라 다를 수 있으니 사전에 1글자 단어들에 대한 검토가 한번 이뤄져야 하겠지만 말이다.

그 외에, 너무 보편적인 의미를 담고 있어 분석에 도움이 되지 않는다면 불용어 사전 (stop-word dictionary)을 만들어 등록해두게 된다. 위 내용에서 ‘현재’, ‘이용자’ 등이 해당될 수 있겠다. 물론 이 부분은 상당 부분 주관이 개입하는 부분이고 도메인에 따라서, 담당자의 관점에 따라서도 달라질 수 있으니 여러 명의 상호 체크가 필요하다고 생각된다.

마무리하며

텍스트 분석의 전처리/후처리 관련하여 더 많은 내용이 있을텐데 급하게 글을 작성하느라 디테일한 부분들을 다 아우르지는 못한 것 같다. 하지만 큰그림을 그리고자 했던 목표에 맞게 꼭 필요한 부분들은 정리를 해 보았다. 실제 서비스 운영에서는 품질을 무한히 올릴 수 있는게 아니라 운영 효율과 비용도 고려해야 하므로 더 디테일한 부분들이 고민되어야 할 것이다. 9월부터는 본격적으로 전처리나 사전 구축을 시작하게 될 것 같은데, 세부적인 부분들에서 많이 배울 수 있기를 기대한다.