본문 바로가기
➕ Data Science/▹ ML

1. 텍스트 분석 기초

by Ardor924 2025. 5. 23.

텍스트 분석 기초

🔶 텍스트 마이닝(=자연어처리) (Natural language processing)
◻ 개념 :

  • 사람이 사용하는 일상의 말이나 언어의 의미르 분석해서 컴퓨터가 처리할수록 하는 작업\
  • 텍스트에서 컴퓨터가 이해 할 수 있는 특성으로 추출하는 작업

🔶자연어 처리과정
![[Screenshot_407.png]]

◻ 0. 전처리

  • 오류수정, 결측치처리 등등 (자세한건 아래에서 확인)
    ◻ 1. 토큰화
  • 큰 문장을 작은 문장 또는 단어로 분리하는 작업
  • 문장 분할 및 형태소 분류
    ◻ 2. 인코딩
  • AI모델이 숫자를 기반으로 하기때문에 문자 데이터를 수치형으로 변환하는 작업
  • 모델이 이해할수있게 문자를 숫자로 변환
    ◻ 3. 임베딩
  • 단어간의 관계(상관성)를 분석해서 컴퓨터가 중요도를 판단하여 이해할수 있게 단어사전으로 만드는작업
  • 의미를 부여하여 단어사전 생성

🔶0. 텍스트 전처리 작업
◻ 오류수정(정제 : cleaning)
◻ 결측치처리

  • 삭제 혹은 부정표현으로 채우기

◻ 정규화

  • 정규식 사용해서 필요한 내용만 추출
  • 예) 한글분류시 영문,숫자등을 제거

◻ 어간 추출

![[Screenshot_405 1.png]]

  • 단어에서 중요한 부분만 추출 (일반적으로 앞쪽에 위치)
  • 예 ) 만들었어요,만들고,만들다,만듦 ----> 만들다

◻ 표제어 추출

  • 대표 단어를 추출
  • 예 ) 먹었어요,드셨어요,식사했어요,맛을봤어요 -> 먹다

◻ 불용어 (stopwords)

  • 학습에 사용하지 않을 단어

◻ 텍스트 증식(증강)

  • 텍스트데이터가 적은 경우 데이터의 수를 늘리는 작업
    • 단어 삭제
      • 예) 나는 학교에 갑니다 -> 학교에 갑니다
    • 단어 교환
      • 예) 나는 학교에 갑니다 -> 학교에 나는 갑니다
    • 단어 추가
      • 예) 나는 학교에 갑니다 -> 나는 버스로 학교에 갑니다
    • 유사단어로 변경
      • 예) 나는 학교에 갑니다 -> 나는 교실에 갑니다
    • 번역기 사용후 재번역
      • 예) 나는 학교에 갑니다 -> 我去学校 -> 저는 학교에 가요

🔶1. 토큰화 처리과정
![[Screenshot_408.png]]

◻ 개념 : 문장(corpus)를 작은문장(chunk)이나 단어(token)로 분리하는 작업

◻ 영문 VS 한글 토큰화 차이
영문

  • 빈공백으로 분리(띄어쓰기가 잘 진행되기 때문)
    한글
  • 토큰화가 어렵다
    • 띄어쓰기가 잘 안되서 토큰화가 진행되기 어렵다.
    • 꾸며주는 특성을 갖는 형용사/부사적 표현이 많다.
    • 의태어/의성어 문제 (보글보글,지글지글 등)표현이 많다.
    • 따라서 토큰화 대신 형태소 분리를 사용

◻ 형태소분리
◽ 형태소 분리 종류 : Kkma, Hanaum, Twitter,Okt

예시

text1 = "I am actively looking for Ph.D. students. and you are a Ph.D. student."
text2 = "나는 버스를 타고 학교에 아침 일찍 갔습니다."
print(word_tokenize(text1))
print(word_tokenize(text2))

결과

