import re
: text 조각을 톸는이라고 하는 더 작은 단위로 분리하는 방법
import nltk
sent = """At eight 0'clock on Thursday morning Arhur didn't feel very good."""
token = nltk.word_tokenize(sent)
token
>>>> ['At', 'eight', "o'clock", 'on', 'Thursday', 'morning',
'Arthur', 'did', "n't", 'feel', 'very', 'good', '.']
✅ 불용어 제거 추천
언어 분류, 스팸 필터링, 캡션 생성, 자동 태그, 생성, 감정 분석 또는 텍스트 분류와 관련된 작업
✅ 불용어 유지
기계 번역, 질문 답변 문재, 텍스트 요약, 언어 모델링 중 하나인 경우 이러한 응용 프로그램의 중요한 부분이므로 유지
✅ Python에서 불용어 제거 방법
: NLTK, SpaCy, Gensim 등 라이브러리 사용
: 단어들의 순서는 전혀 고려하지 않고, 단어들의 출현 빈도(frequency)에만 집중하는 텍스트 데이터의 수치화 표현 방법
: 모든 단어를 고려하는 것이 아니라 일부 단어만 고려하는 접근 방법 사용
n-gram : 동물원에 버스를 타고 갔다.
uni-gram : ['동물원에','버스를', '타고', '갔다']
bi-gram : ['동물원에 버스를', '버스를 타고', '타고 갔다.']
✅ 너무 희귀한 단어를 제외하는 효과가 있는 것은 무엇을까요? min_df
✅ 너무 많이 등장하는 불용어를 제외하는 효과가 있는 것은 무엇일까요? max_df
✅ BOW를 사용하다보면 앞뒤 맥락을 고려하지 않는 단점이 있습니다. 이것을 해결하기 위한 것은 무엇일까요? ngram_range
✅ 단어를 너무 많이 사용해서 dtm 가 너무 커지는 것을 방지하기 위해 최대 단어를 제한하는 것은 무엇일까요? max_features
: 여러 문서로 이루어진 문서군이 있을 때 어떤 단어가 특정 문서 내에서 얼마나 중요한 것인지 나타내는 통계적 수치.
문서의 핵심어 추출, 검색 엔진에서 검색 결과의 순위를 결정하거나, 문서들 사이의 비슷한 정도를 구하는 등의 용도로 사용.
✅ TF : 단어 빈도, 특정한 단어가 문서 내에 얼마나 자주 등장하는 지 나타내는 값
✅ DF : 문서 빈도, 특정 단어가 등장한 문서의 수
✅ TF-IDF : 모든 문서에서 자주 등장하는 단어는 중요도가 낮다고 판단
➡️ 사이킷런은 TF-IDF를 자동 계산해주는 TfidfVectorizer
https://scikit-learn.org/stable/modules/feature_extraction.html
import warnings
warnings.filterwarning('ignore')
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
# 시각화를 위한 한글폰트 설정
import koreanize_matplotlib
%config InlineBackend.figure_format = 'retina'
corpus = ["코로나 거리두기와 코로나 상생지원금 문의입니다.",
"지하철 운행시간과 지하철 요금 문의입니다.",
"지하철 승강장 문의입니다.",
"코로나 선별진료소 문의입니다.",
"버스 운행시간 문의입니다.",
"버스 터미널 위치 안내입니다.",
"코로나 거리두기 안내입니다.",
"택시 승강장 문의입니다."
]
: sklearn에서 제공하는 BOW를 만들 수 있는 방법
from sklearn.feature_extraction.text import CountVectorizer
📌주의 !!
단, fit_transform 은 학습데이터만 사용하고 예측 데이터에는 transform을 사용
fit은 학습 데이터에만 사용
cvect = CountVectorizer()
dtm = cvect.fit_transform(corpus)
dtm
>>>>
# fit_transform() 어휘 사전을 배우고 문서 용어 매트릭스를 반환합니다.
# fit 다음에 변환이 오는 것과 동일하지만 더 효율적으로 구현됩니다.
# dtm
dtm = cvect.fit_transform(corpus)
dtm
>>>>
<8x16 sparse matrix of type '<class 'numpy.int64'>'
with 27 stored elements in Compressed Sparse Row format>
vocab = cvect.get_feature_names_out()
vocab
>>>>
array(['거리두기', '거리두기와', '문의입니다', '버스', '상생지원금', '선별진료소', '승강장', '안내입니다',
'요금', '운행시간', '운행시간과', '위치', '지하철', '코로나', '택시', '터미널'],
dtype=object)
# 단어사전은 {"단어": 인덱스번호}
cvect.vocabulary_
>>>>
{'코로나': 13,
'거리두기와': 1,
'상생지원금': 4,
'문의입니다': 2,
'지하철': 12,
'운행시간과': 10,
'요금': 8,
'승강장': 6,
'선별진료소': 5,
'버스': 3,
'운행시간': 9,
'터미널': 15,
'위치': 11,
'안내입니다': 7,
'거리두기': 0,
'택시': 14}
df_dtm = pd.DataFrame(dtm.toarray(), columns=vocab)
print(df_dtm.shape)
df_dtm
>>>>
(8, 16)
df_dtm.sum()
>>>>
거리두기 1
거리두기와 1
문의입니다 6
버스 2
상생지원금 1
선별진료소 1
승강장 2
안내입니다 2
요금 1
운행시간 1
운행시간과 1
위치 1
지하철 3
코로나 4
택시 1
터미널 1
dtype: int64
cvect = CountVectorizer(ngram_range=(1, 2))
dtm = cvect.fit_transform(corpus)
dtm
>>>>
<8x36 sparse matrix of type '<class 'numpy.int64'>'
with 48 stored elements in Compressed Sparse Row format>
df_dtm = pd.DataFrame(dtm.toarray(), columns=cvect.get_feature_names_out())
df_dtm
df_dtm.sum()
>>>>
거리두기 1
거리두기 안내입니다 1
거리두기와 1
거리두기와 코로나 1
문의입니다 6
버스 2
버스 운행시간 1
버스 터미널 1
상생지원금 1
상생지원금 문의입니다 1
선별진료소 1
선별진료소 문의입니다 1
승강장 2
승강장 문의입니다 2
안내입니다 2
요금 1
요금 문의입니다 1
운행시간 1
운행시간 문의입니다 1
운행시간과 1
운행시간과 지하철 1
위치 1
위치 안내입니다 1
지하철 3
지하철 승강장 1
지하철 요금 1
지하철 운행시간과 1
코로나 4
코로나 거리두기 1
코로나 거리두기와 1
코로나 상생지원금 1
코로나 선별진료소 1
택시 1
택시 승강장 1
터미널 1
터미널 위치 1
dtype: int64
def display_transform_dtm(cvect, corpus):
"""
모델을 받아 변환을 하고 문서 용어 행렬을 반환하는 함수
"""
dtm = cvect.fit_transform(corpus)
df_dtm = pd.DataFrame(dtm.toarray(), columns=cvect.get_feature_names_out())
print(df_dtm.shape)
return df_dtm.style.background_gradient()
display_transform_dtm(cvect, corpus)
cvect = CountVectorizer(min_df=2)
display_transform_dtm(cvect, corpus)
cvect = CountVectorizer(max_df=4)
display_transform_dtm(cvect, corpus)
cvect = CountVectorizer(max_feature=10)
display_transform_dtm(cvect, corpus)
stop_word = ['코로나', '문의입니다', '터미널', '택시']
cvect = CountVectorizer(stop_words=stop_words)
display_transform_dtm(cvect, corpus)
from sklearn.feature_extraction.text import TfidfVectorizer
tfidfvect = TfidfVectorizer()
dtm = tfidfVect.fit_transform(corpus)
# 문서에 토큰이 더 많이 나타날수록 가중치는 더 커짐
# 그러나 토큰이 문서에 많이 표시될수록 가중치 감소
# 얼마나 빈번하게 등장하냐에 따라 가중치 값 변환
# 전체 문서에서는 자주 등장하지 않지만, 특정 문서에서 자주 등장한다면 가중치 값 높게 나옴
# 모든 문서에서 자주 등장하는 값은 가중치 낮게 나옴
tfidfvect = TfidfVectorizer()
display_transform_dtm(tfidfvect, corpus)
idf = tfidfVect.idf_
idf
>>>>
array([2.5040774 , 2.5040774 , 1.25131443, 2.09861229, 2.5040774 ,
2.5040774 , 2.09861229, 2.09861229, 2.5040774 , 2.5040774 ,
2.5040774 , 2.5040774 , 2.09861229, 1.81093022, 2.5040774 ,
2.5040774 ])
# 사전만들기
vocab = tfidfvect.get_feature_names_out()
vocab
idf_dict = dict(zip(vocab, idf))
idf_dict
>>>>
{'거리두기': 2.504077396776274,
'거리두기와': 2.504077396776274,
'문의입니다': 1.251314428280906,
'버스': 2.09861228866811,
'상생지원금': 2.504077396776274,
'선별진료소': 2.504077396776274,
'승강장': 2.09861228866811,
'안내입니다': 2.09861228866811,
'요금': 2.504077396776274,
'운행시간': 2.504077396776274,
'운행시간과': 2.504077396776274,
'위치': 2.504077396776274,
'지하철': 2.09861228866811,
'코로나': 1.8109302162163288,
'택시': 2.504077396776274,
'터미널': 2.504077396776274}
pd.Series(idf_dict).plot.barh()
tv = TfidfVectorizer(analyzer='word', ngram_range=(1, 2), min_df=1, max_df=1.0,
stop_words=['거리두기', '거리두기와', '문의입니다', '코로나'])
tv.fit_transform(corpus)
display_transform_dtm(tv, corpus)