Develop/AI

자연어 처리 요약 정리(2)

YOOZI. 2025. 2. 23. 23:10
728x90
언어를 이해하고 분석하기

 

 

 

오늘은 자연어 처리 요약을 해보자.

오늘의 배움
  • 정규 표현식 & 인코딩
  • 패딩
  • 워드 클라우드
  • FastText

1. 정규 표현식 (Regular Expression)

  • 특정한 규칙을 가진 문자열을 찾기 위한 패턴
  • 정규 표현식을 사용하면 대량의 텍스트 데이터에서 특정 패턴을 효율적으로 추출, 삭제, 대체 가능

 

 

1-1. 정규 표현식 문법 요약

기호(명령어) 설명 예제
. 임의의 한 글자 (개행 문자 제외) a.b → "acb", "a1b"
^ 문자열의 시작 ^abc → "abc로 시작하는"
$ 문자열의 끝 abc$ → "abc로 끝나는"
* 0개 이상 반복 a* → "", "a", "aaa"
+ 1개 이상 반복 a+ → "a", "aaa"
? 0개 또는 1개 a? → "", "a"
{m} 정확히 m개 반복 a{3} → "aaa"
{m,n} m~n번 반복 a{2,4} → "aa", "aaa", "aaaa"
[] 문자 집합 (택1) [abc] → "a", "b", "c"
[^] 부정 문자 집합 [^abc] → "a, b, c 제외"
\d 숫자 (0-9) \d+ → "123", "0"
\D 숫자가 아닌 문자 \D → "a", "!"
\w 문자 + 숫자 + 밑줄 ([a-zA-Z0-9_]) \w+ → "word123"
\W \w에 해당하지 않는 문자 \W → "!", " "
\s 공백 문자 (스페이스, 탭, 개행) \s → " ", "\n", "\t"
\S 공백이 아닌 문자 \S → "a", "1"
` ` OR 연산자
() 그룹화 (서브패턴) (abc) → "abc"
(?P<name>pattern) 그룹에 이름 부여 (?P<year>\d{4})
(?=pattern) 긍정형 전방탐색 (포함 O) \w+(?=\d) → "abc" (abc123)
(?!pattern) 부정형 전방탐색 (포함 X) abc(?!123) → "abc"
(?<=pattern) 긍정형 후방탐색 (포함 O) (?<=@)\w+ → "gmail" (abc@gmail.com)
(?<!pattern) 부정형 후방탐색 (포함 X) (?<!@)\w+

 

 

re 모듈의 주요 함수

함수  설명
re.compile(pattern) 정규 표현식을 컴파일 (재사용 시 성능 향상)
re.match(pattern, str) 문자열의 시작에서 패턴 일치 여부 확인 (없으면 None)
re.search(pattern, str) 문자열 전체에서 패턴 일치하는 첫 번째 항목 반환
re.findall(pattern, str) 패턴과 일치하는 모든 항목을 리스트로 반환
re.finditer(pattern, str) 패턴과 일치하는 모든 항목을 이터레이터(객체)로 반환
re.sub(pattern, repl, str) 패턴과 일치하는 항목을 repl로 치환
re.split(pattern, str) 패턴을 기준으로 문자열 분할 (리스트 반환)

 

 

re 객체의 주요 메서드

re.compile()로 만든 컴파일 객체에서 사용 가능한 메서드들입니다.

메서드 설명
pattern.match(str) 문자열 시작에서 패턴 일치 여부 확인 (None 반환 가능)
pattern.search(str) 문자열 전체에서 패턴 찾기 (처음 일치하는 항목 반환)
pattern.findall(str) 일치하는 모든 항목 리스트 반환
pattern.finditer(str) 일치하는 모든 항목 이터레이터 객체로 반환
pattern.sub(repl, str) 패턴과 일치하는 항목을 repl로 치환
pattern.split(str) 패턴 기준으로 문자열 분할 (리스트로 반환)

 

정규 표현식 예제

import re

# 1. 문자열에서 이메일 주소 추출
text = "Contact us at support@example.com or info@test.com"
emails = re.findall(r'\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\b', text)
print(emails)
# 출력: ['support@example.com', 'info@test.com']

