🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

자연어 처리 기초 완벽 가이드 - 슬라이드 1/8
A

AI Generated

2025. 12. 4. · 11 Views

자연어 처리 기초 완벽 가이드

컴퓨터가 인간의 언어를 이해하고 분석하는 자연어 처리(NLP)의 핵심 개념을 초급 개발자도 쉽게 이해할 수 있도록 설명합니다. 텍스트 전처리부터 TF-IDF까지, 실무에서 바로 활용할 수 있는 기초를 다룹니다.


목차

  1. 자연어_처리_개론
  2. NLP_용어_이해
  3. 텍스트_전처리_기법
  4. 토큰화와_정규화
  5. 단어_문서_행렬
  6. TF_IDF_계산하기
  7. 텍스트_데이터_정제

1. 자연어 처리 개론

어느 날 김개발 씨는 회사에서 새로운 프로젝트를 맡게 되었습니다. "고객 리뷰를 분석해서 불만 사항을 자동으로 분류하는 시스템을 만들어주세요." 수천 개의 리뷰를 사람이 일일이 읽을 수는 없으니, 컴퓨터가 텍스트를 이해하도록 만들어야 합니다.

바로 이때 필요한 것이 자연어 처리입니다.

**자연어 처리(Natural Language Processing, NLP)**는 컴퓨터가 인간의 언어를 이해하고 분석하며 생성하는 기술입니다. 마치 외국어 통역사가 두 나라 사람 사이에서 소통을 돕듯이, NLP는 인간과 컴퓨터 사이의 언어 장벽을 허물어줍니다.

이것을 제대로 이해하면 챗봇, 번역기, 감성 분석 등 다양한 텍스트 기반 서비스를 구축할 수 있습니다.

다음 코드를 살펴봅시다.

# 자연어 처리의 기본 흐름을 보여주는 예제
import nltk
from nltk.tokenize import word_tokenize

# 원본 텍스트 - 컴퓨터는 이것을 그냥 문자열로 봅니다
text = "자연어 처리는 정말 흥미로운 분야입니다!"

# 토큰화 - 텍스트를 의미 있는 단위로 분리합니다
tokens = word_tokenize(text)
print(f"원본: {text}")
print(f"토큰화 결과: {tokens}")

# 결과: ['자연어', '처리는', '정말', '흥미로운', '분야입니다', '!']
# 이제 컴퓨터가 각 단어를 개별적으로 분석할 수 있습니다

김개발 씨는 입사 2년 차 개발자입니다. Python으로 웹 서비스를 만드는 일은 익숙했지만, 텍스트를 분석하는 일은 처음이었습니다.

팀장님이 건넨 프로젝트 기획서를 읽으며 고민에 빠졌습니다. "컴퓨터가 어떻게 글을 이해할 수 있지?" 선배 개발자 박시니어 씨가 다가와 말했습니다.

"NLP를 공부해야 할 때가 왔네요. 어렵게 생각하지 마세요.

기초부터 차근차근 배우면 됩니다." 그렇다면 자연어 처리란 정확히 무엇일까요? 쉽게 비유하자면, 자연어 처리는 마치 외국어 통역사와 같습니다.

통역사가 한국어를 영어로 바꿔서 외국인이 이해할 수 있게 해주듯이, NLP는 인간의 언어를 컴퓨터가 이해할 수 있는 형태로 변환해줍니다. 컴퓨터는 본래 0과 1만 이해하는 기계이기 때문입니다.

여기서 자연어라는 말에 주목해봅시다. 자연어란 우리가 일상에서 자연스럽게 사용하는 언어를 말합니다.

한국어, 영어, 일본어 같은 것들이죠. 반대로 프로그래밍 언어는 인공어입니다.

Python이나 Java처럼 사람이 규칙을 정해서 만든 언어이기 때문입니다. NLP가 없던 시절에는 어땠을까요?

과거에는 텍스트 데이터를 분석하려면 사람이 직접 읽어야 했습니다. 수백 개의 고객 리뷰를 분류하려면 며칠이 걸렸습니다.

더 큰 문제는 사람마다 판단 기준이 달라서 일관성이 없었다는 점입니다. 프로젝트가 커질수록 이런 문제는 감당하기 어려워졌습니다.

바로 이런 문제를 해결하기 위해 자연어 처리 기술이 발전했습니다. NLP를 사용하면 수만 개의 리뷰도 몇 분 만에 분석할 수 있습니다.

또한 일관된 기준으로 분류하기 때문에 결과를 신뢰할 수 있습니다. 무엇보다 24시간 쉬지 않고 작동한다는 큰 장점이 있습니다.

위의 코드를 살펴보겠습니다. 먼저 nltk 라이브러리를 불러옵니다.

