Skip to main content

한국어 형태소 분석

학습 목표

  • 한국어가 영어와 다른 언어적 특성(교착어, 띄어쓰기)이 NLP에 미치는 영향을 설명할 수 있습니다
  • 형태소(Morpheme)의 개념과 한국어 형태소의 종류를 구분할 수 있습니다
  • KoNLPy의 5가지 분석기(Mecab, Okt, Komoran, Hannanum, Kkma)의 특성을 비교하고 선택할 수 있습니다
  • 한국어 형태소 분석 코드를 작성하고 결과를 해석할 수 있습니다
  • 서브워드 토큰화와 형태소 분석의 관계를 이해할 수 있습니다

왜 중요한가

한국어는 **교착어(Agglutinative Language)**입니다. 어근에 조사, 어미, 접사가 붙어 다양한 형태를 만듭니다. “먹다”라는 단어 하나에서 “먹고”, “먹으며”, “먹었습니다”, “먹지 않겠습니까” 등 수백 가지 변형이 생깁니다. 영어에서 “I eat”을 단순히 공백으로 나누면 ["I", "eat"]으로 깔끔하게 토큰화됩니다. 하지만 한국어에서 “나는 밥을 먹습니다”를 공백으로 나누면 ["나는", "밥을", "먹습니다"]가 되고, “나”와 “는”, “밥”과 “을”이 분리되지 않아 의미 분석이 어렵습니다. 이 때문에 한국어 NLP에서는 형태소 분석(Morphological Analysis)이 핵심적인 전처리 단계입니다. 현대 서브워드 토크나이저(BPE, SentencePiece)가 이 문제를 어느 정도 완화하지만, 형태소 분석의 원리를 이해하는 것은 한국어 NLP의 기본입니다.

핵심 개념

한국어의 언어적 특성

교착어의 구조

한국어는 어근(Root)에 다양한 접사(Affix)가 결합하여 의미를 구성합니다.
먹 (어근) + 었 (과거 시제 선어말 어미) + 습니다 (종결 어미)
→ "먹었습니다"

학교 (체언) + 에서 (부사격 조사)
→ "학교에서"

아름답 (어근) + ㄴ (관형사형 전성 어미)
→ "아름다운"
이러한 교착어 특성 때문에 같은 의미의 단어가 문법적 맥락에 따라 수십 가지 형태로 나타납니다. 단어 단위 토큰화로는 이 변형들을 모두 다른 단어로 취급하게 됩니다.

띄어쓰기 문제

한국어 띄어쓰기는 규칙이 복잡하고, 실제 텍스트에서 오류가 매우 빈번합니다.
# 같은 의미이지만 띄어쓰기가 다른 텍스트
text_correct = "나는 학교에 간다"     # 올바른 띄어쓰기
text_wrong1  = "나는학교에간다"       # 띄어쓰기 없음
text_wrong2  = "나 는 학교에간 다"    # 잘못된 띄어쓰기

# 공백 기반 토큰화 결과가 모두 다릅니다
print(text_correct.split())  # ['나는', '학교에', '간다']
print(text_wrong1.split())   # ['나는학교에간다']
print(text_wrong2.split())   # ['나', '는', '학교에간', '다']

형태소란

형태소(Morpheme)는 의미를 가진 최소 단위입니다. 한국어 형태소는 크게 두 가지로 나뉩니다.
유형설명예시
자립 형태소단독으로 사용 가능한 형태소명사(학교, 사과), 동사 어근(먹, 가), 부사(매우)
의존 형태소단독 사용 불가, 다른 형태소에 붙어 사용조사(은, 는, 이, 가), 어미(다, 습니다), 접사(불, 적)
"아름다운 꽃이 피었습니다"
→ 아름답 / ㄴ / 꽃 / 이 / 피 / 었 / 습니다
   어근    어미 명사 조사 어근 어미  어미

KoNLPy 형태소 분석기

KoNLPy(Korean NLP in Python)는 한국어 형태소 분석을 위한 파이썬 패키지입니다. 5가지 형태소 분석기를 통합 인터페이스로 제공합니다.

분석기 비교표

분석기개발속도정확도사용자 사전특징
Mecab일본어 MeCab 기반⭐⭐⭐⭐⭐⭐⭐⭐⭐지원가장 빠름, 설치가 까다로울 수 있음
OktTwitter 한국어팀⭐⭐⭐⭐⭐⭐미지원정규화, 구어체에 강함
KomoranShineware⭐⭐⭐⭐⭐⭐⭐지원공백 오류에 강건, Java 기반
HannanumKAIST⭐⭐⭐⭐⭐지원학술적 정확도, 속도 느림
Kkma서울대 IDS⭐⭐⭐⭐⭐미지원가장 정확하지만 가장 느림