# 2. 전화번호 포맷 변환
text = "My number is 010-1234-5678"
new_text = re.sub(r'(\d{3})-(\d{4})-(\d{4})', r'(\1) \2-\3', text)
print(new_text)
# 출력: My number is (010) 1234-5678

# 3. 특정 패턴으로 문자열 분리
data = "apple, orange; banana|grape"
fruits = re.split(r'[;,\|]', data)
print(fruits)
# 출력: ['apple', ' orange', ' banana', 'grape']

 

 


1-2. 정규 표현식을 활용한 토큰화

  • RegexpTokenizer: nltk의 RegexpTokenizer는 특정 정규 표현식을 기반으로 텍스트를 토큰화
from nltk.tokenize import RegexpTokenizer

# 영어와 숫자로 이루어진 단어 추출
tokenizer = RegexpTokenizer('[a-zA-Z0-9_]+')
text = "Hello, I'm learning NLP with Python 3.9!"
tokens = tokenizer.tokenize(text)
print(tokens)
# 출력: ['Hello', 'I', 'm', 'learning', 'NLP', 'with', 'Python', '3', '9']

2. 정수 인코딩 (Integer Encoding)

  • 정의: 텍스트 데이터를 숫자로 변환하는 과정
  • 작동 과정:
    • 텍스트 데이터 수집
    • 토큰화(Tokenization): 문장을 단어(토큰)로 분리
    • 단어 사전(Vocabulary) 생성: 고유한 단어에 인덱스 부여
    • 정수로 변환(Integer Encoding): 각 단어를 해당 정수로 매핑
  • 한계:
    • 순서 기반 정보 손실
    • 희소성 문제 (단어 수 ↑, 희소 행렬 형태로 표현되므로 메모리 사용량 ↑)
    • Out-of-Vocabulary(OOV): 새로운 단어 처리 필요.
  • 해결: 
    • Word Embedding: 정수 인코딩된 데이터를 밀집 벡터(Dense Vector)로 변환.
    • 서브워드 기반 모델: BPE, WordPiece(BERT에서 사용) 적용.
from nltk.tokenize import sent_tokenize, word_tokenize
from nltk.corpus import stopwords

# 문장 토큰화
sentences = sent_tokenize(raw_text)

# 영문 불용어 리스트
en_stopwords = stopwords.words('english')

# 단어사전
vocab = {}

# 토큰화/정제/정규화 처리 결과
preprocessed_sentences = []

for sentence in sentences:
    sentence = sentence.lower()    # 대소문자 정규화 (소문자 변환)
    tokens = word_tokenize(sentence)    # 토큰화
    tokens = [token for token in tokens if token not in en_stopwords]    # 불용어 제거
    tokens = [token for token in tokens if len(token) > 2]    # 단어 길이가 2 이하면 제거

    for token in tokens:
        if token not in vocab:
            vocab[token] = 1
        else:
            vocab[token] += 1
    
    preprocessed_sentences.append(tokens)

2-1. OOV (Out-Of-Vocabulary)

  • 단어 사전에 없는 단어
  • 처리 방법:
    • OOV 토큰 사용: Tokenizer의 oov_token 인자로 미등록 단어를 특정 토큰으로 변환
    • 미등록 단어 무시: 사전에 없는 단어를 제거
    • oov_token="<OOV>"을 지정하면, 사전에 없는 단어는 <OOV>에 해당하는 정수(여기서는 1)로 인코딩됨.
    • OOV 처리를 하지 않으면 미등록 단어는 무시되므로 주의가 필요함.
    • => 미등록 단어는 <OOV>로 변환
from tensorflow.keras.preprocessing.text import Tokenizer

# 입력 데이터
texts = ["나는 사과를 좋아해", "나는 바나나를 좋아해"]
new_texts = ["나는 딸기를 좋아해", "사과는 맛있어"]

# OOV 처리를 위한 Tokenizer 생성
tokenizer = Tokenizer(oov_token="<OOV>")
tokenizer.fit_on_texts(texts)