NLTK는 Natural Language Toolkit의 약자로, Python에서 가장 널리 사용되는 NLP 라이브러리입니다. 다음으로 word_tokenize 함수를 사용해 문장을 단어 단위로 쪼갭니다.

이것이 NLP의 첫 번째 단계인 토큰화입니다. 실제 현업에서는 어떻게 활용할까요?

예를 들어 쇼핑몰 서비스를 운영한다고 가정해봅시다. 매일 쏟아지는 상품 리뷰에서 "배송이 느려요", "포장이 엉망이에요" 같은 불만을 자동으로 찾아낼 수 있습니다.

이런 정보를 바탕으로 서비스를 개선하면 고객 만족도가 올라갑니다. 많은 기업에서 이런 방식으로 NLP를 활용하고 있습니다.

하지만 주의할 점도 있습니다. 자연어는 매우 복잡하고 모호합니다.

"이 영화 미쳤다"라는 표현이 칭찬인지 비난인지는 문맥을 봐야 알 수 있습니다. 단순한 규칙만으로는 이런 미묘한 차이를 잡아내기 어렵습니다.

따라서 충분한 학습 데이터와 정교한 모델이 필요합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.

박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다. "아, NLP가 이런 거였군요!

생각보다 재미있을 것 같아요." 자연어 처리의 세계는 넓고 깊습니다. 하지만 기초부터 탄탄히 다지면 누구나 이 분야를 정복할 수 있습니다.

실전 팁

💡 - NLTK, spaCy, KoNLPy 등 다양한 NLP 라이브러리를 먼저 설치해두세요

  • 한국어 처리에는 KoNLPy가, 영어 처리에는 NLTK나 spaCy가 적합합니다
  • 작은 데이터셋으로 먼저 실험해보고, 점차 규모를 키워가세요

2. NLP 용어 이해

김개발 씨가 NLP 관련 블로그를 읽다가 머리가 복잡해졌습니다. 코퍼스, 토큰, 형태소, 불용어...

처음 보는 단어들이 쏟아져 나왔기 때문입니다. "이 용어들부터 정리해야겠어요." 박시니어 씨가 화이트보드 앞에 서며 말했습니다.

NLP를 제대로 이해하려면 먼저 핵심 용어들을 알아야 합니다. **코퍼스(Corpus)**는 분석할 텍스트의 집합이고, **토큰(Token)**은 텍스트를 쪼갠 최소 단위입니다.

형태소는 의미를 가진 가장 작은 말의 단위이며, **불용어(Stopword)**는 분석에서 제외할 단어를 뜻합니다.

다음 코드를 살펴봅시다.

# NLP 핵심 용어를 코드로 이해하기
from konlpy.tag import Okt

# 코퍼스(Corpus): 분석할 텍스트 데이터의 집합
corpus = [
    "오늘 날씨가 정말 좋습니다",
    "내일은 비가 올 예정입니다",
    "주말에 소풍을 가고 싶어요"
]

okt = Okt()
# 토큰(Token): 텍스트를 나눈 단위
tokens = okt.morphs(corpus[0])  # 형태소 단위로 토큰화
print(f"토큰: {tokens}")  # ['오늘', '날씨', '가', '정말', '좋습니다']

# 불용어(Stopword): 분석에서 제외할 단어
stopwords = ['가', '를', '은', '는', '이', '의']
clean_tokens = [t for t in tokens if t not in stopwords]
print(f"불용어 제거: {clean_tokens}")  # ['오늘', '날씨', '정말', '좋습니다']

김개발 씨는 노트를 펴고 박시니어 씨의 설명을 받아 적기 시작했습니다. 새로운 분야를 배울 때 가장 먼저 해야 할 일은 그 분야의 언어를 익히는 것이기 때문입니다.

박시니어 씨가 화이트보드에 큰 글씨로 **코퍼스(Corpus)**라고 적었습니다. "코퍼스는 라틴어로 '몸'이라는 뜻이에요.

NLP에서는 분석하려는 텍스트 데이터의 집합을 말합니다." 마치 도서관을 생각하면 이해하기 쉽습니다. 도서관에 있는 모든 책이 하나의 코퍼스라고 볼 수 있습니다.

뉴스 기사 10만 개를 모아놓으면 뉴스 코퍼스가 되고, 트위터 글을 모아놓으면 소셜 미디어 코퍼스가 됩니다. 다음으로 **토큰(Token)**입니다.

토큰은 텍스트를 나눈 최소 단위입니다. 어떤 기준으로 나누느냐에 따라 토큰의 형태가 달라집니다.

