Notice
Recent Posts
Recent Comments
Link
- Today
- Total
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
Tags
- 빅쿼리
- 회고록
- 깃허브
- error
- github
- 데이터사이언티스트
- 데이터베이스
- 머신러닝
- 딥러닝
- python
- 변수
- 2주차
- bigquery
- 1주차
- ML
- 딕셔너리
- 주피터노트북
- AI
- 데이터
- 프로젝트
- 회고
- data
- 함수
- 파이썬
- 개념정리
- 데이터사이언스
- 파이썬문법
- sql
- 모두의연구소
- Jupyter Notebook
Archives
[딥러닝] 텍스트의 분포로 벡터화 하기(BoW, DTM&코사인 유사도, TF-IDF, LSA&LDA, soynlp) 본문
Deep Learning
[딥러닝] 텍스트의 분포로 벡터화 하기(BoW, DTM&코사인 유사도, TF-IDF, LSA&LDA, soynlp)
jpocket 2025. 6. 16. 17:43반응형
머신러닝 모델이 텍스트를 이해하고 잘 분석하기 위해서, 전처리 과정에서 텍스트를 숫자 벡터로 변환하는 벡터화 과정을 거친다.
벡터화 방법으로는
1. 통계와 머신 러닝을 활용한 방법
2. 인공 신경망을 활용하는 방법
두 가지로 나눌 수 있다.
이 글에서는 1번에 대한 내용을 담고 있다.
1. 🛠 Bag of Words (BoW)
- 개념: 문서 내 단어들의 등장 횟수를 기반으로 문서를 표현하는 매우 간단한 방법.
- 단어 가방: 단어들의 순서나 문법적 구조는 무시하고, 단순히 단어의 유무 및 빈도만 고려.
- 등장 횟수 기록: 각 단어가 문서에 나타난 횟수를 기록 ({"movies": 2}).
- 단어장(Vocabulary): 중복을 제거한 모든 단어들의 집합.
- 활용 도구:
1) Keras Tokenizer: 단어와 빈도수를 딕셔너리 형태로 반환.
from tensorflow.keras.preprocessing.text import Tokenizer
sentence = ["John likes to watch movies. Mary likes movies too! Mary also likes to watch football games."]
tokenizer = Tokenizer()
tokenizer.fit_on_texts(sentence) # 단어장 생성
bow = dict(tokenizer.word_counts) # 각 단어와 각 단어의 빈도를 bow에 저장
print("Bag of Words :", bow) # bow 출력
print('단어장(Vocabulary)의 크기 :', len(tokenizer.word_counts)) # 중복을 제거한 단어들의 개수
2) scikit-learn CountVectorizer: 단어 인덱스 기반의 벡터 형태로 반환 (단어장 매핑 제공).
from sklearn.feature_extraction.text import CountVectorizer
sentence = ["John likes to watch movies. Mary likes movies too! Mary also likes to watch football games."]
vector = CountVectorizer()
bow = vector.fit_transform(sentence).toarray()
print('Bag of Words : ', bow) # 코퍼스로부터 각 단어의 빈도수를 기록한다.
print('각 단어의 인덱스 :', vector.vocabulary_) # 각 단어의 인덱스가 어떻게 부여되었는지를 보여준다.
- Keras Tokenizer는 딥러닝 모델의 임베딩 레이어와 함께 사용될 때 강력하며, 텍스트를 정수 시퀀스로 변환하는 데 중점을 둔다.
토큰화와 인덱싱에 초점을 맞추고, 그 외의 전처리는 비교적 간단하다. - scikit-learn CountVectorizer는 BoW 표현 자체를 생성하고, 더 많은 전처리 및 특성 추출 옵션을 내장하고 있어 다양한 전통적인 머신러닝 모델에 바로 적용하기 편리하다.
출력 형태도 희소 행렬로 효율적이다.
🔥요약하자면,
👉 Keras Tokenizer는 딥러닝 모델, scikit-learn CountVectorizer는 머신러닝 모델에 적용하기 좋다.🚀
하나의 문장에 대해 그 문장의 BoW를 만드는 과정을 보았다면, DTM은 여러 문서가 포함된 대규모 텍스트 데이터셋을 처리하는 방식을 보여주는 데 초점이 있다.
2. 🛠 문서-단어 행렬 (DTM: Document-Term Matrix) & 코사인 유사도
- DTM 개념: 여러 문서의 BoW를 하나의 행렬로 결합한 것. <-> TDM 단어-문서 행렬
- 행: 각 문서.
- 열: 각 단어 (단어장의 단어들).
- 값: 문서 내 특정 단어의 빈도.
- 역할: 문서와 단어 간의 관계를 수치적으로 표현.
- 코사인 유사도: DTM 내 각 문서 벡터 간의 유사도 측정에 활용.
- 측정 방식: 두 벡터의 코사인 값 (방향 유사도) 계산.
- 활용: 문서 간의 의미적 유사성 파악.
문서1 : I like dog
문서2 : I like cat
문서3 : I like cat I like cat
import numpy as np
from numpy import dot
from numpy.linalg import norm
doc1 = np.array([0,1,1,1]) # 문서1 벡터
doc2 = np.array([1,0,1,1]) # 문서2 벡터
doc3 = np.array([2,0,2,2]) # 문서3 벡터
def cos_sim(A, B):
return dot(A, B)/(norm(A)*norm(B))
print('{:.2f}'.format(cos_sim(doc1, doc2))) #문서1과 문서2의 코사인 유사도
print('{:.2f}'.format(cos_sim(doc1, doc3))) #문서1과 문서3의 코사인 유사도
print('{:.2f}'.format(cos_sim(doc2, doc3))) #문서2과 문서3의 코사인 유사도
# 0.67
# 0.67
# 1.00
scikit-learn CountVectorizer 활용
from sklearn.feature_extraction.text import CountVectorizer
corpus = [
'John likes to watch movies',
'Mary likes movies too',
'Mary also likes to watch football games',
]
vector = CountVectorizer()
print(vector.fit_transform(corpus).toarray()) # 코퍼스로부터 각 단어의 빈도수를 기록.
print(vector.vocabulary_) # 각 단어의 인덱스가 어떻게 부여되었는지를 보여준다.
[[0 0 0 1 1 0 1 1 0 1]
[0 0 0 0 1 1 1 0 1 0]
[1 1 1 0 1 1 0 1 0 1]]
{'john': 3, 'likes': 4, 'to': 7, 'watch': 9, 'movies': 6, 'mary': 5, 'too': 8, 'also': 0, 'football': 1, 'games': 2}
DTM의 한계점:
- 희소성(Sparsity): 문서와 단어 수가 증가할수록 행렬 대부분이 0으로 채워짐 (메모리 및 계산 효율성 문제).
- 단순 빈도 기반: 단어의 등장 횟수에만 집중하여, 단어의 실제 중요도를 반영하지 못함.
❓그렇다면 중요한 단어와 중요하지 않은 단어에 가중치를 따로 선별해서 주는 방법은 없을까?
3. 🛠 TF-IDF (Term Frequency-Inverse Document Frequency)
- 개념: DTM의 한계를 극복하고 각 단어의 중요도를 판단하여 가중치를 부여하는 방법.
- 핵심: 모든 문서에서 자주 나타나는 단어는 중요도가 낮고, 특정 문서에서만 자주 나타나는 단어는 중요도가 높다고 판단.
- 구성 요소:
def tf(t, d): # 단어 빈도
return d.count(t)
def idf(t): # 역문서 빈도
df = 0
for doc in docs:
df += t in doc
return log(N/(df + 1)) + 1
def tfidf(t, d): # 최종 TF-IDF
return tf(t,d)* idf(t)
TF (Term Frequency): 특정 문서 내 단어의 등장 빈도.
result = []
for i in range(N): # 각 문서에 대해서 아래 명령을 수행
result.append([])
d = docs[i]
for j in range(len(vocab)):
t = vocab[j]
result[-1].append(tf(t, d))
tf_ = pd.DataFrame(result, columns = vocab) # 각 문서 내에서 단어의 빈도수 계산하여 DTM 형태 생성
tf_
IDF (Inverse Document Frequency): 전체 코퍼스에서 단어가 얼마나 희귀하게 등장하는지 나타내는 지표. (자주 등장하는 단어일수록 IDF 값 낮음).
result = []
for j in range(len(vocab)):
t = vocab[j]
result.append(idf(t))
idf_ = pd.DataFrame(result, index = vocab, columns=["IDF"]) # 각 단어의 희귀도를 나타내는 IDF 계산
idf_
TF-IDF = TF IDF: 단어의 문서 내 빈도와 전체 문서에서의 희귀도를 종합하여 중요도 점수 산출.
result = []
for i in range(N):
result.append([])
d = docs[i]
for j in range(len(vocab)):
t = vocab[j]
result[-1].append(tfidf(t,d))
tfidf_ = pd.DataFrame(result, columns = vocab)
tfidf_
scikit-learn TFidVectorizer 활용
from sklearn.feature_extraction.text import TfidfVectorizer
corpus = [
'John likes to watch movies and Mary likes movies too',
'James likes to watch TV',
'Mary also likes to watch football games',
]
tfidfv = TfidfVectorizer().fit(corpus)
vocab = list(tfidfv.vocabulary_.keys()) # 단어장을 리스트로 저장
vocab.sort() # 단어장을 알파벳 순으로 정렬
# TF-IDF 행렬에 단어장을 데이터프레임의 열로 지정하여 데이터프레임 생성
tfidf_ = pd.DataFrame(tfidfv.transform(corpus).toarray(), columns = vocab)
tfidf_
4. 🛠 LSA (Latent Semantic Analysis) & LDA (Latent Dirichlet Allocation)
- 도입 배경: DTM이나 TF-IDF가 단어의 빈도에 초점을 맞추는 한계를 넘어, 단어의 의미와 주제를 파악하기 위해 등장.
LSA (잠재 의미 분석):
- 개념: 전체 코퍼스에서 문서 속 단어들 사이의 잠재적인 의미 관계를 찾아내는 정보 검색 기술.
- 주요 기술: 특잇값 분해(SVD)를 활용하여 차원을 축소하고 숨겨진 의미 패턴을 추출
데이터 정제 및 정규화 과정을 거친 데이터 = train_data
# 역토큰화 (토큰화 작업을 역으로 수행)
detokenized_doc = []
for i in range(len(text)):
t = ' '.join(text[i])
detokenized_doc.append(t)
train_data = detokenized_doc
# 상위 5000개의 단어만 사용
c_vectorizer = CountVectorizer(stop_words='english', max_features = 5000)
document_term_matrix = c_vectorizer.fit_transform(train_data)
print('행렬의 크기 :',document_term_matrix.shape)
scikit-learn TruncatedSVD 활용
from sklearn.decomposition import TruncatedSVD
n_topics = 10
lsa_model = TruncatedSVD(n_components = n_topics)
lsa_model.fit_transform(document_term_matrix)
print(lsa_model.components_.shape)
terms = c_vectorizer.get_feature_names_out() # 단어 집합. 5,000개의 단어가 저장됨.
def get_topics(components, feature_names, n=5):
for idx, topic in enumerate(components):
print("Topic %d:" % (idx+1), [(feature_names[i], topic[i].round(5)) for i in topic.argsort()[:-n - 1:-1]])
get_topics(lsa_model.components_, terms)
LDA (잠재 디리클레 할당):
- 개념: 토픽 모델링의 한 종류로, 전체 코퍼스로부터 주요 주제(토픽)를 찾아내는 데 사용.
- 역할: 문서가 여러 토픽으로 구성될 수 있다고 가정하고, 각 문서와 토픽의 분포를 확률적으로 모델링.
# TF-IDF 행렬 생성
# 상위 5,000개의 단어만 사용
tfidf_vectorizer = TfidfVectorizer(stop_words='english', max_features=5000)
tf_idf_matrix = tfidf_vectorizer.fit_transform(train_data)
# TF-IDF 행렬의 크기를 확인해봅시다.
print('행렬의 크기 :', tf_idf_matrix.shape)
scikit-learn LDA Model 활용
from sklearn.decomposition import LatentDirichletAllocation
lda_model = LatentDirichletAllocation(n_components=10, learning_method='online', random_state=777, max_iter=1)
lda_model.fit_transform(tf_idf_matrix)
print(lda_model.components_.shape)
# LDA의 결과 토픽과 각 단어의 비중을 출력
terms = tfidf_vectorizer.get_feature_names_out() # 단어 집합. 5,000개의 단어가 저장됨.
def get_topics(components, feature_names, n=5):
for idx, topic in enumerate(components):
print("Topic %d:" % (idx+1), [(feature_names[i], topic[i].round(5)) for i in topic.argsort()[:-n-1:-1]])
get_topics(lda_model.components_, terms)
5. 텍스트 분포를 이용한 비지도 학습 토크나이저 (🛠 soynlp)
- 필요성 (한국어):
- 형태소 분석의 필요성: 한국어는 띄어쓰기만으로 정확한 단어 구분이 어려움.
- 단어 미등록 문제: 기존 형태소 분석기는 등록된 단어 기반으로 작동하여 신조어 등 미등록 단어 인식에 한계.
- soynlp 개념:
- 특징: 텍스트 데이터 내 문자 시퀀스의 출현 빈도와 앞뒤 단어의 연결 분포를 고려하여 형태소를 판단하는 비지도 학습 기반 형태소 분석기.
- 학습 과정: 전체 코퍼스로부터 응집 확률(Cohesion Score)과 브랜칭 엔트로피(Branching Entropy)를 계산하여 단어 점수표를 생성.
- 활용: LTokenizer 등을 활용하여 최대 점수를 기반으로 토큰화 수행.
"반포한강공원"이라는 문자열을 하나의 의미 있는 단어로 인식할 가능성이 높다.
"디스플레이"라는 문자열을 하나의 의미 있는 단어로 인식할 가능성이 높다.
이러한 점수들을 바탕으로 어떻게 단어를 나눌까? -> 최대 점수 토크나이저와 같은 알고리즘 개념으로!
🛠 LTokenizer
최대 점수 토크나이저의 원리를 바탕으로 실제 텍스트를 토큰화하는 데 사용되는 클래스이다.
from soynlp.tokenizer import LTokenizer
scores = {word:score.cohesion_forward for word, score in word_score_table.items()}
l_tokenizer = LTokenizer(scores=scores)
l_tokenizer.tokenize("국제사회와 우리의 노력들로 범죄를 척결하자", flatten=False)
🛠 최대 점수 Tokenizer
주어진 문자열을 분리할 때, 가장 높은 단어 점수를 갖는 문자열을 우선적으로 찾아 분리하는 방식이다.
from soynlp.tokenizer import MaxScoreTokenizer
maxscore_tokenizer = MaxScoreTokenizer(scores=scores)
maxscore_tokenizer.tokenize("국제사회와우리의노력들로범죄를척결하자")
반응형
'Deep Learning' 카테고리의 다른 글
[딥러닝] 텍스트 데이터를 문자열로 저장하기, 파일과 디렉터리 (3) | 2025.06.14 |
---|---|
[딥러닝] 딥러닝 알아보기2 - 텐서 생성, 텐서 타입, 텐서 타입 변환, 텐서 연산, 다양한 함수 정리 (1) | 2025.06.13 |
[딥러닝] 딥러닝 알아보기1 - 인공 신경망, 퍼셉트론, 은닉층, 딥러닝 문제점 및 해결 방법 (1) | 2025.06.12 |