# 단어 사전 확인
print(tokenizer.word_index)
# 출력: {'<OOV>': 1, '나는': 2, '좋아해': 3, '사과를': 4, '바나나를': 5}

# 새로운 데이터 정수 인코딩
encoded_new_texts = tokenizer.texts_to_sequences(new_texts)
print(encoded_new_texts)
# 출력: [[2, 1, 3], [1, 1]]

2-2. 정수 인코딩 주요 메서드 (Keras Tokenizer)

메서드 설명
Tokenizer() 토크나이저 객체 생성
fit_on_texts(texts) 텍스트 학습 및 단어 사전 생성
texts_to_sequences(texts) 텍스트를 정수 시퀀스로 변환
sequences_to_texts(sequences) 정수 시퀀스를 텍스트로 변환
word_index 생성된 단어 사전(딕셔너리 형태) 조회
word_counts 각 단어의 등장 횟수 반환
num_words 상위 N개의 단어만 인코딩
oov_token 미등록 단어 처리 시 사용할 OOV 토큰 지정

3. 패딩(padding)

  • 정수 인코딩 후, 딥러닝 모델에 입력할 수 있도록 시퀀스의 길이를 맞추는 작업
  • 장점:
    1. 일관된 입력 형식
    2. 병렬 연산 최적화
    3. 유연한 데이터 처리
from tensorflow.keras.preprocessing.sequence import pad_sequences

# 데이터 준비
texts = ["나는 사과를 좋아해", "사과와 바나나 모두 좋아해"]
tokenizer = Tokenizer()
tokenizer.fit_on_texts(texts)
sequences = tokenizer.texts_to_sequences(texts)

# 패딩 적용 (길이 맞추기)
padded_sequences = pad_sequences(sequences, padding='post')
print(padded_sequences)
# 출력: [[1 2 3 0], [4 5 6 3]]

pad_sequences 주요 옵션

옵션 설명
maxlen 패딩 후 시퀀스의 최대 길이 설정
padding 'pre' (앞에 패딩) 또는 'post' (뒤에 패딩)
truncating 길이 초과 시 'pre' (앞) 또는 'post' (뒤) 제거

 

3-1. 원-핫 인코딩

 

왜 패딩에서 원-핫 인코딩이 필요할까?

원-핫 인코딩이 필요한 이유는 주로 모델의 입력 형식 때문이다. 특정 모델에서는 정수 인코딩만 사용해도 괜찮지만, 일부 모델에서는 원-핫 인코딩이 필수이기 때문이다.

  • 패딩: 시퀀스 길이를 맞춰 모델 입력 형식을 통일.
  • 원-핫 인코딩: 정수 인코딩의 서열 관계 문제를 피하기 위해 필요.
  • 필요 여부는 사용하는 모델 구조 레이어에 따라 다름.
    • Embedding 레이어 → 원-핫 인코딩 불필요
    • Dense 레이어 → 원-핫 인코딩 필요

 

3-1-1. 원-핫 인코딩이 필요한 경우

  1. 기본 신경망(MLP, Dense Layer 사용)
    • 밀집 신경망(Dense Layer)은 숫자 크기에 의미를 두기 때문에, 정수 인코딩만 사용하면 모델이 순위나 크기 정보로 잘못 이해할 수 있음.
    • 따라서, 원-핫 인코딩으로 순서 정보를 없애고 각 단어를 독립적으로 표현해야 함.
    from tensorflow.keras.utils import to_categorical
    import numpy as np
    
    # 정수 인코딩된 데이터
    encoded = [1, 2, 3, 4]
    
    # 원-핫 인코딩 수행
    one_hot = to_categorical(encoded, num_classes=5)
    print(one_hot)
    # 출력:
    # [[0. 1. 0. 0. 0.]
    #  [0. 0. 1. 0. 0.]
    #  [0. 0. 0. 1. 0.]
    #  [0. 0. 0. 0. 1.]]
    
  2. 다중 클래스 분류 문제 (Multi-class Classification)
    • 출력층에서 클래스를 구분해야 할 때는 원-핫 인코딩이 필수.
    • 정수 값만 사용하면 모델이 특정 숫자 간의 서열 관계를 잘못 인식할 수 있기 때문.

 