공백으로 나누면 단어가 토큰이 되고, 형태소 분석기를 쓰면 형태소가 토큰이 됩니다. "마치 레고 블록과 같아요." 박시니어 씨가 비유를 들었습니다.

"완성된 레고 성을 분해하면 작은 블록들이 나오잖아요. 문장을 분해하면 토큰이 나오는 거예요." **형태소(Morpheme)**는 의미를 가진 가장 작은 말의 단위입니다.

예를 들어 "먹었다"라는 단어를 보겠습니다. 이것은 "먹-"(동작) + "-었-"(과거) + "-다"(종결)로 나눌 수 있습니다.

각각이 의미를 담고 있는 형태소입니다. 영어보다 한국어에서 형태소 분석이 더 중요한 이유가 바로 이것입니다.

마지막으로 **불용어(Stopword)**입니다. 불용어는 분석에 큰 의미가 없어서 제거하는 단어를 말합니다.

한국어에서는 "은, 는, 이, 가, 을, 를" 같은 조사가 대표적입니다. 영어에서는 "the, a, is, are" 같은 단어들이죠.

이런 단어들은 너무 자주 나타나서 특별한 정보를 주지 않습니다. 위의 코드를 살펴보면, KoNLPyOkt 분석기를 사용하고 있습니다.

Okt는 Open Korean Text의 약자로, 한국어 형태소 분석에 널리 쓰이는 도구입니다. morphs 함수는 텍스트를 형태소 단위로 쪼개줍니다.

리스트 컴프리헨션을 사용해 불용어를 제거하는 부분도 주목해보세요. 토큰 목록에서 불용어 목록에 없는 것만 남기는 간단하지만 효과적인 방법입니다.

실무에서는 도메인에 따라 불용어 목록을 직접 만들기도 합니다. 의료 분야에서는 일반적인 의학 용어를, 법률 분야에서는 흔한 법률 용어를 불용어로 지정할 수 있습니다.

김개발 씨가 노트를 덮으며 말했습니다. "이제 용어들이 머릿속에서 정리되는 것 같아요!" 용어를 제대로 알면 문서를 읽을 때도, 코드를 짤 때도 훨씬 수월해집니다.

이것이 바로 기초를 탄탄히 해야 하는 이유입니다.

실전 팁

💡 - 새로운 용어를 만나면 직접 코드로 실험해보며 익히세요

  • 한국어 NLP에서는 형태소 분석이 특히 중요합니다
  • 불용어 목록은 프로젝트 특성에 맞게 커스터마이징하세요

3. 텍스트 전처리 기법

김개발 씨가 실제 데이터를 열어보고 당황했습니다. "이게 뭐예요?

HTML 태그도 섞여 있고, 이상한 특수문자도 있고..." 현실의 텍스트 데이터는 생각보다 지저분했습니다. 박시니어 씨가 웃으며 말했습니다.

"그래서 전처리가 필요한 거예요."

텍스트 전처리는 분석 전에 데이터를 깨끗하게 정리하는 과정입니다. 마치 요리하기 전에 재료를 씻고 다듬는 것과 같습니다.

HTML 태그 제거, 특수문자 처리, 대소문자 통일, 공백 정리 등이 포함되며, 이 과정 없이는 정확한 분석이 불가능합니다.

다음 코드를 살펴봅시다.

import re

def preprocess_text(text):
    # 1. HTML 태그 제거
    text = re.sub(r'<[^>]+>', '', text)

    # 2. 특수문자 제거 (한글, 영문, 숫자, 공백만 유지)
    text = re.sub(r'[^가-힣a-zA-Z0-9\s]', '', text)

    # 3. 연속된 공백을 하나로 정리
    text = re.sub(r'\s+', ' ', text)

    # 4. 앞뒤 공백 제거
    text = text.strip()

    # 5. 소문자 변환 (영문의 경우)
    text = text.lower()

    return text

# 지저분한 원본 데이터
raw_text = "<p>Hello!!!   자연어 처리는 @#정말 AMAZING합니다...</p>"
clean_text = preprocess_text(raw_text)
print(f"전처리 결과: {clean_text}")
# 결과: "hello 자연어 처리는 정말 amazing합니다"

김개발 씨가 크롤링한 데이터를 처음 열어봤을 때, 눈앞이 캄캄해졌습니다. 웹에서 가져온 텍스트에는 온갖 것들이 섞여 있었기 때문입니다.

"<div class='content'>상품 후기입니다!!!</div>" 이런 데이터를 그대로 분석하면 어떻게 될까요? 컴퓨터는 "div"와 "class"도 중요한 단어로 인식할 것입니다.

당연히 분석 결과는 엉망이 됩니다. 박시니어 씨가 차분하게 설명했습니다.