['I', 'am', 'actively', 'looking', 'for', 'Ph.D.', 'students', '.', 'and', 'you', 'are', 'a', 'Ph.D.', 'student', '.']
['나는', '버스를', '타고', '학교에', '아침', '일찍', '갔습니다', '.']

◽ pos 사용하여 단어형태 분석
예시

okt.pos(text2)

결과

[('나', 'Noun'),
('는', 'Josa'),
('버스', 'Noun'),
('를', 'Josa'),
('타고', 'Noun'),
('학교', 'Noun'),
('에', 'Josa'),
('아침', 'Noun'),
('일찍', 'Noun'),
('갔습니다', 'Verb'),
('.', 'Punctuation')]

◻ 정규화
◽ 개념 : 정규식을 이용해서 필요한 데이터만 따로 추출하는 작업

예시

corpus = "소크라테스가 말했습니다. '너 자신을 알라' ==> 무슨 의미 일까요? Now is 11 hour 35 minute. "
result = re.compile("[^가-힣]")
print(result.sub('',corpus))

결과

소크라테스가말했습니다너자신을알라무슨의미일까요

해설

  • ^ : not 의 의미
  • 가-힣 : 한글전체
  • ㄱ-ㅎ : 한글자음
  • ㅏ-ㅣ : 한글모음
  • A-Z : 영문 대문자
  • a-z : 영문 소문자
  • 0-9 : 숫자

◻ 표제어 추출
◽ 개념

  • 대표단어 추출
  • 해당 문장의 원형에 해당 단어를 추출

예시

#==================================
# 표제어 추출
#==================================
lemmatizer = WordNetLemmatizer()
word = ['leaves','lives','dies','has','children']
print([lemmatizer.lemmatize(w) for w in word])

결과

['leaf', 'life', 'dy', 'ha', 'child']

◻ 어간추출
◽ 개념 : 단어를 앞에서 잘라내서 추출
예시

#==================================
# 어간 추출
#==================================
s = PorterStemmer()
print([s.stem(w) for w in word])

결과

['leav', 'live', 'die', 'ha', 'children']

◻ 불용어
◽ 개념 : 학습에 사용하지 않을 단어를 미리 지정해서 필터링후 추출
예시

#==================================
# 불용어 필터링
#==================================
corpus = '고기를 아무렇게나 구울려고 하면 안 돼. 고기라고 다 같은게 아니거든. 예컨데 삼겹살을 구울때 중요한 게 있지.'
result = []
# 불용어 목록
stop_words = ['은','는','이','가','을','를','하면','돼',',','.','라고','다','게','예컨데','\n']
# 형태소분리
result = okt.morphs(corpus,stem=True)
print(result)
# 불용어처리
result = [w for w in result if w not in stop_words]
print(result)

결과

['고기', '를', '아무렇다', '구울', '려고', '하다', '안', '돼다', '.', '고기', '라고', '다', '같다', '아니다', '.', '예컨데', '삼겹살', '을', '구울', '때', '중요하다', '게', '있다', '.']
['고기', '아무렇다', '구울', '려고', '하다', '안', '돼다', '고기', '같다', '아니다', '삼겹살', '구울', '때', '중요하다', '있다']

🔶2. 인코딩 처리과정
![[Screenshot_409.png]]

◻ 개념 : 학습을 위해 문자 데이터를 숫자 데이터로 변환하는 작업

◻ Tokenizer()
◽ 빈도수 기반 분석
◽ 빈도수 순으로 내림차순 정렬

  • 빈도수가 동일하면 등장순 으로 정렬
    ◽ 정렬순으로 1부터 인덱스 부여
    ◽ 문자 토큰을 해당 인덱스로 변환

예시

# 토큰갯수 제한
tokenizer = Tokenizer(num_words=10)
# 빈도분석
tokenizer.fit_on_texts(result)
print(tokenizer.word_index)
print(tokenizer.word_counts)
# 인코딩
print(tokenizer.texts_to_sequences([result]))
# 패딩 길이를 5로 설정
result = pad_sequences(en, maxlen=5, truncating='pre')
print([result])