3-1-2. 원-핫 인코딩이 필요하지 않은 경우

  1. 임베딩 레이어(Embedding Layer) 사용
    • Keras의 Embedding 레이어는 정수 인코딩된 입력을 받아들이므로, 별도의 원-핫 인코딩이 필요 없음.
    from tensorflow.keras.layers import Embedding
    from tensorflow.keras.models import Sequential
    
    model = Sequential()
    model.add(Embedding(input_dim=1000, output_dim=64, input_length=10))
    
  2. 순환 신경망(RNN, LSTM, GRU)
    • 이들 모델도 Embedding 레이어를 사용하는 경우가 많아 원-핫 인코딩을 생략할 수 있음.

4. 워드 클라우드 (word cloud)

  • 워드 클라우드:  자연어 처리에서 중요한 키워드를 시각화하는 도구로, 데이터 탐색과 노이즈 확인, 트렌드 파악에 유용

 

4-1. 코드 설명

  • WordCloud() : 워드 클라우드 객체 생성
    • font_path : 한글 사용 시 폰트 경로 지정 (미설정 시 한글 깨짐)
    • width, height : 워드 클라우드 이미지 크기
    • background_color : 배경색 (흰색 추천: 'white')
    • max_words : 표시할 최대 단어 수
    • colormap : 색상 팔레트 (예: 'viridis', 'plasma', 'inferno', 'magma' 등)
  • generate() : 입력된 텍스트 기반으로 워드 클라우드 생성
  • plt.imshow() : 이미지 출력
  • plt.axis('off') : x, y축 제거

 

4-2. 자주 사용하는 메서드와 변수

메서드/변수 설명
generate(text) 텍스트로부터 워드 클라우드 생성
to_file('path') 워드 클라우드를 이미지로 저장
stopwords 제외할 단어 목록 설정
max_font_size 최대 글씨 크기 설정
contour_color 외곽선 색상 지정
collocations 연속된 단어 조합 사용 여부 (기본: True)

 

4-3. 불용어 제거 예시

from wordcloud import WordCloud, STOPWORDS

text = """
파이썬은 데이터 분석, 머신러닝, 자연어 처리에 널리 사용되는 프로그래밍 언어입니다.
자연어 처리는 인공지능 분야에서 중요한 역할을 합니다.
"""

# 불용어 설정
custom_stopwords = set(STOPWORDS)  # 기본 불용어
custom_stopwords.update(['자연어', '처리'])  # 사용자 정의 불용어 추가

# 워드 클라우드 생성
wordcloud = WordCloud(
    font_path='malgun.ttf',
    stopwords=custom_stopwords,
    background_color='white'
).generate(text)

plt.imshow(wordcloud, interpolation='bilinear')
plt.axis('off')
plt.show()


5.  FastText

  • 텍스트 분류 및 단어 임베딩을 위한 라이브러리.
  • 희귀 단어다국어 데이터에서 강력한 성능을 발휘

주요 메서드

메서드 설명
train_unsupervised() 비지도 학습으로 단어 임베딩 모델 생성
train_supervised() 지도 학습으로 텍스트 분류 모델 생성
load_model() 저장된 모델 로드
get_word_vector() 단어의 임베딩 벡터 반환
get_sentence_vector() 문장의 임베딩 벡터 반환
predict() 입력 데이터의 분류 예측
save_model() 학습한 모델 저장

주요 변수

매개변수 설명
model 'skipgram' 또는 'cbow' 선택
dim 벡터 차원 수 (기본값: 100)
epoch 학습 반복 수 (기본값: 5)
minCount 최소 등장 횟수 (기본값: 5)
wordNgrams 사용할 n-gram의 최대 길이 (기본값: 1)
lr 학습률 (기본값: 0.1)
loss 손실 함수 ('softmax', 'hs', 'ns' 지원)

 

FastText와 다른 임베딩 비교

특징 Word2Vec FastText
학습 방식 단어 단위 문자 n-gram 사용
신조어/오타 대응 불가능 가능
학습 속도 빠름 더 빠름
분류 지원 지원 안함 기본 지원

 

728x90