"전처리는 데이터 청소예요. 분석에 방해되는 불순물을 제거하는 거죠." 마치 금광에서 금을 캐는 것과 같습니다.

광석을 캐면 금만 들어있는 게 아니라 흙과 돌도 함께 나옵니다. 금만 추출하려면 여러 단계의 정제 과정이 필요합니다.

텍스트 전처리도 마찬가지입니다. 가장 먼저 해야 할 일은 HTML 태그 제거입니다.

웹에서 수집한 데이터에는 거의 항상 HTML 태그가 포함되어 있습니다. <p>, <div>, <span> 같은 것들이죠.

정규표현식 <[^>]+>를 사용하면 꺾쇠 안의 모든 내용을 찾아서 제거할 수 있습니다. 다음은 특수문자 처리입니다.

"!!!", "@#$%", "..." 같은 특수문자들은 대부분 분석에 필요하지 않습니다. 물론 감성 분석에서 느낌표가 강조의 의미를 가질 수도 있지만, 기본적인 분석에서는 제거하는 것이 일반적입니다.

공백 정리도 빼놓을 수 없습니다. 데이터에는 종종 연속된 공백이 들어있습니다.

"자연어 처리"처럼요. 이것을 "자연어 처리"로 정리해야 토큰화가 제대로 됩니다.

\s+ 패턴으로 연속된 공백을 찾아 하나로 바꿔줍니다. 대소문자 통일은 영문 처리에서 중요합니다.

"Python"과 "python"은 컴퓨터 입장에서 완전히 다른 단어입니다. 하지만 사람이 보기에는 같은 의미죠.

모두 소문자로 바꾸면 이런 중복을 방지할 수 있습니다. 위 코드의 preprocess_text 함수는 이 모든 과정을 순서대로 수행합니다.

re 모듈의 sub 함수가 핵심입니다. 패턴을 찾아서 원하는 문자열로 바꿔주는 역할을 합니다.

한 가지 주의할 점이 있습니다. 전처리를 너무 과하게 하면 중요한 정보가 손실될 수 있습니다.

예를 들어 "3.14"에서 마침표를 제거하면 의미가 완전히 달라집니다. 숫자와 마침표 사이의 관계를 고려해야 합니다.

또한 이모지를 어떻게 처리할지도 고민해야 합니다. 소셜 미디어 분석에서 이모지는 감정을 나타내는 중요한 신호일 수 있기 때문입니다.

김개발 씨가 직접 함수를 실행해보며 감탄했습니다. "와, 정말 깔끔해졌네요!" 전처리는 NLP 파이프라인에서 가장 먼저 수행되는 단계입니다.

이 단계를 잘 해야 이후 모든 분석이 의미를 가집니다.

실전 팁

💡 - 정규표현식(regex)을 익혀두면 전처리가 훨씬 수월해집니다

  • 전처리 함수는 재사용 가능하게 만들어두세요
  • 원본 데이터는 항상 백업해두고 전처리를 진행하세요

4. 토큰화와 정규화

전처리를 마친 김개발 씨 앞에 새로운 과제가 놓였습니다. 깨끗해진 텍스트를 이제 분석 가능한 단위로 쪼개야 합니다.

"문장을 어떻게 나누는 게 좋을까요?" 박시니어 씨가 답했습니다. "토큰화와 정규화를 배울 차례예요."

**토큰화(Tokenization)**는 텍스트를 분석 가능한 최소 단위로 나누는 과정입니다. **정규화(Normalization)**는 같은 의미의 다른 표현을 하나로 통일하는 작업입니다.

"뛰다", "뛰어", "뛰는"을 모두 "뛰다"로 통일하면 분석이 훨씬 정확해집니다.

다음 코드를 살펴봅시다.

from konlpy.tag import Okt

okt = Okt()

# 토큰화: 여러 수준으로 나눌 수 있습니다
text = "아버지가 방에 들어가신다"

# 형태소 단위 토큰화
morphs = okt.morphs(text)
print(f"형태소: {morphs}")  # ['아버지', '가', '방', '에', '들어가신다']

# 명사만 추출
nouns = okt.nouns(text)
print(f"명사: {nouns}")  # ['아버지', '방']

# 품사 태깅 (POS tagging)
pos = okt.pos(text)
print(f"품사: {pos}")  # [('아버지', 'Noun'), ('가', 'Josa'), ...]

# 정규화: 어간 추출 (stem=True)
normalized = okt.morphs(text, stem=True)
print(f"정규화: {normalized}")  # ['아버지', '가', '방', '에', '들어가다']

깨끗하게 정리된 텍스트가 있습니다. 하지만 이것만으로는 분석을 시작할 수 없습니다.

컴퓨터가 이해할 수 있는 단위로 나눠줘야 합니다. 박시니어 씨가 비유를 들었습니다.