◽설명
num_words : 사용할 인덱스 의 개수
word_index : 인덱스분석
word_counts : 사용된 횟수 분석
texts_to_sequences : 토크나이징 결과 출력
pad_sequences : 훈련전 문장들의 길이를 맞추기 위해 임의로 0값을 집어넣는방식
![[Screenshot_410.png]]

결과

[[1, 3, 2, 4, 5, 6, 7, 1, 8, 9, 2]]
[array([[7, 1, 8, 9, 2]], dtype=int32)]

◽ BoW (Back of Word)

![[Screenshot_412.png]]

  • 단어의순서를고려하지않고, 빈도수만 이용해서 텍스트를 수치화 하는 방법
  • CountVectorizer와 TFI-DIF가 해당

◻ CountVectorizer()
◽ 빈도수기반

  • 각 토큰별로 빈도수를 분석
  • 각 토큰별로 빈도수의 수치로할당
    ◽ 원-핫 인코딩방식 (토큰의 수가 많아지면 크기가 커짐)
  • 같은길이로 만듦 -> 패딩 필요 없음
    ◽ 토큰을 사전순으로 오름차순정렬
    ◽ 정렬된 순으로 인덱스를 0부터 부여

예시

# countVectorizer
from sklearn.feature_extraction.text import CountVectorizer
okt = Okt()
cv = CountVectorizer()
cv_fit = cv.fit_transform([corpus])
print(cv_fit.toarray())
print(cv.vocabulary_)

결과

[[1 1 1 1 1 1 1 1 1 1 1 1]]
{'고기를': 2, '아무렇게나': 7, '구울려고': 4, '하면': 11, '고기라고': 1, '같은게': 0, '아니거든': 6, '예컨데': 8, '삼겹살을': 5, '구울때': 3, '중요한': 10, '있지': 9}

◻ TFI-DIF Vectorizer()
◽특성 : 실수(float) 인코딩
![[Screenshot_385.png]]

◽ TF (Text Frequency)

  • 토큰의 빈도수
    ◽ DF (Document Frequency)
  • 토큰이 등장하는 문장의 수
    ◽ IDF (Inverse DF)
  • 문장에 자주 등장하는 토큰은 문장 구분시 중요하지 않다.
  • 예시) 을,를,이,가,은,는,에게,으로......
    ◽ N
  • 확률(평균)을 구하기 위해 전체갯수로 나눠주기 위한것
    ◽ log
  • 비선형방식을 선형방식으로 바꾸기위해 로그를 취함
  • 로그->지수 변환 ->선형 | 지수->로그 변환 ->선형
  • 빈도수가 선형특성을 갖기때문에 토큰문장구할때도 선형방식으로 변환할필요가있음
  • 토큰이 문장에 들어가는 분포를 보면 많이 들어가는 토큰과 그렇지 않는 토큰이 지수의 특성을 지니기 때문에 로그변환으로 선형식으로 바꿔줌

🔶훈련함수
◻ fit() :분석만 수행
◻ fit_transform() : 분석하고 인코딩을 동시에 수행
◻ transform : fit()이나 fit_transform으로 이전에 분석된 결과를 기반으로 인코딩만 수행

🔶3. 임베딩(Embedding)
![[Screenshot_411.png]]

◻개념

  • 인코딩된 토큰에 의미를 부여하는 작업
  • 단어들 간의 유사성이나 선 후 관계 등을 분석해서 벡터 값(크기,방향) 을 계산하는 작업

◻특성
![[Screenshot_413.png]]

  • 거리적특성
  • 방향적특성

◻ 맵핑예시

 

◻ 계산
![[Screenshot_415.png]]

 

◻ 종류

  • 단어 임베딩
    • Word2Vec
      • 단어들의 지역적 정보를 반영
    • GroVe
      • 단어들의 전역적 정보를 반영
    • FastText
      • 내부 단어를 고려
  • 문장 임베딩
    • Doc2Vec
      • 문장을 벡터로 변환 (%RAG)

