본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 17. · 5 Views
텍스트 데이터 전처리 완벽 가이드
자연어 처리의 첫 단추, 텍스트 전처리를 실무 중심으로 배웁니다. 토큰화부터 정규화까지, 초급 개발자가 반드시 알아야 할 핵심 개념을 이북처럼 술술 읽히는 스타일로 정리했습니다.
목차
1. 텍스트 전처리의 중요성
어느 날 김개발 씨가 챗봇 프로젝트를 맡게 되었습니다. 사용자 입력을 받아 답변을 생성하는 간단한 기능이었는데, 막상 테스트해보니 "안녕하세요"와 "안녕하세요!"를 다른 단어로 인식하는 문제가 생겼습니다.
선배 박시니어 씨가 말했습니다. "텍스트 전처리부터 제대로 해야 해요."
텍스트 전처리는 자연어 처리의 첫 단계로, 원시 텍스트 데이터를 컴퓨터가 이해하기 쉬운 형태로 변환하는 과정입니다. 마치 요리하기 전에 재료를 손질하는 것처럼, 데이터 분석 전에 텍스트를 깨끗하게 정리합니다.
전처리 품질이 최종 모델의 성능을 좌우합니다.
다음 코드를 살펴봅시다.
# 전처리 전후 비교
raw_text = "안녕하세요!!! 저는 김개발입니다. "
# 전처리: 소문자 변환, 공백 정리, 특수문자 제거
import re
preprocessed = raw_text.strip() # 양쪽 공백 제거
preprocessed = re.sub(r'\s+', ' ', preprocessed) # 연속 공백을 하나로
preprocessed = re.sub(r'[!?.,]+', '', preprocessed) # 특수문자 제거
print(f"원본: '{raw_text}'")
print(f"전처리 후: '{preprocessed}'")
# 결과: '안녕하세요 저는 김개발입니다'
김개발 씨는 입사 2개월 차 주니어 개발자입니다. 오늘 팀장님께 새로운 미션을 받았습니다.
고객 리뷰 데이터를 분석해서 긍정/부정을 분류하는 시스템을 만드는 것이었습니다. 의욕적으로 데이터를 받아 바로 분석을 시작했지만, 결과가 이상했습니다.
"좋아요"와 "좋아요!!!"가 서로 다른 단어로 취급되고, "최고예요 "처럼 뒤에 공백이 있는 텍스트는 제대로 처리되지 않았습니다. 선배 박시니어 씨가 화면을 보더니 웃으며 말했습니다.
"신입 때 다들 한 번씩 겪는 일이에요. 텍스트 전처리를 건너뛴 거죠." 텍스트 전처리란 무엇일까요? 쉽게 비유하자면, 전처리는 마치 요리사가 재료를 손질하는 것과 같습니다.
당근을 볶기 전에 껍질을 벗기고 씻듯이, 텍스트 데이터도 분석하기 전에 불필요한 부분을 제거하고 정리해야 합니다. 아무리 좋은 요리 실력이 있어도 재료가 엉망이면 맛있는 음식을 만들 수 없는 것처럼, 전처리 없이는 정확한 분석이 불가능합니다.
전처리가 없던 시절의 문제점 초창기 자연어 처리 시스템들은 이런 문제로 고생했습니다. "사과"와 "사과."를 다른 단어로 인식했고, 대소문자 때문에 "Apple"과 "apple"이 별개로 취급되었습니다.
더 큰 문제는 데이터의 일관성이었습니다. 같은 의미인데도 표기만 다르면 다른 것으로 처리되어, 모델이 패턴을 학습하기 어려웠습니다.
프로젝트가 커질수록 이런 노이즈는 눈덩이처럼 불어났고, 정확도는 떨어졌습니다. 전처리의 등장과 효과 바로 이런 문제를 해결하기 위해 체계적인 전처리 과정이 정립되었습니다.
전처리를 수행하면 데이터의 일관성이 확보됩니다. "안녕!"과 "안녕"이 같은 의미로 처리되어 모델이 패턴을 더 잘 학습합니다.
또한 노이즈 제거로 불필요한 정보가 사라져 계산 효율이 높아집니다. 무엇보다 모델 성능 향상이라는 큰 이점이 있습니다.
코드로 이해하는 전처리 위의 코드를 한 줄씩 살펴보겠습니다. 먼저 strip() 메서드로 문자열 양쪽의 공백을 제거합니다.
이것만으로도 많은 문제가 해결됩니다. 다음으로 정규표현식 \s+로 연속된 공백을 하나로 통일합니다.
마지막으로 특수문자를 제거해 순수한 텍스트만 남깁니다. 실무에서의 활용 실제 현업에서는 어떻게 활용할까요?
예를 들어 쇼핑몰의 상품 리뷰 분석 시스템을 개발한다고 가정해봅시다. 사용자들은 "너무좋아요!!!", "완전 만족ㅎㅎ", "최고 입니다 " 같은 다양한 표현을 사용합니다.
전처리를 통해 이런 표현들을 정규화하면 감성 분석의 정확도가 크게 향상됩니다. 네이버, 쿠팡 같은 대형 플랫폼에서도 이런 전처리 파이프라인을 필수로 사용합니다.
주의할 점 초보 개발자들이 흔히 하는 실수는 과도한 전처리입니다. 예를 들어 감성 분석에서 느낌표를 모두 제거하면 "좋아요!!!"의 강조 의미가 사라집니다.
상황에 맞는 적절한 전처리가 중요합니다. 정리하며 다시 김개발 씨의 이야기로 돌아가 봅시다.
박시니어 씨의 조언을 듣고 전처리 파이프라인을 구축한 김개발 씨는 리뷰 분석 정확도를 20%나 향상시켰습니다. "전처리가 이렇게 중요했군요!" 텍스트 전처리는 화려하지 않지만 가장 중요한 기초입니다.
여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - 전처리 전후 데이터를 항상 출력해서 확인하세요
- 도메인 특성에 맞게 전처리 규칙을 조정하세요
- 전처리 함수를 재사용 가능하게 모듈화하세요
2. 토큰화
전처리의 기본을 익힌 김개발 씨는 다음 단계로 넘어갔습니다. 문장을 단어로 나누는 작업이 필요했는데, 단순히 공백으로 나누니 "don't"가 "don"과 "t"로 잘못 분리되었습니다.
박시니어 씨가 말했습니다. "토큰화 라이브러리를 쓰세요."
토큰화는 텍스트를 의미 있는 최소 단위인 토큰으로 분리하는 과정입니다. 마치 문장을 레고 블록으로 분해하는 것처럼, 텍스트를 단어나 형태소 단위로 쪼갭니다.
자연어 처리의 가장 기본적이면서도 중요한 작업입니다.
다음 코드를 살펴봅시다.
# NLTK를 사용한 토큰화
from nltk.tokenize import word_tokenize, sent_tokenize
text = "Hello! My name is Kim. I'm a developer."
# 문장 토큰화
sentences = sent_tokenize(text)
print("문장 토큰화:", sentences)
# ['Hello!', "My name is Kim.", "I'm a developer."]
# 단어 토큰화
words = word_tokenize(text)
print("단어 토큰화:", words)
# ['Hello', '!', 'My', 'name', 'is', 'Kim', '.', "I'm", 'a', 'developer', '.']
김개발 씨는 영어 뉴스 기사를 분석하는 프로젝트를 시작했습니다. 첫 번째 해야 할 일은 기사 본문을 단어 단위로 나누는 것이었습니다.
처음에는 간단하게 생각했습니다. "그냥 split() 쓰면 되겠지?" 하지만 결과를 보고 당황했습니다.
"don't"가 하나의 단어인데 "don"과 "t"로 쪼개졌고, 문장 끝의 마침표가 단어에 붙어있었습니다. 박시니어 씨가 코드를 보더니 고개를 저었습니다.
"공백으로만 나누면 안 돼요. 제대로 된 토큰화 도구를 써야 합니다." 토큰화란 정확히 무엇일까요? 토큰화를 쉽게 비유하자면, 레고 작품을 블록으로 분해하는 것과 같습니다.
완성된 레고 성을 만들 때 사용한 블록들을 하나씩 떼어내듯이, 문장을 의미 있는 최소 단위로 분리합니다. 이때 중요한 건 블록을 의미 있게 나누는 것입니다.
레고 블록을 아무렇게나 부러뜨리면 안 되듯, 단어도 문법적 의미를 고려해서 나눠야 합니다. 단순 분리의 한계 split() 메서드만 사용하던 시절의 문제점은 명확했습니다.
축약형 처리가 불가능했습니다. "I'm", "don't", "won't" 같은 표현을 제대로 처리할 수 없었습니다.
또한 구두점 처리도 엉망이었습니다. "Hello!"에서 느낌표가 단어에 붙어 "Hello!"라는 잘못된 토큰이 생성되었습니다.
더 심각한 문제는 언어별 특성을 고려하지 못한다는 점이었습니다. 한국어처럼 띄어쓰기가 명확하지 않은 언어는 아예 처리가 불가능했습니다.
토큰화 라이브러리의 등장 이런 문제를 해결하기 위해 NLTK, spaCy 같은 전문 라이브러리가 개발되었습니다. 이 라이브러리들은 언어학적 규칙을 내장하고 있어 축약형, 구두점, 특수 케이스를 모두 올바르게 처리합니다.
또한 문장 토큰화와 단어 토큰화를 분리해서 제공해 다양한 요구사항에 대응할 수 있습니다. 코드 상세 분석 위의 코드에서 sent_tokenize()는 텍스트를 문장 단위로 나눕니다.
마침표, 느낌표, 물음표를 기준으로 하되, "Mr."처럼 약어는 문장 끝이 아닌 것으로 인식합니다. word_tokenize()는 더욱 정교합니다.
"I'm"을 "I'm" 그대로 유지하고, 구두점은 별도 토큰으로 분리합니다. 이렇게 하면 단어의 의미를 보존하면서도 구두점 정보를 잃지 않습니다.
실무 적용 사례 검색 엔진을 개발한다고 가정해봅시다. 사용자가 "don't worry"를 검색하면, 시스템은 이를 올바르게 토큰화해서 "don't"와 "worry"로 인식해야 합니다.
만약 "don"과 "t"로 잘못 나눈다면 검색 결과가 엉망이 됩니다. 카카오, 네이버 같은 포털에서는 수억 건의 문서를 토큰화해서 색인을 구축합니다.
정확한 토큰화가 검색 품질을 좌우합니다. 한국어 토큰화의 특수성 한국어는 영어와 달리 형태소 단위 토큰화가 필요합니다.
"먹었습니다"를 "먹", "었", "습니다"로 분리해야 의미 분석이 가능합니다. 이를 위해 KoNLPy 같은 한국어 전용 라이브러리를 사용합니다.
주의사항 토큰화할 때 주의할 점은 도메인 특성을 고려해야 한다는 것입니다. 의료 문서에서 "COVID-19"는 하나의 토큰으로 유지해야 하지만, 일반 토큰화는 이를 여러 조각으로 나눌 수 있습니다.
필요시 커스텀 토크나이저를 구현하세요. 정리 김개발 씨는 NLTK의 토큰화 기능을 적용한 후 훨씬 정확한 결과를 얻었습니다.
"토큰화 하나만 제대로 해도 이렇게 달라지네요!" 토큰화는 모든 자연어 처리의 출발점입니다. 제대로 배워두면 다음 단계가 훨씬 수월합니다.
실전 팁
💡 - 영어는 NLTK/spaCy, 한국어는 KoNLPy를 사용하세요
- 도메인 특화 용어는 커스텀 사전에 추가하세요
- 토큰화 결과를 항상 샘플링해서 검증하세요
3. 불용어 제거
토큰화까지 완료한 김개발 씨는 단어 빈도를 분석했습니다. 그런데 "the", "is", "a" 같은 단어가 상위권을 차지했습니다.
정작 중요한 내용은 파악하기 어려웠습니다. 박시니어 씨가 조언했습니다.
"불용어를 제거해야 의미 있는 단어만 남아요."
불용어는 분석에 큰 의미가 없는 흔한 단어들을 말합니다. 영어의 "the", "is", "a"나 한국어의 "그리고", "하지만" 같은 조사와 접속사가 대표적입니다.
이런 단어들을 제거하면 핵심 내용에 집중할 수 있습니다.
다음 코드를 살펴봅시다.
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
# NLTK 불용어 다운로드 (최초 1회)
# import nltk
# nltk.download('stopwords')
text = "This is a sample sentence showing off the stop words filtration."
tokens = word_tokenize(text.lower())
# 영어 불용어 로드
stop_words = set(stopwords.words('english'))
# 불용어 제거
filtered_tokens = [word for word in tokens if word not in stop_words]
print("원본:", tokens)
print("불용어 제거 후:", filtered_tokens)
# ['sample', 'sentence', 'showing', 'stop', 'words', 'filtration', '.']
김개발 씨는 고객 리뷰 데이터에서 자주 등장하는 키워드를 추출하는 작업을 맡았습니다. 열심히 토큰화하고 빈도를 세었는데, 결과가 이상했습니다.
상위 10개 단어가 "the", "is", "and", "a", "to", "of", "in", "it", "for", "that"이었습니다. 정작 "quality", "delivery", "price" 같은 의미 있는 단어는 한참 아래에 있었습니다.
"이게 뭐지?" 김개발 씨는 혼란스러웠습니다. 박시니어 씨가 화면을 보더니 웃었습니다.
"불용어를 제거하지 않았네요. 당연히 그럴 수밖에 없어요." 불용어란 무엇일까요? 불용어를 쉽게 비유하자면, 책에서 하이라이트를 칠 때 제외하는 단어들입니다.
"그리고", "하지만", "그런데" 같은 접속사는 문장을 연결하지만 핵심 내용은 아닙니다. 마치 요리할 때 야채를 씻으면서 상한 부분을 도려내듯, 텍스트에서도 분석에 방해가 되는 단어를 걸러냅니다.
불용어 제거가 없던 시절 초기 자연어 처리 시스템들은 모든 단어를 동등하게 취급했습니다. 결과적으로 계산 낭비가 심각했습니다.
"the"를 수백만 번 처리하느라 컴퓨팅 리소스가 소모되었습니다. 더 큰 문제는 의미 왜곡이었습니다.
중요한 단어보다 흔한 단어의 빈도가 높아 제대로 된 분석이 불가능했습니다. 불용어 사전의 등장 이 문제를 해결하기 위해 언어학자들이 불용어 사전을 만들었습니다.
NLTK는 영어 불용어 179개를 기본 제공합니다. "a", "an", "the", "is", "are" 같은 관사와 be동사부터 "myself", "yourself" 같은 재귀대명사까지 포함됩니다.
이 사전을 사용하면 한 줄의 코드로 불용어를 모두 제거할 수 있습니다. 코드 동작 원리 위 코드를 단계별로 살펴보겠습니다.
먼저 stopwords.words('english')로 영어 불용어 목록을 가져옵니다. 이를 set으로 변환하는 이유는 검색 속도 때문입니다.
리스트에서 검색하면 O(n)이지만 집합은 O(1)입니다. 다음으로 리스트 컴프리헨션으로 각 토큰을 검사합니다.
word not in stop_words 조건을 만족하는 단어만 남기면 불용어가 자동으로 제거됩니다. 실무 적용 사례 뉴스 기사 요약 시스템을 개발한다고 가정해봅시다.
기사에서 핵심 단어를 추출해 요약문을 생성하는데, 불용어를 제거하지 않으면 "기자가", "이라고", "했다" 같은 단어가 중요하게 취급됩니다. 불용어를 제거하면 "대통령", "정책", "발표" 같은 핵심 명사가 부각되어 훨씬 정확한 요약이 가능합니다.
실제로 구글 뉴스, 네이버 뉴스 요약 시스템도 불용어 제거를 필수로 사용합니다. 한국어 불용어 처리 한국어는 조사가 발달해서 불용어가 더 복잡합니다.
"은", "는", "이", "가", "을", "를", "의", "에", "에서" 같은 조사는 모두 불용어입니다. KoNLPy와 함께 사용할 수 있는 한국어 불용어 사전도 있지만, 도메인에 따라 커스텀 불용어 사전을 만드는 것이 좋습니다.
쇼핑몰 리뷰라면 "것", "거", "이거" 같은 단어도 불용어로 추가할 수 있습니다. 주의사항 불용어 제거 시 주의할 점은 맥락 고려입니다.
예를 들어 감성 분석에서 "not"을 제거하면 "not good"이 "good"이 되어 의미가 반대로 바뀝니다. 작업 목적에 따라 불용어 사전을 조정해야 합니다.
정리 김개발 씨는 불용어를 제거한 후 리뷰에서 "quality", "fast", "satisfied" 같은 의미 있는 단어를 추출할 수 있었습니다. "이제야 제대로 된 분석이네요!" 불용어 제거는 간단하지만 효과가 큽니다.
데이터 크기도 줄고 분석 속도도 빨라집니다.
실전 팁
💡 - 불용어 사전을 맹신하지 말고 도메인에 맞게 조정하세요
- 감성 분석에서는 부정어("not", "no")를 불용어에서 제외하세요
- 한국어는 형태소 분석 후 조사만 제거하는 방식도 유용합니다
4. 어간 추출
키워드 추출까지 성공한 김개발 씨는 새로운 문제에 직면했습니다. "running", "runs", "ran"이 모두 다른 단어로 취급되어 빈도 분석이 부정확했습니다.
박시니어 씨가 말했습니다. "어간 추출로 단어를 원형으로 통일하세요."
어간 추출은 단어의 어미를 제거해서 어간만 남기는 과정입니다. "running"에서 "ning"을 제거해 "run"을 얻는 식입니다.
마치 나무에서 가지를 쳐내고 몸통만 남기는 것처럼, 단어의 핵심 부분만 추출합니다.
다음 코드를 살펴봅시다.
from nltk.stem import PorterStemmer
# Porter Stemmer 객체 생성
stemmer = PorterStemmer()
# 다양한 형태의 단어들
words = ["running", "runs", "ran", "runner", "easily", "fairly"]
# 어간 추출
stemmed_words = [stemmer.stem(word) for word in words]
print("원본:", words)
print("어간 추출:", stemmed_words)
# ['run', 'run', 'ran', 'runner', 'easili', 'fairli']
# 주의: 완벽하지 않음 (easily -> easili)
김개발 씨는 영어 뉴스 기사에서 "run"과 관련된 내용이 얼마나 언급되는지 분석하고 있었습니다. 단어 빈도를 세어보니 이상한 결과가 나왔습니다.
"run"이 5번, "running"이 8번, "runs"가 3번, "ran"이 4번으로 모두 따로 집계되었습니다. 실제로는 총 20번이나 언급된 셈인데, 가장 많은 "running"도 8번에 불과했습니다.
"이걸 어떻게 합쳐야 하지?" 박시니어 씨가 설명했습니다. "어간 추출을 쓰면 이런 변형들을 모두 하나로 통일할 수 있어요." 어간 추출이란? 어간 추출을 쉽게 비유하자면, 사람의 얼굴에서 화장을 지우는 것과 같습니다.
립스틱, 아이섀도우, 블러셔를 지우면 본래 얼굴이 드러나듯, 단어에서 어미를 제거하면 핵심 의미를 담은 어간이 남습니다. "running", "runs", "ran"은 모두 다르게 보이지만 핵심은 "run"입니다.
변형 단어의 문제 어간 추출이 없던 시절의 어려움은 명확했습니다. 영어는 시제, 인칭, 수에 따라 단어가 변합니다.
"go"는 "goes", "going", "went", "gone"으로 변형됩니다. 이들을 모두 다른 단어로 취급하면 의미 중복이 발생합니다.
같은 개념인데 여러 번 나뉘어 집계되어 분석이 부정확해집니다. 또한 사전 크기도 불필요하게 커집니다.
"run"의 변형만 수십 개를 저장하느라 메모리가 낭비됩니다. Stemmer의 등장 이 문제를 해결하기 위해 Porter Stemmer 같은 알고리즘이 개발되었습니다.
1980년 Martin Porter가 만든 이 알고리즘은 규칙 기반으로 동작합니다. "ing" 제거, "ed" 제거, "s" 제거 같은 규칙을 순차적으로 적용해 어간을 추출합니다.
빠르고 간단하지만, 때로는 부정확할 수 있습니다. 코드 분석 위 코드에서 PorterStemmer()는 NLTK에서 제공하는 가장 널리 사용되는 스테머입니다.
stem() 메서드에 단어를 넣으면 규칙을 적용해 어간을 반환합니다. "running"은 "run"으로, "runs"도 "run"으로 통일됩니다.
하지만 "ran"은 불규칙 변화라서 "ran" 그대로 남습니다. 흥미로운 점은 "easily"가 "easili"로 변하는 것입니다.
문법적으로는 틀렸지만, 같은 어간을 가진 단어들을 통일한다는 목적은 달성합니다. 실무 활용 검색 엔진에서 어간 추출은 필수입니다.
사용자가 "running shoes"를 검색하면, "run shoes", "runner shoes", "runs shoes" 같은 문서도 함께 보여줘야 합니다. 어간 추출로 검색어를 정규화하면 재현율이 크게 향상됩니다.
구글 검색도 내부적으로 이런 기법을 사용해 관련 문서를 폭넓게 찾아줍니다. 한계점 인식 어간 추출의 한계도 알아야 합니다.
규칙 기반이라 불규칙 변화를 처리하지 못합니다. "go"와 "went"는 전혀 다른 어간으로 처리됩니다.
또한 의미 변화도 고려하지 못합니다. "universe"와 "university"는 어간이 비슷해 같은 것으로 처리될 수 있지만 의미는 완전히 다릅니다.
다른 Stemmer들 Porter Stemmer 외에도 Lancaster Stemmer, Snowball Stemmer 등이 있습니다. Lancaster는 더 공격적으로 자르고, Snowball은 여러 언어를 지원합니다.
상황에 맞게 선택하세요. 정리 김개발 씨는 어간 추출을 적용해서 "run" 관련 단어를 모두 통일했습니다.
빈도 분석이 훨씬 정확해졌습니다. "이제 제대로 된 통계네요!" 어간 추출은 빠르고 간단하지만 완벽하지 않습니다.
다음에 배울 표제어 추출과 비교해서 적절한 것을 선택하세요.
실전 팁
💡 - 속도가 중요하면 Stemmer, 정확도가 중요하면 Lemmatizer를 사용하세요
- Porter Stemmer가 가장 널리 사용되지만 상황에 따라 다른 것도 시도하세요
- 결과를 항상 확인하고 도메인 특화 규칙을 추가하세요
5. 표제어 추출
어간 추출을 적용한 김개발 씨는 결과를 확인하다가 이상한 점을 발견했습니다. "better"가 "better"로 남아있고, "are"가 "are"로 유지되었습니다.
박시니어 씨가 설명했습니다. "어간 추출은 한계가 있어요.
표제어 추출을 쓰면 더 정확합니다."
표제어 추출은 단어를 사전에 등재된 기본형으로 변환하는 과정입니다. "better"를 "good"으로, "are"를 "be"로 바꿉니다.
어간 추출과 달리 문법과 의미를 고려한 언어학적 변환입니다.
다음 코드를 살펴봅시다.
from nltk.stem import WordNetLemmatizer
from nltk.corpus import wordnet
# Lemmatizer 객체 생성
lemmatizer = WordNetLemmatizer()
# 다양한 형태의 단어들
words = ["running", "ran", "better", "are", "feet", "geese"]
# 표제어 추출 (품사 정보 없이)
lemmas = [lemmatizer.lemmatize(word) for word in words]
print("기본:", lemmas)
# 품사 정보와 함께 (더 정확함)
lemmas_v = [lemmatizer.lemmatize(word, pos='v') for word in words]
print("동사로:", lemmas_v)
# ['run', 'run', 'better', 'be', 'feet', 'geese']
김개발 씨는 어간 추출의 한계를 느끼기 시작했습니다. "better"와 "best"가 "good"으로 통일되지 않고, "mice"와 "mouse"가 따로 취급되었습니다.
"더 정확한 방법은 없을까요?" 박시니어 씨가 새로운 해결책을 제시했습니다. "표제어 추출은 언어학적 지식을 활용해서 더 정확하게 처리해요." 표제어 추출이란? 표제어 추출을 쉽게 비유하자면, 도서관에서 책을 찾을 때 사용하는 색인과 같습니다.
"달리는", "달렸다", "달린다"를 모두 "달리다"라는 표제어로 찾듯이, 다양한 변형을 사전의 기본형으로 통일합니다. 단순히 어미를 자르는 것이 아니라 언어 규칙을 적용합니다.
어간 추출과의 차이 어간 추출은 단순하지만 부정확합니다. 규칙만 적용하다 보니 "better"를 "good"으로 바꾸지 못합니다.
반면 표제어 추출은 사전 기반입니다. WordNet이라는 영어 어휘 데이터베이스를 참조해서 "better"가 "good"의 비교급임을 알고 변환합니다.
"are", "is", "was"를 모두 "be"로 통일하는 것도 가능합니다. WordNet의 역할 WordNet은 프린스턴 대학에서 만든 영어 어휘 데이터베이스입니다.
단어들을 의미 관계로 연결합니다. 동의어, 반의어, 상하위어 정보를 포함하고 있어 문맥을 고려한 변환이 가능합니다.
NLTK의 WordNetLemmatizer는 이 데이터베이스를 활용합니다. 코드 상세 분석 첫 번째 예시에서는 품사 정보 없이 표제어를 추출합니다.
기본적으로 명사로 가정하므로 "running"이 "running"으로 남습니다. 두 번째 예시에서는 pos='v'로 품사를 동사로 지정합니다.
그러면 "running"이 "run"으로, "ran"도 "run"으로 올바르게 변환됩니다. 품사 정보가 정확도를 크게 좌우합니다.
품사 태깅과의 조합 실무에서는 표제어 추출 전에 품사 태깅을 먼저 수행합니다. "Running is good"에서 "running"은 동명사이고, "I am running"에서는 동사입니다.
품사 태거로 이를 구분한 후 적절한 표제어를 추출하면 정확도가 극대화됩니다. 실무 적용 사례 질의응답 시스템을 개발한다고 가정해봅시다.
사용자가 "What are the best practices?"라고 물으면, "best"를 "good"으로 변환해 "good practice"에 관한 문서도 검색해야 합니다. 표제어 추출 없이는 "best"와 "good"을 연결할 수 없어 관련 정보를 놓치게 됩니다.
챗봇, 검색 엔진, 추천 시스템 모두 표제어 추출을 활용합니다. 한국어 표제어 추출 한국어는 교착어라 더 복잡합니다.
"먹었습니다"를 "먹다"로 변환하려면 형태소 분석이 필수입니다. KoNLPy의 형태소 분석기들은 자동으로 기본형을 제공합니다.
Okt, Komoran, Mecab 모두 표제어 추출 기능을 내장하고 있습니다. 성능 고려사항 표제어 추출은 사전 검색이 필요해서 어간 추출보다 느립니다.
대용량 데이터를 처리할 때는 속도와 정확도를 저울질해야 합니다. 실시간 처리가 중요하면 어간 추출을, 정확도가 중요하면 표제어 추출을 선택하세요.
또는 하이브리드 방식으로 자주 쓰는 단어만 표제어 추출하고 나머지는 어간 추출하는 방법도 있습니다. 정리 김개발 씨는 표제어 추출을 적용해서 "better"를 "good"으로 올바르게 변환했습니다.
검색 품질이 한층 향상되었습니다. "어간 추출과 표제어 추출의 차이를 확실히 알겠어요!" 표제어 추출은 어간 추출보다 정확하지만 느립니다.
상황에 맞게 선택하세요.
실전 팁
💡 - 품사 태깅과 함께 사용하면 정확도가 크게 향상됩니다
- 대용량 데이터는 어간 추출, 소량의 중요 데이터는 표제어 추출을 고려하세요
- WordNet이 없는 언어는 형태소 분석기의 기본형 기능을 활용하세요
6. 텍스트 정규화
다양한 전처리 기법을 배운 김개발 씨는 실제 데이터를 처리하다 새로운 문제를 발견했습니다. 같은 의미인데 "colour"와 "color", "10"과 "ten"이 다르게 취급되었습니다.
박시니어 씨가 말했습니다. "텍스트 정규화로 표현을 통일하세요."
텍스트 정규화는 다양한 표현을 일관된 형태로 통일하는 과정입니다. 대소문자 통일, 숫자 변환, 약어 확장 등을 포함합니다.
마치 서로 다른 단위를 표준 단위로 바꾸는 것처럼, 텍스트를 표준 형태로 변환합니다.
다음 코드를 살펴봅시다.
import re
text = "I bought 3 apples and 2 Oranges for $5.50 in the U.S.A."
# 1. 소문자 변환
text = text.lower()
# 2. 숫자를 특수 토큰으로 변환
text = re.sub(r'\d+\.?\d*', '<NUM>', text)
# 3. 약어 확장 (간단한 예시)
abbreviations = {
"u.s.a.": "united states of america",
"u.s.": "united states"
}
for abbr, full in abbreviations.items():
text = text.replace(abbr, full)
print("정규화 결과:", text)
# "i bought <NUM> apples and <NUM> oranges for $<NUM> in the united states of america."
김개발 씨는 글로벌 쇼핑몰의 리뷰 데이터를 분석하고 있었습니다. 미국, 영국, 호주 고객들의 리뷰를 합쳐서 처리하는데 문제가 생겼습니다.
영국식 영어인 "colour"와 미국식 영어인 "color"가 다른 단어로 취급되었습니다. "3 days"와 "three days"도 마찬가지였습니다.
"이걸 어떻게 통일하지?" 김개발 씨는 고민에 빠졌습니다. 박시니어 씨가 조언했습니다.
"텍스트 정규화를 통해 이런 변형들을 표준 형태로 통일할 수 있어요." 텍스트 정규화란? 정규화를 쉽게 비유하자면, 세계 각국의 통화를 달러로 환전하는 것과 같습니다. 원화, 엔화, 유로를 각각 따로 계산하면 복잡하지만, 모두 달러로 바꾸면 쉽게 비교할 수 있습니다.
마찬가지로 텍스트의 다양한 표현을 표준 형태로 바꾸면 일관된 처리가 가능합니다. 정규화가 필요한 이유 실제 텍스트 데이터는 매우 다양합니다.
같은 단어도 대소문자가 섞여 있습니다. "Apple", "apple", "APPLE"이 모두 등장합니다.
숫자도 "3", "three", "three hundred"처럼 여러 형태로 나타납니다. 약어는 "Dr.", "Dr", "Doctor"처럼 불규칙합니다.
이런 변형들을 그대로 두면 데이터 분산이 심해집니다. 같은 의미인데 여러 형태로 쪼개져서 통계적 패턴을 찾기 어려워집니다.
정규화 기법들 텍스트 정규화는 여러 기법을 조합합니다. 대소문자 통일은 가장 기본입니다.
일반적으로 모두 소문자로 바꿉니다. 단, 고유명사가 중요한 경우는 예외입니다.
숫자 처리는 상황에 따라 다릅니다. 숫자 자체가 중요하지 않으면 <NUM> 같은 특수 토큰으로 대체합니다.
금액이나 날짜가 중요하면 별도 처리합니다. 약어 확장은 도메인 지식이 필요합니다.
의료 분야의 "BP"는 "blood pressure"이고, IT에서는 "base pointer"일 수 있습니다. 코드 상세 분석 위 코드는 세 단계 정규화를 수행합니다.
첫째, lower()로 모든 글자를 소문자로 변환합니다. 간단하지만 효과적입니다.
둘째, 정규표현식으로 숫자를 찾아 <NUM>으로 대체합니다. \d+\.?\d*는 정수와 소수를 모두 매칭합니다.
"3", "5.50" 모두 처리됩니다. 셋째, 사전 기반으로 약어를 확장합니다.
"u.s.a."를 "united states of america"로 바꿉니다. 실무에서는 수백 개의 약어 사전을 유지합니다.
실무 적용 사례 의료 기록 분석 시스템을 개발한다고 가정해봅시다. 의사들은 "BP", "b.p.", "blood pressure"를 혼용합니다.
정규화 없이는 같은 개념을 세 번 따로 처리해야 합니다. 약어 사전을 구축하고 정규화를 적용하면 모든 표현이 "blood pressure"로 통일됩니다.
분석 정확도가 크게 향상됩니다. URL과 이메일 처리 소셜 미디어 데이터는 URL과 이메일이 많습니다.
이들을 그대로 두면 노이즈가 됩니다. 정규표현식으로 URL을 <URL>, 이메일을 <EMAIL>로 대체하면 깔끔해집니다.
필요하면 완전히 제거할 수도 있습니다. 한국어 정규화 한국어는 띄어쓰기 통일이 중요합니다.
"안녕하세요"와 "안녕 하세요"를 같게 만들어야 합니다. 또한 맞춤법 교정도 정규화의 일부입니다.
"안뇽"을 "안녕"으로, "ㅋㅋ"를 제거하거나 <LAUGH>로 대체할 수 있습니다. 한국어 전용 정규화 라이브러리인 soynlp, customized-konlpy를 활용하세요.
주의사항 과도한 정규화는 정보 손실을 일으킵니다. 예를 들어 주가 분석에서 "Apple"과 "apple"은 다른 의미입니다.
하나는 회사명이고 하나는 과일입니다. 도메인 특성을 고려해서 필요한 만큼만 정규화하세요.
모든 것을 통일하는 것보다 맥락을 유지하는 것이 중요할 때도 있습니다. 정리 김개발 씨는 정규화 파이프라인을 구축해서 영미권 리뷰를 통일된 형태로 처리했습니다.
분석 결과가 훨씬 일관되고 신뢰할 수 있게 되었습니다. "정규화가 이렇게 중요했군요!" 텍스트 정규화는 전처리의 마지막 마무리입니다.
꼼꼼하게 처리하면 후속 작업이 훨씬 수월합니다.
실전 팁
💡 - 정규화는 데이터 특성에 맞게 커스터마이징하세요
- 약어 사전은 지속적으로 업데이트하고 관리하세요
- 정보 손실을 최소화하도록 과도한 정규화를 피하세요
7. NLTK와 KoNLPy 라이브러리
다양한 전처리 기법을 직접 구현하던 김개발 씨는 코드가 점점 복잡해지는 것을 느꼈습니다. 박시니어 씨가 말했습니다.
"직접 만들 필요 없어요. NLTK와 KoNLPy 같은 검증된 라이브러리를 쓰세요."
NLTK는 영어 자연어 처리를 위한 파이썬 대표 라이브러리입니다. KoNLPy는 한국어 처리를 위한 라이브러리입니다.
토큰화, 품사 태깅, 형태소 분석 등 전처리에 필요한 모든 도구를 제공합니다.
다음 코드를 살펴봅시다.
# NLTK 사용 예시
import nltk
from nltk.tokenize import word_tokenize
from nltk.tag import pos_tag
# 영어 처리
text_en = "Natural language processing is fascinating!"
tokens = word_tokenize(text_en)
pos_tags = pos_tag(tokens)
print("영어 품사 태깅:", pos_tags)
# KoNLPy 사용 예시
from konlpy.tag import Okt
okt = Okt()
text_ko = "자연어 처리는 정말 흥미로워요"
morphs = okt.morphs(text_ko) # 형태소 분석
pos_ko = okt.pos(text_ko) # 품사 태깅
print("한국어 형태소:", morphs)
print("한국어 품사:", pos_ko)
김개발 씨는 지금까지 배운 전처리 기법들을 직접 구현했습니다. 토큰화 함수, 불용어 제거 함수, 정규화 함수를 하나씩 만들었습니다.
하지만 코드가 500줄을 넘어가면서 관리가 어려워졌습니다. 더 큰 문제는 예외 케이스였습니다.
"Mr. Smith"를 두 문장으로 잘못 나누고, "don't"를 제대로 처리하지 못했습니다.
직접 만든 함수의 한계였습니다. 박시니어 씨가 조언했습니다.
"바퀴를 다시 발명할 필요 없어요. NLTK 같은 검증된 라이브러리를 사용하세요." NLTK란? NLTK는 Natural Language Toolkit의 약자로, 1999년부터 개발된 역사 깊은 라이브러리입니다.
펜실베이니아 대학에서 시작해 전 세계 연구자들이 기여하고 있습니다. 마치 과학자들이 공유하는 실험 도구처럼, NLTK는 NLP 연구자와 개발자들의 표준 도구가 되었습니다.
교육용으로도 훌륭해서 많은 대학 강의에서 사용됩니다. NLTK의 주요 기능 NLTK는 방대한 기능을 제공합니다.
토큰화는 문장/단어 레벨 모두 지원합니다. 품사 태깅은 단어의 문법적 역할을 식별합니다.
"run"이 명사인지 동사인지 구분합니다. 구문 분석은 문장 구조를 트리로 표현합니다.
의미 분석은 단어 간 관계를 파악합니다. 심지어 코퍼스까지 내장되어 있어 학습 데이터로 바로 사용할 수 있습니다.
KoNLPy의 등장 NLTK는 영어 중심이라 한국어는 잘 처리하지 못합니다. 한국어는 교착어로 영어와 구조가 완전히 다르기 때문입니다.
이 문제를 해결하기 위해 KoNLPy가 개발되었습니다. 서울대 박은정 교수팀이 주도한 이 프로젝트는 한국어 형태소 분석기를 파이썬에서 쉽게 사용할 수 있게 만들었습니다.
KoNLPy의 형태소 분석기들 KoNLPy는 여러 형태소 분석기를 통합 제공합니다. Okt는 트위터 한국어 처리기로, 빠르고 간편합니다.
초보자에게 추천합니다. Komoran은 정확도가 높고 복합명사를 잘 처리합니다.
Mecab은 가장 빠르지만 설치가 복잡합니다. Hannanum과 Kkma는 학술용으로 정교합니다.
상황에 맞게 선택하세요. 속도가 중요하면 Mecab, 정확도가 중요하면 Komoran을 사용합니다.
코드 실전 활용 위 코드에서 NLTK의 pos_tag()는 품사를 태깅합니다. "Natural"은 형용사(JJ), "processing"은 명사(NN), "is"는 동사(VBZ)로 식별됩니다.
KoNLPy의 morphs()는 형태소 단위로 분리합니다. "흥미로워요"를 "흥미롭", "어요"로 나눕니다.
pos()는 품사까지 함께 반환합니다. 실무 적용 사례 챗봇을 개발한다고 가정해봅시다.
사용자 입력 "배송이 언제 도착하나요?"를 분석해야 합니다. KoNLPy로 형태소 분석하면 "배송", "이", "언제", "도착", "하", "나요"로 분리됩니다.
"배송"과 "도착"이 핵심 명사임을 파악하고, "언제"가 시간 질문임을 인식합니다. 이 정보로 적절한 답변을 생성할 수 있습니다.
설치와 초기 설정 NLTK는 pip install nltk로 설치하고, 필요한 데이터를 추가로 다운로드해야 합니다. python import nltk nltk.download('punkt') # 토큰화 데이터 nltk.download('averaged_perceptron_tagger') # 품사 태깅 모델 nltk.download('stopwords') # 불용어 사전 KoNLPy는 자바 기반 분석기를 포함하므로 JDK 설치가 필요합니다.
pip install konlpy 후 JPype1도 자동 설치됩니다. 성능 최적화 대용량 데이터를 처리할 때는 멀티프로세싱을 활용하세요.
KoNLPy는 GIL 문제로 멀티스레딩이 비효율적이지만, 멀티프로세싱은 효과적입니다. 또한 캐싱을 적용하면 같은 텍스트를 반복 처리할 때 속도가 크게 향상됩니다.
functools의 lru_cache 데코레이터를 활용하세요. 주의사항 라이브러리에 맹목적으로 의존하지 마세요.
NLTK의 토크나이저가 항상 완벽한 것은 아닙니다. 도메인 특화 용어는 사용자 사전에 추가해야 정확하게 처리됩니다.
KoNLPy도 마찬가지입니다. "갤럭시폴드"같은 신조어는 사전에 없어 잘못 분리될 수 있습니다.
지속적인 업데이트가 필요합니다. 정리 김개발 씨는 직접 만든 500줄의 코드를 NLTK와 KoNLPy를 사용한 50줄로 대체했습니다.
성능도 더 좋고 유지보수도 쉬워졌습니다. "검증된 도구를 쓰는 게 정답이었네요!" 텍스트 전처리는 NLTK와 KoNLPy로 시작하세요.
기본을 익힌 후 필요하면 커스터마이징하면 됩니다.
실전 팁
💡 - 영어는 NLTK, 한국어는 KoNLPy를 기본으로 사용하세요
- 도메인 특화 용어는 사용자 사전에 추가하세요
- 대용량 처리는 멀티프로세싱과 캐싱을 활용하세요
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
Helm 마이크로서비스 패키징 완벽 가이드
Kubernetes 환경에서 마이크로서비스를 효율적으로 패키징하고 배포하는 Helm의 핵심 기능을 실무 중심으로 학습합니다. Chart 생성부터 릴리스 관리까지 체계적으로 다룹니다.
보안 아키텍처 구성 완벽 가이드
프로젝트의 보안을 처음부터 설계하는 방법을 배웁니다. AWS 환경에서 VPC부터 WAF, 암호화, 접근 제어까지 실무에서 바로 적용할 수 있는 보안 아키텍처를 단계별로 구성해봅니다.
AWS Organizations 완벽 가이드
여러 AWS 계정을 체계적으로 관리하고 통합 결제와 보안 정책을 적용하는 방법을 실무 스토리로 쉽게 배워봅니다. 초보 개발자도 바로 이해할 수 있는 친절한 설명과 실전 예제를 제공합니다.
AWS KMS 암호화 완벽 가이드
AWS KMS(Key Management Service)를 활용한 클라우드 데이터 암호화 방법을 초급 개발자를 위해 쉽게 설명합니다. CMK 생성부터 S3, EBS 암호화, 봉투 암호화까지 실무에 필요한 모든 내용을 담았습니다.
AWS Secrets Manager 완벽 가이드
AWS에서 데이터베이스 비밀번호, API 키 등 민감한 정보를 안전하게 관리하는 Secrets Manager의 핵심 개념과 실무 활용법을 배워봅니다. 초급 개발자도 쉽게 따라할 수 있도록 실전 예제와 함께 설명합니다.