"문장은 기차와 같아요. 기차가 여러 칸으로 연결되어 있듯이, 문장도 여러 단어로 연결되어 있죠.

토큰화는 이 기차를 각 칸으로 분리하는 작업이에요." 영어는 토큰화가 비교적 간단합니다. 단어 사이에 공백이 있기 때문이죠.

"I love Python"을 공백으로 나누면 ["I", "love", "Python"]이 됩니다. 하지만 한국어는 다릅니다.

한국어는 교착어입니다. 단어에 조사가 붙어서 하나의 덩어리가 됩니다.

"사과를"에서 "사과"와 "를"은 붙어 있지만 별개의 의미 단위입니다. 그래서 한국어에서는 형태소 분석이 필수입니다.

위 코드에서 Okt 분석기의 세 가지 함수를 살펴보세요. morphs 함수는 텍스트를 형태소 단위로 쪼갭니다.

"아버지가"가 "아버지" + "가"로 분리됩니다. nouns 함수는 명사만 추출합니다.

키워드 분석에 유용합니다. pos 함수는 품사 태깅을 수행합니다.

각 형태소가 명사인지, 동사인지, 조사인지 알려줍니다. 정규화는 토큰화만큼 중요합니다.

"먹다", "먹었다", "먹는다", "먹을"은 모두 같은 동사의 변형입니다. 이것들을 각각 다른 단어로 취급하면 분석이 분산됩니다.

"먹다"라는 기본형으로 통일하면 그 단어의 빈도를 정확하게 셀 수 있습니다. 코드에서 stem=True 옵션을 주목하세요.

"들어가신다"가 "들어가다"로 변환됩니다. 이것이 바로 **어간 추출(Stemming)**입니다.

단어에서 활용 어미를 제거하고 기본형을 찾는 과정입니다. 영어에도 비슷한 개념이 있습니다.

Lemmatization이라고 합니다. "running", "ran", "runs"를 모두 "run"으로 바꾸는 것이죠.

실무에서 토큰화 방식을 선택할 때는 목적을 고려해야 합니다. 감성 분석에서는 형용사와 동사가 중요합니다.

"좋다", "싫다" 같은 표현이 감정을 나타내기 때문입니다. 반면 키워드 추출에서는 명사가 핵심입니다.

"배송", "품질", "가격" 같은 명사가 주제를 나타냅니다. 김개발 씨가 물었습니다.

"그럼 항상 정규화를 해야 하나요?" 박시니어 씨가 고개를 저었습니다. "상황에 따라 달라요.

'먹었다'와 '먹을 것이다'를 구분해야 하는 분석에서는 정규화를 하면 안 되겠죠." 결국 중요한 것은 분석의 목적입니다. 토큰화와 정규화는 도구일 뿐, 어떻게 사용할지는 개발자가 결정해야 합니다.

실전 팁

💡 - 한국어 형태소 분석기는 Okt, Komoran, Mecab 등 여러 종류가 있으니 비교해보세요

  • 명사만 필요하면 nouns(), 품사 정보가 필요하면 pos()를 사용하세요
  • 정규화 여부는 분석 목적에 따라 결정하세요

5. 단어 문서 행렬

토큰화를 마친 김개발 씨는 다음 질문을 던졌습니다. "이제 단어들을 모았는데, 이걸 어떻게 숫자로 바꾸나요?" 컴퓨터는 결국 숫자를 다루는 기계입니다.

텍스트를 숫자로 표현하는 방법, 바로 단어 문서 행렬을 배울 차례입니다.

**단어 문서 행렬(Term-Document Matrix, TDM)**은 문서 집합을 숫자 행렬로 표현하는 방법입니다. 행은 단어, 열은 문서를 나타내며, 각 셀에는 해당 단어가 해당 문서에 몇 번 등장하는지가 기록됩니다.

이것이 텍스트를 수학적으로 분석할 수 있게 해주는 핵심 기법입니다.

다음 코드를 살펴봅시다.

from sklearn.feature_extraction.text import CountVectorizer

# 분석할 문서들 (코퍼스)
documents = [
    "파이썬 자연어 처리 입문",
    "파이썬 데이터 분석 기초",
    "자연어 처리와 머신러닝"
]

# CountVectorizer: 단어 문서 행렬을 만들어줍니다
vectorizer = CountVectorizer()
tdm = vectorizer.fit_transform(documents)

# 단어 목록 확인
print(f"단어 목록: {vectorizer.get_feature_names_out()}")
# ['기초', '데이터', '머신러닝', '분석', '입문', '자연어', '처리', '처리와', '파이썬']

