[NLP] ์์ฐ์ด์ฒ๋ฆฌ 4. ํ ํฝ ๋ชจ๋ธ๋ง(LDA, NMF)
๐ํ ํฝ ๋ชจ๋ธ๋ง (Topic Modeling)
- ๋ฌธ์ ๋ด ์ ์ฌ์ ์ธ "์ฃผ์ "๋ฅผ ์๋ณํ๋ ๊ฒ = ์ฃผ์ ํ์ /๋ถ๋ฅ
- LDA, NMF, pLSA, LSI, PLSI
- ํ ํฝ ๋ชจ๋ธ
: ๋ฌธ์ ์งํฉ์ ์ถ์์ ์ธ "์ฃผ์ "๋ฅผ ๋ฐ๊ฒฌํ๊ธฐ ์ํ ํต๊ณ์ ๋ชจ๋ธ ์ค ํ๋
: ํ ์คํธ ๋ณธ๋ฌธ์ ์จ๊ฒจ์ง ์๋ฏธ๊ตฌ์กฐ๋ฅผ ๋ฐ๊ฒฌํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ ํ ์คํธ ๋ง์ด๋ ๊ธฐ๋ฒ ์ค ํ๋
โ๏ธ์์ฉ : ๋ฌธ์ ๋ถ๋ฅ ๋ฐ ์์ฝ, ์ถ์ฒ ์์คํ , ์์ฅ ์กฐ์ฌ ๋ฐ ์ฌ๋ก ๋ถ์
โ๏ธ ์ ์ฌ ์๋ฏธ ๋ถ์, LSI : ์ต์ด์ ํ ํฝ ๋ชจ๋ธ, ๋ฌธํ-์ฉ์ดํ๋ ฌ = ๋ฌธํ-์๋ฏธํ๋ ฌ + ์๋ฏธ-์ฉ์ดํ๋ ฌ ๋ถํดํ์ฌ ์ ์ฌ๋ณ์ ์๋ฏธ๋ฅผ ๋ฐ๊ฒฌํ๊ณ ์ ํจ
โ๏ธ ์ ์ฌ ๋๋ฆฌํด๋ ํ ๋นLDA : ๊ฐ ๋ฌธ์์ ํ ํฝ ๋ถํฌ์ ๊ฐ ํ ํฝ ๋ด์ ๋จ์ด ๋ถํฌ๋ฅผ ์ถ์ / ํ๋ฅ ์ ๋ชจ๋ธ
โ๏ธ NMF ๋น์์ ํ๋ ฌ๋ถํด : ๋ชจ๋ ์์๊ฐ 0 ์ด์์ธ ํ๋ ฌ์ ๋ ๊ฐ ์ด์์ ๋น์์ ํ๋ ฌ์ ๊ณฑ์ผ๋ก ๋ถํดํ๋ ๊ธฐ๋ฒ / ์ ํ ๋์ ๊ธฐ๋ฐ ๋ชจ๋ธ
- ์ฅ์ : ์ง๊ด์ ์ผ๋ก ํด์, ๋ณต์ ํ ๋ฐ์ดํฐ์ ๋ด์ฌ๋ ๊ตฌ์กฐ ๋ฐ๊ฒฌ์ ํจ๊ณผ์ | ๋จ์ : ๋ชจ๋ ์์๊ฐ ๋น์์์ผ ๋๋ง ์ ์ฉ ๊ฐ๋ฅ
๐พLDA ํ ํฝ ๋ชจ๋ธ๋ง ์ด์ฉ
๋ฐ์ดํฐ๋ ๋ด์ค ์ ๋ชฉ๊ณผ ๋ ์ด๋ธ์ ํฌํจํ๊ณ ์๊ณ , ์ด ์ ๋ชฉ๋ค์ ๋ถ์ํ์ฌ 4๊ฐ์ ํ ํฝ์ผ๋ก ๋๋ ๋ณด๊ณ ์ค์ ๋ ์ด๋ธ๊ณผ ๋น๊ตํด๋ณด๋ ์ค์ต์ ๋๋ค.
# TF-IDF๋ก ํ
์คํธ ๋ฒกํฐํ ์งํ
from sklearn.feature_extraction.text import TfidfVectorizer
tfidfV= TfidfVectorizer()
dtm = tfidfV.fit_transform(df['title'])
df_dtm = pd.DataFrame(dtm.toarray(), columns=tfidfV.get_feature_names_out())
LDA ํ ํฝ ๋ชจ๋ธ๋ง์ ์งํํ๊ณ ํ ํฝ์ 4๊ฐ๋ก ์ง์ ,
W : ์๋ณธ ๋ฐ์ดํฐ์ ๊ฐ ํ์ด ์ด๋ป๊ฒ H์ ๊ฐ ํ์ ์กฐํฉ์ผ๋ก ํํ๋ ์ ์๋์ง ๋ํ๋
-> weight matrix, basis matrix / ์๋ณธ ๋ฐ์ดํฐ๋ฅผ ์ ์ฌ์ ํน์ ์ผ๋ก ๋ณํํ๋ ๊ธฐ์ ํ์ฑ
H : ์๋ณธ ๋ฐ์ดํฐ์ ์ด์ ์๋ก์ด ์ถ์๋ ์ฐจ์์ ํน์ฑ์ผ๋ก ํํํจ
-> coefficient matrix, encoding matrix / ์ ์ฌ์ ํน์ฑ๋ค์ด ์๋ณธ ๋ฐ์ดํฐ๋ฅผ ์ด๋ป๊ฒ ์ฌ๊ตฌ์ฑํ๋์ง๋ฅผ ๋ํ๋ด๋ ๊ณ์๋ค ํฌํจ
# LDA ํ ํฝ ๋ชจ๋ธ๋ง ์งํ
from sklearn.decomposition import LatentDirichletAllocation
LDA_model = LatentDirichletAllocation(n_component = 4) #4๊ฐ ํ ํฝ์ผ๋ก ๋๋
W = LDA_model.fit_transform(df_dtm)
H = LDA_model.components_
# df์ ์ค์ ์ ๋ชฉ๊ณผ ๋ ์ด๋ธ์ ๊ฐ์ด ํํ
df_lda_w = pd.DataFrame(W)
df_lda_w['title'] = df['title']
df_lda_w['label'] = df['label']
# df๋ก ๊ฒฐ๊ณผ ๋ฐํ
df_lda_topic = pd.DataFrame(H, columns=tfidfvect.get_feature_names_out())
df_lda_W[df_lda_W["label"] == "์คํฌ์ธ "].head(20).style.background_gradient(axis=1)
์ด๋ ๊ฒ ํน์ ๋ ์ด๋ธ์ ๊ฐ๋ค๋ง ๋ดค์ ๋ ์คํฌ์ธ ๋ 3๋ฒ ์ธ๋ฑ์ค ํ ํฝ์ผ๋ก ์ ๋๋์ด ์ง ๊ฒ์ ํ์ธํ ์ ์๋ค.
๐พNMF ํ ํฝ ๋ชจ๋ธ๋ง ์ด์ฉ
from sklearn.decomposition import NMF
nmf_model = NMF(n_components = 4)
W = nmf_model.fit_transform(df_dtm)
H = nmf_model.components_
df_nmf_w = pd.DataFrame(W)
df_nmf_w['title'] = df['title']
df_nmf_w['label'] = df['label']
df_nmf_w[df_nmf_w["label"] == "์ธ๊ณ"].head(20).style.background_gradient(axis=1)
์์์ ํ๋ LDA ๊ณผ์ ์ด๋ ๋๊ฐ๋ค.
๋ง์ง๋ง์ผ๋ก ๋ ๋ชจ๋ธ์์ ๊ฐ ํ ํฝ ๋ณ๋ก ๋ง์ด ๋์จ ๋จ์ด๋ค์ ๊ทธ๋ํ๋ก ๋น๊ต
# ํ ํฝ๋ณ๋ก ์์ ํค์๋๋ฅผ ๋ง๋๊ทธ๋ํ๋ก ์๊ฐํํ๋ ํจ์ : plot_top_words
n_top_words = 20
plot_top_words(
LDA_model, tfidfvect.get_feature_names_out(), n_top_words,
"Topics in LDA model (LatentDirichletAllocation)", n_topics=4
)
plot_top_words(
nmf_model, tfidfvect.get_feature_names_out(), n_top_words,
"Topics in LDA model (LatentDirichletAllocation)", n_topics=4
)
ํ ์คํธ ๋ฒกํฐํ๋ฅผ TF-IDF ๋ง๊ณ CountVectorizer๋ฅผ ์ด์ฉํด์ ๋ค์ ํด๋ด๋ ์ข๊ณ
์ด์ ์ ํ๋ ์๋ํด๋ผ์ฐ๋๋ ๋ณต์ตํด๋ณด๋ ๊ฒ์ ์ถ์ฒํ๋ค.
์ถ์ฒ
https://www.eecis.udel.edu/~shatkay/Course/papers/UIntrotoTopicModelsBlei2011-5.pdf
๋ชจ๋์ ํ๊ตญ์ด ํ ์คํธ ๋ถ์๊ณผ ์์ฐ์ด์ฒ๋ฆฌ with ํ์ด์ฌ ๊ฐ์ | ๋ฐ์กฐ์ - ์ธํ๋ฐ
๋ฐ์กฐ์ | ํ์ด์ฌ ํ๊ตญ์ด ํ ์คํธ ๋ถ์๊ณผ ์์ฐ์ด์ฒ๋ฆฌ ์๋ํด๋ผ์ฐ๋ ์๊ฐํ, ํํ์ ๋ถ์, ํ ํฝ๋ชจ๋ธ๋ง, ๊ตฐ์งํ, ์ ์ฌ๋ ๋ถ์, ํ ์คํธ๋ฐ์ดํฐ ๋ฒกํฐํ๋ฅผ ์ํ ๋จ์ด ๊ฐ๋ฐฉ๊ณผ TF-IDF, ๋จธ์ ๋ฌ๋๊ณผ ๋ฅ๋ฌ๋์
www.inflearn.com