LDiA
๋๋ถ๋ถ ์ฃผ์ ๋ชจํํ๋ ์๋ฏธ ๊ฒ์, ๋ด์ฉ ๊ธฐ๋ฐ ์ถ์ฒ ์์ง์์ ๊ฐ์ฅ ๋จผ์ ์ ํํด์ผ ํ ๊ธฐ๋ฒ์ LSA์ด๋ค. ๋ด์ฉ ๊ธฐ๋ฐ ์ํ์ถ์ฒ ์๊ณ ๋ฆฌ์ฆ์ ์ํ๋ฉด LSA๊ฐ LDiA ๋ณด๋ค ์ฝ ๋๋ฐฐ๋ก ์ ํํ๋ค. LSA์ ๊น๋ฆฐ ์ํ์ ๊ฐ๋จํ๊ณ ํจ์จ์ ์ด๋ค.
NLP์ ๋งฅ๋ฝ์์ LDiA๋ LSA์ฒ๋ผ ํ๋์ ์ฃผ์ ๋ชจํ์ ์ฐ์ถํ๋ค. LDiA๋ ์ด๋ฒ ์ฅ ๋์
๋ถ์์ ํ๋ ์ฌ๊ณ ์คํ๊ณผ ๋น์ทํ ๋ฐฉ์์ผ๋ก ์๋ฏธ ๋ฒกํฐ ๊ณต๊ฐ(์ฃผ์ ๋ฒกํฐ๋ค์ ๊ณต๊ฐ)์ ์ฐ์ถํ๋ค.
LDiA๊ฐ LSA์ ๋ค๋ฅธ ์ ์ ๋จ์ด ๋น๋๋ค์ด ๋๋ฆฌํด๋ ๋ถํฌ๋ฅผ ๋ฐ๋ฅธ๋ค๊ณ ๊ฐ์ ํ๋ค. LSA์ ๋ชจํ๋ณด๋ค LDiA์ ๋๋ฆฌํด๋ ๋ถํฌ๊ฐ ๋จ์ด ๋น๋๋ค์ ๋ถํฌ๋ฅผ ์ ํํํ๋ค.
LDiA๋ ์๋ฏธ ๋ฒกํฐ ๊ณต๊ฐ์ ์ฐ์ถํ๋ค. ์ฌ๊ณ ์คํ์์ ํน์ ๋จ์ด๋ค์ด ๊ฐ์ ๋ฌธ์์ ํจ๊ป ๋ฑ์ฅํ๋ ํ์์ ๊ธฐ์ดํด์ ๋จ์ด๋ค์ ์ฃผ์ ๋ค์ ์ง์ ๋ฐฐ์ ํ๋ค. ํ ๋ฌธ์์ ๋ํ ๊ฐ ๋จ์ด์ ์ฃผ์ ์ ์๋ค์ ์ด์ฉํด ๋ฌธ์์ ๋ฐฐ์ ํ๋ ์ ๊ทผ ๋ฐฉ์์ ๋ฐ๋ฅด๊ธฐ ๋๋ฌธ์ LSA๋ณด๋ค ์ดํดํ๊ธฐ ์ฝ๋ค.
LDiA๋ ๊ฐ ๋ฌธ์๋ฅผ ์์์ ๊ฐ์์ ์ฃผ์ ๋ค์ ํผํฉ์ผ๋ก ๊ฐ์ฃผํ๋ค. ์ฃผ์ ๊ฐ์๋ LDiA ๋ชจํ์ ํ๋ จํ๊ธฐ ์ ์ ๊ฐ๋ฐ์๊ฐ ๋ฏธ๋ฆฌ ์ ํ๋ค. LDiA๋ ๋ํ ๊ฐ ์ฃผ์ ๋ฅผ ๋จ์ด ์ถํ ํ์๋ค์ ๋ถํฌ๋ก ํํํ ์ ์๋ค๊ณ ๊ฐ์ ํ๋ค. LDiA๋ ๋ํ ๊ฐ ์ฃผ์ ๋ฅผ ๋จ์ด ์ถํ ํ์๋ค์ ๋ถํฌ๋ก ํํํ ์ ์๋ค๊ณ ๊ฐ์ ํ๋ค. (์ฌ์ (prior) ํ๋ฅ ๋ถํฌ)
LDiA์ ๊ธฐ์ด
๋๋ฆฌํด๋ ๋ถํฌ์ ๊ธฐ์ดํ ๋ถ์ ๋ฐฉ๋ฒ์ ์ ์ ์ ์์ด์์ ์ง๋จ ๊ตฌ์กฐ(population structure)๋ฅผ ์ถ๋ก ํ๊ธฐ ์ํด ๊ณ ์ํ๋ค.
LDiA์ ๊ธฐ์ดํ ๋ฌธ์ ์์ฑ๊ธฐ๋ ๋ค์ ๋๊ฐ์ง๋ฅผ ๋์๋ก ๊ฒฐ์ ํ๋ค.
- ๋ฌธ์๋ฅผ ์ํด ์์ฑํ ๋จ์ด๋ค์ ์(ํฌ์์ก ๋ถํฌ)
- ๋ฌธ์๋ฅผ ์ํด ํผํฉํ ์ฃผ์ ๋ค์ ์(๋๋ฆฌํด๋ ๋ถํฌ)
๋ฌธ์์ ๋จ์ด ์๋ฅผ ๊ฒฐ์ ํ๋ ๋ฐ ์ฐ์ด๋ ํฌ์์ก ๋ถํฌ๋ ํ๊ท ๋ฌธ์ ๊ธธ์ด๋ผ๋ ๋งค๊ฐ ๋ณ์ ํ๋๋ก ์ ์๋๋ค. ์ฃผ์ ๊ฐ์๋ฅผ ๊ฒฐ์ ํ๋ ๋ฐ ์ฐ์ด๋ ๋๋ฆฌํด๋ ๋ถํฌ๋ ๊ทธ๋ณด๋ค ๋๊ฐ ๋ง์ ์ธ๊ฐ์ ๋งค๊ฐ ๋ณ์๋ก ์ ์๋๋ค. ๋ ์์น๋ฅผ ๊ฒฐ์ ํ ํ์๋ ๋ฌธ์์ ์ฌ์ฉํ ๋ชจ๋ ์ฃผ์ ์ ์ฉ์ด-์ฃผ์ ํ๋ ฌ๋ง ์์ผ๋ฉด ๊ฐ๋จํ ์ ์ฐจ๋ก ์๋ก์ด ๋ฌธ์๋ค์ ์์ฑํ ์ ์๋ค.
ํต๊ณํ์ ์ผ๋ก ๋ถ์ํ๋ฉด ๋ ๋์ ๋ฐ์ ํ๋ฅ ๋ถํฌ์ ๋งค๊ฐ ๋ณ์๋ค์ ๊ตฌํ ์ ์์์ ๊นจ๋ฌ์๋ค. 1๋ฒ ์์น, ์ฆ ๋ฌธ์์ ๋จ์ด ์๋ฅผ ๊ฒฐ์ ํ๊ธฐ ์ํด์๋ ํด๋น ํฌ์์ก ๋ถํฌ๋ฅผ ์ ํด์ผํ๋ค. ์ด๋ฅผ ์ํ ํ๊ท ์ ๋ง๋ญ์น์ ๋ชจ๋ ๋ฌธ์์ ๋ํ ๋จ์ด ๋ชจ์๋ค์ ํ๊ท ๋จ์ด ์(ํ๊ท n-gram ์)๋ก ์ค์ ํ๋ฉด ๋๋ค.
ํฌ์์ก ๋ถํฌ ํจ์ $f(x) = \frac{e^{-\lambda}\lambda^x}{x!}$
ํ๊ท ($u$) = ${\lambda}$ = mean_document_len
total_corpus_len = 0
for document_text in sms.text:
total_corpus_len += len(casual_tokenize(document_text))
mean_document_len = total_corpus_len / len(sms)
round(mean_document_len,2) # 21.35
์ด ํต๊ณ๋์ ๋ฐ๋์ BOW๋ค์์ ์ง์ ๊ณ์ฐํด์ผํ๋ค. ๋ถ์ฉ์ด ํํฐ๋ง์ด๋ ๊ธฐํ ์ ๊ทํ๋ฅผ ์ ์ฉํ ๋ฌธ์๋ค์ ํ ํฐํํ๊ณ ๋ฒกํฐํํ ๋จ์ด๋ค์ ์๋ฅผ ์ธ์ด์ผํ๋ค.(๋จ์ด ์ฌ์ ์ ๊ธธ์ด)
2๋ฒ ์์น, ์ฆ ์ฃผ์ ์ ์๋ ์ค์ ๋ก ๋จ์ด๋ค์ ์ฃผ์ ๋ค์ ๋ฐฐ์ ํด ๋ณด๊ธฐ ์ ๊น์ง๋ ์์ ์๋ค. ์ด๋ K-NN์ด๋ K-means
clustering ๊ตฐ์งํ์ ๊ฐ์ ๊ตฐ์งํ ์๊ณ ๋ฆฌ์ฆ๋ค์ฒ๋ผ ๋จผ์ k๋ฅผ ๊ฒฐ์ ํด์ผ ๋ค์ ๋จ๊ณ๋ก ๋์๊ฐ ์ ์๋ ๊ฒ๊ณผ ๋น์ทํ ์ํฉ์ด๋ค.
์ฃผ์ ์ ๊ฐ์๋ฅผ ์์๋ก ์ ํ๊ณ ๊ฐ์ ํด ๋๊ฐ๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ค. ์ผ๋จ ์ฃผ์ ๊ฐ์๋ฅผ ์ง์ ํด ์ฃผ๋ฉด LDiA๋ ๊ฐ ์ฃผ์ ์ ๋ํด ๋ชฉ์ ํจ์๊ฐ ์ต์ ๊ฐ์ด ๋๋ ๋จ์ด๋ค์ ํผํฉ์ ์ฐพ์๋ธ๋ค.
LDiA๋ฅผ ๋ฐ๋ณตํ๋ฉด์ k๋ฅผ ์กฐ์จํ๋ฉด ์ต์ ์ k์ ๋๋ฌํ ์ ์๋ค. ์ด๋ฐ ์ต์ ํ ๊ณผ์ ์ ์๋ํํ ์์๋ค. LDiA ์ธ์ด ๋ชจํ์ ํ์ง์ ํ๊ฐํ๋ ๋ฐฉ๋ฒ์ด ํ์ํ๋ค. LDiA์ ๊ฒฐ๊ณผ๊ฐ ๋ง๋ญ์น์ ์๋ ์ด๋ค ๋ถ๋ฅ ๋๋ ํ๊ท๋ฌธ์ ์ ์ ์ฉํด์ ๊ทธ ๊ฒฐ๊ณผ์ ์ ๋ต์ ์ค์ฐจ๋ฅผ ์ธก์ ํ๋ ๊ฒ์ด๋ค. ์ด๋ ๋น์ฉํจ์(cost function)๋ฅผ ํ๊ฐํ๋ ๊ฒ์ ํด๋นํ๋ค. ์ ๋ต์ผ๋ก ๋ถ๋ฅ๋ช
(๊ฐ์ , ํค์๋, ์ฃผ์ )์ด ๋ถ์ ๋ฌธ์๋ค๋ก LDiA ๋ชจํ์ ์คํํด์ ์ค์ฐจ๋ฅผ ์ธก์ ํ๋ฉด ๋๋ค.
๋ฌธ์ ๋ฉ์์ง ๋ง๋ญ์น์ ๋ํ LDiA ์ฃผ์ ๋ชจํ
LDiA๊ฐ ์ฐ์ถํ ์ฃผ์ ๋ ์ฌ๋์ด ์ดํดํ๊ธฐ ์ข ๋ ์ฝ๋. LSA๊ฐ ๋จ์ด์ ์๋ ๋จ์ด๋ค์ ๋ ๋จ์ด๋จ๋ฆฐ๋ค๋ฉด LDiA๋ ๊ฐ๊น๊ฒ ์๊ฐํ๋ ๋จ์ด๋ค์ ๋ ๊ฐ๊น๊ฒ ๋ง๋ ๋ค.
LDiA๋ ๊ณต๊ฐ์ ๋น์ ํ์ ์ธ ๋ฐฉ์์ผ๋ก ๋นํ๊ณ ์ผ๊ทธ๋ฌ ๋จ๋ฆฐ๋ค. ์๋์ ๊ณต๊ฐ์ด 3์ฐจ์์ด๊ณ ์ด๋ฅผ 2์ฐจ์์ผ๋ก ํฌ์ํ๋ ๋ฐฉ๋ฒ์ด ์๋ํ ์๊ฐํํ๊ธฐ ์ด๋ ต๋ค.
# ๋ฉ์ธ์ง ์คํธ ๋ฌธ์ ์ ๋์
์ฌ์ฉํ ์ฃผ์ ์ ์๋ 16. ์ฃผ์ ์ ์๋ฅผ ๋ฎ๊ฒ ์ ์งํ๋ฉด ๊ณผ๋์ ํฉ(overfitting)์ ์ค์ด๋๋ฐ ๋์์ด ๋๋ค.
from sklearn.feature_extraction.text import CountVectorizer
from nltk.tokenize import casual_tokenize
import numpy as np
np.random.seed(42) #LDiA๋ ๋์๋ฅผ ์ด์ฉํ๋ค.
# ๋ถ์ฉ์ด ์ ๊ฑฐ + ํ ํฐํ๋ BOW ๋จ์ด๋ค์ ์ฌ์ฉ
counter = CountVectorizer(tokenizer=casual_tokenize)
bow_docs = pd.DataFrame(counter.fit_transform(raw_documents=sms.text).toarray(),index=index)
bow_docs.head()
# 0 1 2 3 4 5 ... 9226 9227 9228 9229 9230 9231
# sms0 0 0 0 0 0 0 ... 0 0 0 0 0 0
# sms1 0 0 0 0 0 0 ... 0 0 0 0 0 0
# sms2! 0 0 0 0 0 0 ... 0 0 0 0 0 0
# sms3 0 0 0 0 0 0 ... 0 0 0 0 0 0
# sms4 0 0 0 0 0 0 ... 0 0 0 0 0 0
column_nums, terms = zip(*sorted(zip(counter.vocabulary_.values(),counter.vocabulary_.keys())))
bow_docs.columns = terms
์ฒซ ๋ฌธ์ ๋ฉ์์ง sms0์ ๋จ์ด ๋ชจ์
sms.loc['sms0'].text
# 'Go until jurong point, crazy.. Available only in bugis n great world la e buffet..
bow_docs.loc['sms0'][bow_docs.loc['sms0'] > 0].head()
# , 1
# .. 1
# 2
# amore 1
# available 1
# Name: sms0, dtype: int64
LDiA ์ ์ฉ ํ ์ฃผ์ ๋ฒกํฐ๋ค์ ์ฐ์ถ
from sklearn.decomposition import LatentDirichletAllocation as LDiA
ldia = LDiA(n_components=16, learning_method='batch') # ์ฃผ์ ์ 16
ldia = ldia.fit(bow_docs) # bow_docs.shape (4837, 9232)
ldia.components_.shape # (16, 9232)
9232๊ฐ์ ๋จ์ด๋ฅผ 16๊ฐ์ ์ฃผ์ ๋ก ์์ถํ๋ค. ์ฑ๋ถ ํ์ธ(component)
๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋ ๋ฌธ์๋ !์ด๊ณ LDiA์์ topic4์ ๊ฐ์ฅ ๋ง์ ์ ์๋ฅผ ํ ๋นํ๋ค.
ldia = ldia.fit(bow_docs) # bow_docs.shape (4837, 9232)
ldia.components_.shape # (16, 9232)
columns = ["topic{}".format(i) for i in range(1,17)]
components = pd.DataFrame(ldia.components_.T,index=terms,columns=columns)
components.round(2).head(3)
# topic1 topic2 topic3 topic4 ... topic13 topic14 topic15 topic16
# ! 184.03 15.00 72.22 394.95 ... 64.40 297.29 41.16 11.70
# " 0.68 4.22 2.41 0.06 ... 0.07 62.72 12.27 0.06
# # 0.06 0.06 0.06 0.06 ... 1.07 4.05 0.06 0.06
# [3 rows x 16 columns]
topic4๋ ๋ค๋ฅธ ๊ฐ์ ํํ๋ณด๋ค !์ ๋ง์ด ์ ์๋ฅผ ์ค๊ฒ์ผ๋ก๋ณด์ ๊ฐํ ๊ฐ์กฐ์ผ ๊ฐ๋ฅ์ฑ์ด ํฌ๋ค.
components.topic4.sort_values(ascending=False)[:20]
# ! 394.952246
# . 218.049724
# to 119.533134
# u 118.857546
# call 111.948541
# £ 107.358914
# , 96.954384
# * 90.314783
# your 90.215961
# is 75.750037
# the 73.335877
# a 62.456249
# on 61.814983
# claim 57.013114
# from 56.541578
# prize 54.284250
# mobile 50.273584
# urgent 49.659121
# & 47.490745
# now 47.419239
# Name: topic4, dtype: float64
LSA์ ๋ค๋ฅด๊ฒ ์ง๊ด์ ์ผ๋ก ํ๋ณํ ์ ์๋ค.
๋ฌธ์ ๋ฉ์์ง๋ฅผ ์คํธ ๋๋ ๋น์คํธ์ผ๋ก ๋ถ๋ฅํ๊ธฐ ์ํด LDiA ์ฃผ์ ๋ฒกํฐ๋ค์ ๊ณ์ฐํ ๋ค์ LDA(์ ํ ํ๋ณ ๋ถ์)์ ์ ์ฉํ๋ค.
0์ธ ๊ฒ์ด ๋ง์ ๊ฒ์ ์ ๋ถ๋ฅํ ๊ฒ์ด๋ค. 0์ ์ฃผ์ ์ ์๊ด์๋ค๋ ์๋ฏธ์ด๋ค. LDiA ํ์ดํ๋ผ์ธ์ ๊ธฐ์ดํด ์ฌ์
์์ ๊ฒฐ์ ์ ๋ด๋ฆด ๋ ์ด๋ ์ค์ํ ์ฅ์ ์ด๋ค.
ldia16_topic_vectors = ldia.transform(bow_docs)
ldia16_topic_vectors = pd.DataFrame(ldia16_topic_vectors,index = index, columns = columns)
ldia16_topic_vectors.round(2).head()
# topic1 topic2 topic3 topic4 ... topic13 topic14 topic15 topic16
# sms0 0.62 0.00 0.00 0.00 ... 0.00 0.00 0.00 NaN
# sms1 0.01 0.01 0.01 0.01 ... 0.01 0.01 0.01 NaN
# sms2! 0.00 0.00 0.00 0.00 ... 0.00 0.00 0.00 NaN
# sms3 0.00 0.00 0.00 0.09 ... 0.00 0.00 0.00 NaN
# sms4 0.00 0.33 0.00 0.00 ... 0.00 0.00 0.00 NaN
# [5 rows x 16 columns]
LDiA + LDA ์คํธ ๋ถ๋ฅ๊ธฐ
from sklearn.model_selection import train_test_split
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
X_train,X_test,y_train,y_test = train_test_split(ldia16_topic_vectors,sms.spam,test_size=0.5)
X_train['topic16'] = np.zeros(len(X_train['topic16'])).T # NaN ๊ฐ -> 0
lda = LDA(n_components=1)
lda = lda.fit(X_train,y_train)
sms['lda16_spam'] = lda.predict(ldia16_topic_vectors)
X_test['topic16'] = np.zeros(len(X_test['topic16'])).T # NaN ๊ฐ -> 0
y_test['topic16'] = np.zeros(len(y_test['topic16'])).T # NaN ๊ฐ -> 0
round(float(lda.score(X_test,y_test)),2) # 0.93 ์ ํ๋
์ฐจ์์ด 16->32์ผ ๋ LDiA ๋น๊ต
ldia32 = LDiA(n_components=32,learning_method='batch')
ldia32 = ldia32.fit(bow_docs)
ldia32.components_.shape # (32, 9232)
ldia32_topic_vectors = ldia32.transform(bow_docs)
columns32 = ['topic{}'.format(i) for i in range(ldia32.n_components)]
ldia32_topic_vectors = pd.DataFrame(ldia32_topic_vectors, index=index,columns=columns32)
ldia32_topic_vectors.round(2).head()
# topic0 topic1 topic2 topic3 topic4 topic5 ... topic26 \
# sms0 0.0 0.0 0.0 0.24 0.0 0.00 ... 0.00
# sms1 0.0 0.0 0.0 0.00 0.0 0.00 ... 0.12
# sms2! 0.0 0.0 0.0 0.00 0.0 0.00 ... 0.00
# sms3 0.0 0.0 0.0 0.93 0.0 0.00 ... 0.00
# sms4 0.0 0.0 0.0 0.00 0.0 0.24 ... 0.00
# topic27 topic28 topic29 topic30 topic31
# sms0 0.0 0.0 0.00 0.00 0.0
# sms1 0.0 0.0 0.00 0.00 0.0
# sms2! 0.0 0.0 0.98 0.00 0.0
# sms3 0.0 0.0 0.00 0.00 0.0
# sms4 0.0 0.0 0.00 0.14 0.0
# [5 rows x 32 columns]
0์ด ๋ง์ ๊ฒ์ผ๋ก ๋ณด์ ๊น๋ํ๊ฒ ๋ถ๋ฆฌ๋์๋ค๋ ๊ฒ์ ์ ์ ์๋ค.
์ ํ๋ ์ธก์
from sklearn.model_selection import train_test_split
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
X_train,X_test,y_train,y_test = train_test_split(ldia32_topic_vectors,sms.spam,test_size=0.5)
lda = LDA(n_components=1)
lda = lda.fit(X_train,y_train)
sms['lda_32_spam'] = lda.predict(ldia32_topic_vectors)
X_train.shape # (2418, 32)
round(float(lda.score(X_train,y_train)),3) #0.927
์ฃผ์ ์ ์๋ฅผ ๋๋ ค ์ข ๋ ๋ช ํํ ๋ถ๋ฆฌ๋ฅผ ํ๋ค. ์ ํ๋๊ฐ ์์ง๊น์ง PCA + LDA๋ฅผ ๋์ง๋ ๋ชปํ๋ค.
'๐ฃ๏ธ Natural Language Processing' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
LSA ๊ฑฐ๋ฆฌ์ ์ ์ฌ๋ (0) | 2021.02.21 |
---|---|
[Transformer] Multi-Head Attention (1) (0) | 2021.02.20 |
[Kaggle] ๋ค์ด๋ฒ ์ํ ๋ฆฌ๋ทฐ ๋ถ๋ฅ(2) (0) | 2021.02.17 |
์ฑ ๋ด ๋ง๋ค๊ธฐ(1) (0) | 2021.02.13 |
MaLSTM (0) | 2021.02.13 |