# 행렬 확인 (희소 행렬을 일반 배열로 변환)
print(f"단어 문서 행렬:\n{tdm.toarray()}")
# [[0 0 0 0 1 1 1 0 1]   문서1: 파이썬 자연어 처리 입문
#  [1 1 0 1 0 0 0 0 1]   문서2: 파이썬 데이터 분석 기초
#  [0 0 1 0 0 1 0 1 0]]  문서3: 자연어 처리와 머신러닝

김개발 씨는 중요한 사실을 깨달았습니다. 머신러닝 모델은 텍스트를 직접 이해하지 못합니다.

모델에 입력하려면 텍스트를 숫자로 바꿔야 합니다. 박시니어 씨가 화이트보드에 표를 그리기 시작했습니다.

"가장 기본적인 방법이 단어 문서 행렬이에요." 마치 출석부를 생각하면 됩니다. 학생 이름이 세로로 나열되고, 날짜가 가로로 나열됩니다.

각 칸에는 그날 그 학생이 출석했는지가 기록됩니다. 단어 문서 행렬도 마찬가지입니다.

단어가 세로로, 문서가 가로로 나열되고, 각 칸에는 그 단어가 그 문서에 몇 번 나왔는지가 기록됩니다. 위 코드의 결과를 자세히 살펴봅시다.

첫 번째 문서 "파이썬 자연어 처리 입문"의 행렬 표현은 [0 0 0 0 1 1 1 0 1]입니다. "입문"이 1번, "자연어"가 1번, "처리"가 1번, "파이썬"이 1번 등장했다는 뜻입니다.

나머지 단어들은 0입니다. CountVectorizer는 scikit-learn 라이브러리에서 제공하는 도구입니다.

텍스트를 넣으면 자동으로 토큰화하고 단어 문서 행렬을 만들어줍니다. fit_transform 메서드가 이 모든 일을 처리합니다.

결과로 나오는 것은 **희소 행렬(Sparse Matrix)**입니다. 대부분의 값이 0이기 때문에 메모리를 효율적으로 사용하기 위한 형태입니다.

toarray() 메서드로 일반 배열로 변환할 수 있습니다. 단어 문서 행렬에는 한계가 있습니다.

첫째, 차원의 저주 문제입니다. 단어가 많아지면 행렬이 매우 커집니다.

수만 개의 단어가 있으면 열이 수만 개가 됩니다. 둘째, 단어의 중요도를 반영하지 못합니다.

"은", "는" 같은 조사와 "인공지능" 같은 핵심 단어가 동등하게 취급됩니다. 단순히 등장 횟수만 세기 때문입니다.

셋째, 단어의 순서가 사라집니다. "개가 사람을 물었다"와 "사람이 개를 물었다"는 완전히 다른 의미지만, 단어 문서 행렬에서는 구분되지 않습니다.

이런 한계 때문에 실무에서는 TF-IDF 같은 개선된 방법을 많이 사용합니다. 다음 장에서 자세히 알아보겠습니다.

김개발 씨가 고개를 끄덕였습니다. "텍스트를 숫자로 바꾸는 게 이런 원리였군요!" 단어 문서 행렬은 NLP의 가장 기초적인 표현 방법입니다.

이것을 이해해야 더 복잡한 기법들도 이해할 수 있습니다.

실전 팁

💡 - CountVectorizer의 max_features 옵션으로 단어 수를 제한할 수 있습니다

  • ngram_range 옵션으로 연속된 단어 조합(바이그램, 트라이그램)도 추출 가능합니다
  • 희소 행렬은 메모리 효율적이므로 toarray() 변환은 필요할 때만 하세요

6. TF IDF 계산하기

김개발 씨가 단어 문서 행렬의 결과를 보며 의문이 들었습니다. "근데 '은', '는' 같은 단어랑 '인공지능' 같은 단어가 똑같이 1로 표시되잖아요.

뭔가 이상한데요?" 박시니어 씨가 미소 지었습니다. "좋은 질문이에요.

바로 그 문제를 해결하는 게 TF-IDF예요."

**TF-IDF(Term Frequency-Inverse Document Frequency)**는 단어의 중요도를 측정하는 가중치입니다. 특정 문서에 자주 등장하지만(TF 높음), 전체 문서에서는 드문 단어(IDF 높음)에 높은 점수를 부여합니다.

이를 통해 "그 문서를 대표하는 핵심 단어"를 찾을 수 있습니다.

다음 코드를 살펴봅시다.

from sklearn.feature_extraction.text import TfidfVectorizer
import numpy as np

documents = [
    "파이썬 자연어 처리 입문 가이드",
    "파이썬 데이터 분석 완벽 가이드",
    "자연어 처리와 딥러닝 실전"
]