설치 및 기본 사용법

# KoNLPy 설치
# pip install konlpy

# 각 분석기 임포트
from konlpy.tag import Mecab, Okt, Komoran, Hannanum, Kkma
# 5가지 분석기로 같은 문장을 분석합니다
text = "아버지가방에들어가셨다"

# Mecab - 가장 빠른 분석기
mecab = Mecab()
print("Mecab:", mecab.morphs(text))
# ['아버지', '가', '방', '에', '들어가', '셨', '다']

print("Mecab(품사):", mecab.pos(text))
# [('아버지', 'NNG'), ('가', 'JKS'), ('방', 'NNG'), ('에', 'JKB'),
#  ('들어가', 'VV'), ('셨', 'EP'), ('다', 'EF')]
# Okt (Open Korean Text) - 정규화 기능 포함
okt = Okt()
print("Okt:", okt.morphs(text))
# ['아버지', '가방', '에', '들어가셨', '다']

# Okt의 정규화 기능
print("정규화:", okt.normalize("ㅋㅋㅋ 완전 좋아용~"))
# 'ㅋㅋ 완전 좋아용~'

# Okt의 명사 추출
print("명사:", okt.nouns("자연어 처리는 인공지능의 한 분야입니다"))
# ['자연어', '처리', '인공지능', '분야']
# Komoran - 공백 오류에 강건
komoran = Komoran()
print("Komoran:", komoran.morphs(text))
# ['아버지', '가', '방', '에', '들어가', '시', '었', '다']

# Hannanum - 학술적 분석
hannanum = Hannanum()
print("Hannanum:", hannanum.morphs(text))
# ['아버지가방에들어가', '시', '었', '다']  (공백이 없으면 어려워함)

# Kkma - 가장 상세한 분석
kkma = Kkma()
print("Kkma:", kkma.morphs(text))
# ['아버지', '가방', '에', '들어가', '시', '었', '다']

분석기 선택 가이드

# 실무에서의 분석기 선택 기준
import time

text_list = ["자연어 처리는 인공지능의 핵심 기술입니다"] * 1000

# 속도 비교
analyzers = {
    "Mecab": Mecab(),
    "Okt": Okt(),
    "Komoran": Komoran()
}

for name, analyzer in analyzers.items():
    start = time.time()
    for t in text_list:
        analyzer.morphs(t)
    elapsed = time.time() - start
    print(f"{name}: {elapsed:.3f}초 (1000문장)")

# 일반적인 결과:
# Mecab: 0.15초
# Okt: 1.20초
# Komoran: 0.80초
# 용도별 추천 조합
def choose_analyzer(use_case):
    """용도에 따른 형태소 분석기 추천"""
    recommendations = {
        "대용량_처리": "Mecab - 속도가 가장 빠릅니다",
        "소셜미디어": "Okt - 구어체/신조어 정규화에 강합니다",
        "정밀_분석": "Kkma - 품사 태깅 정확도가 가장 높습니다",
        "범용_서비스": "Komoran - 띄어쓰기 오류에 강건합니다",
        "학술_연구": "Hannanum - 언어학적 분석에 적합합니다"
    }
    return recommendations.get(use_case, "Mecab (기본 추천)")

영어 토큰화와의 비교

# 영어와 한국어의 토큰화 차이를 비교합니다
from transformers import AutoTokenizer

# 영어 문장
en_text = "I went to school yesterday"
# 한국어 문장 (같은 의미)
ko_text = "나는 어제 학교에 갔습니다"

tokenizer = AutoTokenizer.from_pretrained("bert-base-multilingual-cased")

en_tokens = tokenizer.tokenize(en_text)
ko_tokens = tokenizer.tokenize(ko_text)

print(f"영어 ({len(en_tokens)} 토큰): {en_tokens}")
# 영어 (5 토큰): ['I', 'went', 'to', 'school', 'yesterday']

print(f"한국어 ({len(ko_tokens)} 토큰): {ko_tokens}")
# 한국어 (12 토큰): ['나', '##는', '어', '##제', '학', '##교', '##에', '갔', '##습', '##니', '##다']

# 같은 의미의 문장인데 한국어가 더 많은 토큰을 사용합니다
# 이는 한국어 어휘가 충분히 학습되지 않았기 때문입니다
# 한국어 특화 모델의 토크나이저와 비교합니다
from transformers import AutoTokenizer