🔶 FastText
◻ 파라미터
◽ sentences

  • 토큰 데이터
    ◽ vector_size
  • 벡터의 차원수
    ◽ window
  • 참고할 근처의 단어수
    ◽ min_count
  • 빈도수가 1 이하인 단어는 포함하지 않게 설정
    ◽ workers
  • 사용할 CPU스레드수
    ◽ sg
  • 학습알고리즘(0 : CBOW, 1: Skip-grow)
    • CBOW
      • 여러개의 단어에서 유사한것을 찾아내는 방식
    • Skip-grow
      • 하나의단어로 유사한것을 찾아내는 방식
        ![[Screenshot_386.png]]

실습

데이터

corpus = ["제품을 잘 쓰고 쓰고 있어요",
​​​​​​​​​​"제품의 디자인이 우수해요",
​​​​​​​​​​"성능이 우수해요",
​​​​​​​​​​"제품에 손상이 있어요",
​​​​​​​​​​"제품 가격이 비싸요",
​​​​​​​​​​"정말 필요한 제품입니다",
​​​​​​​​​​"가격이 비싸고 서비스도 엉망이예요",
​​​​​​​​​​"가격대비 성능이 우수해요",
​​​​​​​​​​"디자인이 좋아요",
​​​​​​​​​​"필요없는 기능이 많은듯 해요",
​​​​​​​​​​"서비스 대응이 나빠요",
​​​​​​​​​​"제품에 손상이 심해요"]
labels = [1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0]

훈련

import numpy as np
import gensim
from gensim.models import FastText
from konlpy.tag import Okt
from sklearn.linear_model import LogisticRegression
def get_sentence_vector(tokens):
​​# 하나의 문장(토큰 리스트)을 받아서, 해당 문장의 2차원 벡터 표현을 생성
​​vectors = [fasttext_model.wv[word] for word in tokens if word in fasttext_model.wv]
​​# 만약 문장에 있는 단어가 하나도 모델에 없다면, 0 벡터로 처리
​​# 있다면 단어 벡터들의 평균을 구해서 문장 전체의 벡터로 사용
​​return np.mean(vectors, axis=0) if vectors else np.zeros(fasttext_model.vector_size)
# 토큰화
okt = Okt()
token_texts = [okt.morphs(text) for text in corpus]
# 임베딩
fasttext_model = FastText(sentences=token_texts,
​​​​​​​​​​​​​​​​​​​​​​​​vector_size=100,
​​​​​​​​​​​​​​​​​​​​​​​​window=5,
​​​​​​​​​​​​​​​​​​​​​​​​min_count=2,
​​​​​​​​​​​​​​​​​​​​​​​​workers=4,
​​​​​​​​​​​​​​​​​​​​​​​​sg=1)
fasttext_model.wv.most_similar("좋아요")
# 훈련준비
X = np.array([get_sentence_vector(tokens) for tokens in token_texts])
y = np.array(labels)
print(X)
# 훈련
model = LogisticRegression(C=0.01)
model.fit(X,y)
score = model.score(X,y)
print(f'score : {score*100:.2f}')

결과 100.00

예측

# 예측샘플 corpus 선정
X_new1 = ["제품을 안 쓰고 있어요"]
X_new2 = ["에라이!! 같네! "]
# 토큰화
t1 = okt.morphs(X_new1[0])
t2 = okt.morphs(X_new2[0])
# 임베딩
en_new1 = get_sentence_vector(t1)
en_new2 = get_sentence_vector(t2)
#예측
pred1 = model.predict([en_new1])
pred2 = model.predict([en_new2])
print(pred1,pred2)

결과 [1][0]

'➕ Data Science > ▹ ML' 카테고리의 다른 글

3. 추천시스템 기초  (4) 2025.06.04
2. IMDB 영화리뷰 데이터 분류  (2) 2025.06.02
9. 보스턴 주택가격 예측  (1) 2025.05.19
8. 선형분류  (1) 2025.05.15
7. 보스턴주택가격예측  (0) 2025.05.15