# TF-IDF 벡터화
tfidf = TfidfVectorizer()
tfidf_matrix = tfidf.fit_transform(documents)

# 단어별 TF-IDF 값 확인
feature_names = tfidf.get_feature_names_out()
for doc_idx, doc in enumerate(documents):
    print(f"\n문서{doc_idx + 1}: {doc}")
    # 해당 문서의 TF-IDF 값
    scores = tfidf_matrix[doc_idx].toarray().flatten()
    # 상위 3개 단어 출력
    top_indices = np.argsort(scores)[::-1][:3]
    for idx in top_indices:
        print(f"  {feature_names[idx]}: {scores[idx]:.3f}")

단어 문서 행렬의 가장 큰 약점은 모든 단어를 동등하게 취급한다는 점입니다. "파이썬"이라는 핵심 단어와 "이", "가" 같은 조사가 같은 무게로 계산됩니다.

박시니어 씨가 비유를 들었습니다. "회사에서 모든 직원에게 똑같은 월급을 준다고 생각해보세요.

신입이든 10년 차든 똑같이요. 이상하죠?

기여도에 따라 차등을 줘야 합니다." TF-IDF가 바로 이 차등을 만들어줍니다. TF-IDF는 두 가지 요소의 곱입니다.

**TF(Term Frequency)**는 특정 문서에서 단어가 얼마나 자주 나오는가를 나타냅니다. **IDF(Inverse Document Frequency)**는 전체 문서에서 단어가 얼마나 드문가를 나타냅니다.

직관적으로 이해해봅시다. 어떤 단어가 한 문서에서 많이 나오면(TF 높음), 그 문서에서 중요한 단어일 가능성이 높습니다.

하지만 그 단어가 모든 문서에 다 나온다면(IDF 낮음), 사실 별로 특별한 단어가 아닙니다. 예를 들어 뉴스 기사 모음에서 "기자"라는 단어는 거의 모든 기사에 나올 것입니다.

TF는 높을 수 있지만 IDF는 매우 낮습니다. 반면 "인공지능"이라는 단어는 특정 기사에만 나옵니다.

이 단어가 해당 기사의 핵심 키워드입니다. 수식으로 보면 이렇습니다.

TF = 단어가 문서에 등장한 횟수 / 문서의 총 단어 수 IDF = log(전체 문서 수 / 단어가 등장한 문서 수) TF-IDF = TF × IDF IDF에 로그를 취하는 이유는 값의 범위를 조절하기 위해서입니다. 문서가 1만 개인데 한 단어가 1개 문서에만 나오면, 로그 없이는 IDF가 10000이 됩니다.

로그를 취하면 약 4가 됩니다. 위 코드에서 TfidfVectorizer는 이 모든 계산을 자동으로 해줍니다.

scikit-learn에서 제공하는 편리한 도구입니다. 결과로 나오는 행렬의 각 값이 해당 단어의 TF-IDF 점수입니다.

실무에서 TF-IDF는 정말 많이 사용됩니다. 검색 엔진에서 문서 순위를 매길 때, 추천 시스템에서 비슷한 콘텐츠를 찾을 때, 핵심 키워드를 추출할 때 모두 TF-IDF가 기본이 됩니다.

김개발 씨가 코드를 실행하며 결과를 확인했습니다. "아, 문서1에서 '입문'이 높은 점수를 받았네요.

다른 문서에는 없는 단어니까요!" 정확합니다. TF-IDF는 "이 문서만의 특별한 단어"를 찾아줍니다.

모든 문서에 공통으로 나오는 단어는 자연스럽게 낮은 점수를 받습니다.

실전 팁

💡 - TfidfVectorizer의 min_df, max_df 옵션으로 너무 드물거나 흔한 단어를 제외할 수 있습니다

  • 정규화 옵션(norm)을 조절해 문서 길이에 따른 편향을 줄일 수 있습니다
  • TF-IDF는 간단하지만 강력해서 딥러닝 시대에도 여전히 많이 사용됩니다

7. 텍스트 데이터 정제

프로젝트 마무리 단계에서 김개발 씨는 예상치 못한 문제를 마주했습니다. 분석 결과가 이상합니다.

알고 보니 데이터에 중복이 있었고, 빈 문자열도 섞여 있었습니다. "마지막 점검을 소홀히 했네요." 박시니어 씨가 말했습니다.

"데이터 정제는 아무리 강조해도 지나치지 않아요."

텍스트 데이터 정제는 분석의 품질을 좌우하는 핵심 단계입니다. 중복 제거, 빈 문자열 처리, 이상치 탐지, 인코딩 문제 해결 등 다양한 작업이 포함됩니다.

아무리 좋은 모델도 더러운 데이터로는 좋은 결과를 낼 수 없습니다.