# 다국어 모델
multi_tok = AutoTokenizer.from_pretrained("bert-base-multilingual-cased")
# 한국어 특화 모델
ko_tok = AutoTokenizer.from_pretrained("klue/bert-base")

text = "자연어 처리 기술이 빠르게 발전하고 있습니다"

multi_tokens = multi_tok.tokenize(text)
ko_tokens = ko_tok.tokenize(text)

print(f"다국어 BERT ({len(multi_tokens)} 토큰): {multi_tokens}")
# 다국어 BERT (16 토큰): ['자', '##연', '##어', '처', '##리', ...]

print(f"KLUE BERT ({len(ko_tokens)} 토큰): {ko_tokens}")
# KLUE BERT (9 토큰): ['자연어', '처리', '기술', '##이', '빠르', '##게', ...]

# 한국어 특화 모델이 훨씬 효율적으로 토큰화합니다

형태소 분석과 서브워드 토큰화의 관계

현대 Transformer 모델은 서브워드 토크나이저를 사용하므로, 형태소 분석기를 직접 사용할 일이 줄었습니다. 하지만 형태소 분석은 여전히 유용합니다.
# 형태소 분석 + 서브워드 토큰화 결합 예시
from konlpy.tag import Mecab
from transformers import AutoTokenizer

mecab = Mecab()
tokenizer = AutoTokenizer.from_pretrained("klue/bert-base")

text = "아버지가방에들어가셨다"

# 방법 1: 서브워드 토크나이저에 직접 입력
tokens_direct = tokenizer.tokenize(text)
print(f"직접 토큰화: {tokens_direct}")
# 띄어쓰기 없는 텍스트를 잘못 분석할 수 있습니다

# 방법 2: 형태소 분석 후 서브워드 토큰화
morphs = mecab.morphs(text)               # 형태소 분석
morphs_text = " ".join(morphs)             # 형태소를 공백으로 결합
tokens_morph = tokenizer.tokenize(morphs_text)
print(f"형태소 후 토큰화: {tokens_morph}")
# 형태소 분석이 선행되어 더 정확한 토큰화가 가능합니다
접근법장점단점사용 시점
서브워드만간단, End-to-End띄어쓰기 오류에 약함잘 정제된 데이터
형태소 + 서브워드정확한 분석파이프라인 복잡비정형 데이터, 소셜 미디어
형태소만언어학적 분석어휘 크기 큼전통적 ML, 특수 목적

AI/ML에서의 활용

  • 검색 시스템: 형태소 분석을 통해 “먹었습니다”로 검색해도 “먹다” 관련 문서를 찾을 수 있습니다
  • 감성 분석: 조사와 어미를 분리하면 핵심 의미 단어에 집중할 수 있습니다
  • 키워드 추출: 명사만 추출하여 문서의 핵심 주제를 파악합니다
  • 데이터 증강: 형태소 단위로 분리한 후 동의어 치환 등의 증강이 가능합니다
  • RAG 전처리: 한국어 문서의 청크 분할 시 형태소 경계를 고려하면 품질이 향상됩니다
Mecab은 C++ 기반이라 설치가 까다로울 수 있습니다. 대안으로 Okt나 Komoran을 사용할 수 있습니다. 둘 다 Java 기반이므로 JDK가 필요하지만, pip만으로 설치가 가능합니다. 최근에는 python-mecab-ko 패키지가 설치를 크게 간소화했습니다.
필수는 아닙니다. 한국어에 특화된 서브워드 토크나이저(예: KLUE BERT의 토크나이저)는 형태소 분석 없이도 합리적인 토큰화를 수행합니다. 하지만 띄어쓰기가 부정확한 텍스트(소셜 미디어, OCR 결과 등)에서는 형태소 분석 전처리가 여전히 도움이 됩니다.
KoNLPy에서 사용하는 주요 품사 태그입니다. NNG(일반 명사), NNP(고유 명사), VV(동사), VA(형용사), JKS(주격 조사), JKO(목적격 조사), EF(종결 어미), EP(선어말 어미). 세종 품사 태그 체계를 기반으로 하며, 분석기마다 약간의 차이가 있습니다.

체크리스트

  • 교착어의 특성이 토큰화에 미치는 영향을 설명할 수 있다
  • 형태소의 정의와 자립/의존 형태소의 차이를 이해한다
  • KoNLPy의 5가지 분석기 특성을 비교하고 용도에 맞게 선택할 수 있다
  • morphs(), pos(), nouns() 메서드를 활용할 수 있다
  • 영어와 한국어의 토큰화 차이를 설명할 수 있다
  • 형태소 분석과 서브워드 토큰화의 관계를 이해한다

다음 문서