다음 코드를 살펴봅시다.

import pandas as pd
import re

def clean_text_data(df, text_column):
    # 원본 복사 (원본 보존)
    df = df.copy()

    # 1. 결측치 제거
    df = df.dropna(subset=[text_column])

    # 2. 빈 문자열 제거
    df = df[df[text_column].str.strip() != '']

    # 3. 중복 제거
    df = df.drop_duplicates(subset=[text_column])

    # 4. 텍스트 정규화 함수
    def normalize(text):
        # 소문자 변환
        text = text.lower()
        # 연속 공백 정리
        text = re.sub(r'\s+', ' ', text)
        # 앞뒤 공백 제거
        return text.strip()

    # 5. 정규화 적용
    df[text_column] = df[text_column].apply(normalize)

    # 6. 너무 짧은 텍스트 제거 (최소 10자)
    df = df[df[text_column].str.len() >= 10]

    return df.reset_index(drop=True)

# 사용 예시
data = {'text': ['좋은 상품입니다!', '  ', '좋은 상품입니다!', None, '별로']}
df = pd.DataFrame(data)
clean_df = clean_text_data(df, 'text')
print(clean_df)  # 정제된 결과: 1행만 남음

데이터 과학 분야에는 유명한 말이 있습니다. "쓰레기를 넣으면 쓰레기가 나온다(Garbage In, Garbage Out)".

아무리 정교한 알고리즘도 더러운 데이터로는 의미 있는 결과를 만들 수 없습니다. 박시니어 씨가 김개발 씨에게 말했습니다.

"NLP 프로젝트에서 실제로 가장 많은 시간이 걸리는 게 뭔지 알아요? 바로 데이터 정제예요.

전체 작업의 70% 이상이 여기에 들어갑니다." 마치 집을 짓기 전에 땅을 고르는 것과 같습니다. 울퉁불퉁한 땅에 집을 지으면 나중에 문제가 생깁니다.

기초 공사를 튼튼히 해야 안전한 집이 완성됩니다. 정제해야 할 문제들을 하나씩 살펴봅시다.

**결측치(Missing Value)**는 데이터가 비어있는 경우입니다. 크롤링 과정에서 오류가 생기거나, 원본 데이터 자체에 누락이 있을 수 있습니다.

pandas의 dropna 함수로 제거할 수 있습니다. 빈 문자열은 결측치와 다릅니다.

데이터가 있긴 한데 공백만 있는 경우입니다. " " 같은 것이죠.

**str.strip()**으로 공백을 제거한 후 빈 문자열인지 확인해야 합니다. 중복 데이터도 큰 문제입니다.

같은 리뷰가 여러 번 수집되면 분석 결과가 왜곡됩니다. 그 리뷰의 의견이 과대 대표되기 때문입니다.

drop_duplicates 함수로 중복을 제거합니다. 텍스트 길이도 체크해야 합니다.

"별로", "좋아요" 같은 너무 짧은 텍스트는 분석에 충분한 정보를 담고 있지 않습니다. 최소 길이를 설정해서 필터링하는 것이 좋습니다.

위 코드의 clean_text_data 함수는 이런 정제 작업을 순차적으로 수행합니다. 중요한 점은 원본을 복사해서 작업한다는 것입니다.

원본 데이터는 항상 보존해두어야 나중에 문제가 생겼을 때 돌아갈 수 있습니다. 인코딩 문제도 자주 마주치는 골칫거리입니다.

한국어 데이터를 다룰 때 "깨진 문자"를 본 적이 있을 것입니다. UTF-8로 저장된 파일을 EUC-KR로 열면 이런 일이 생깁니다.

파일을 열 때 인코딩을 명시하는 습관을 들이세요. 실무에서는 정제 파이프라인을 만들어두는 것이 좋습니다.

새로운 데이터가 들어올 때마다 같은 정제 과정을 거치도록 자동화하는 것이죠. 김개발 씨가 정제된 데이터를 확인하며 말했습니다.

"와, 원본 1000개 중에 800개만 남았네요. 20%가 불량 데이터였다니..." 이것이 현실입니다.

실제 데이터는 생각보다 지저분합니다. 하지만 정제를 잘 하면 적은 데이터로도 좋은 결과를 얻을 수 있습니다.

양보다 질이 중요합니다.

실전 팁

💡 - 정제 전후의 데이터 수를 기록해두면 데이터 품질을 파악하기 좋습니다

  • 어떤 데이터가 제거되었는지 로그를 남기세요
  • 정제 파이프라인을 함수나 클래스로 만들어 재사용하세요

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Python#NLP#TextProcessing#Tokenization#TF-IDF#Python,NLP,TextProcessing

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.