Ver3.0 ๐ค ์์ฐ์ด ์ฒ๋ฆฌ์ NLTKยทspaCy๋ฅผ ํ์ฉํ ํ ์คํธ ๋ง์ด๋ ์์ ์ ๋ณต

๐ค ์์ฐ์ด ์ฒ๋ฆฌ์ NLTKยทspaCy๋ฅผ ํ์ฉํ ํ ์คํธ ๋ง์ด๋ ์์ ์ ๋ณต
ํ์ด์ฌ์ผ๋ก ํ ์คํธ ๋ฐ์ดํฐ ๋ถ์ํ๋ ๋ฒ, ์ง์ง ์ค์ ๋ ธํ์ฐ๊น์ง ๋ค ์๋ ค๋๋ฆผ ใ ใ
๐ ํ ์คํธ ๋ง์ด๋์ด ๋ญ๋ฐ? ์ ์ด๋ ๊ฒ ํซํ๊ฑฐ์ผ?
์์ฆ ๋ฐ์ดํฐ ๋ถ์ ์ชฝ์์ ์ผํ๊ฑฐ๋ ๊ด์ฌ์๋ ์ฌ๋๋ค์ด๋ผ๋ฉด 'ํ
์คํธ ๋ง์ด๋'์ด๋ผ๋ ๋จ์ด ํ ๋ฒ์ฏค์ ๋ค์ด๋ดค์ ๊ฑฐ์ ใ
ใ
๊ทผ๋ฐ ๋ง์ ๋ญ์ง ๋ฌผ์ด๋ณด๋ฉด "์... ํ
์คํธ ๋ถ์ํ๋ ๊ฑฐ?" ์ด ์ ๋๋ก๋ง ์๊ณ ์๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋๋ผ๊ณ .
ํ
์คํธ ๋ง์ด๋(Text Mining)์ ๋น์ ํ ํ
์คํธ ๋ฐ์ดํฐ์์ ์๋ฏธ ์๋ ์ ๋ณด์ ํจํด์ ์ถ์ถํ๋ ๊ธฐ์ ์ด์ผ.
์ฝ๊ฒ ๋งํ๋ฉด ์์ฒญ๋ ์์ ๋ฌธ์, ๋ฆฌ๋ทฐ, SNS ๊ธ, ๋ด์ค ๊ธฐ์ฌ ๊ฐ์ ํ
์คํธ ๋๋ฏธ์์ ์ธ์ฌ์ดํธ๋ฅผ ๋ฝ์๋ด๋ ๊ฑฐ์ง ๐ก
์๋ฅผ ๋ค์ด๋ณผ๊ฒ:
โข ์ผํ๋ชฐ ๋ฆฌ๋ทฐ 10๋ง ๊ฐ๋ฅผ ๋ถ์ํด์ ๊ณ ๊ฐ๋ค์ด ๊ฐ์ฅ ๋ถ๋ง์กฑํ๋ ํฌ์ธํธ ์ฐพ๊ธฐ
โข ํธ์ํฐ ๋ฐ์ดํฐ๋ก ํน์ ๋ธ๋๋์ ๋ํ ๊ฐ์ฑ ๋ถ์ํ๊ธฐ
โข ๋ด์ค ๊ธฐ์ฌ์์ ์ฃผ์ ํค์๋์ ํ ํฝ ์๋ ์ถ์ถํ๊ธฐ
โข ๊ณ ๊ฐ ๋ฌธ์ ๋ด์ฉ์ ์๋ ๋ถ๋ฅํด์ ๋ด๋น ๋ถ์๋ก ๋ผ์ฐํ
ํ๊ธฐ
์ด๋ฐ ๊ฒ๋ค์ด ๋ค ํ
์คํธ ๋ง์ด๋์ ์์ญ์ด์ผ. ์ง์ง ์ค๋ฌด์์ ๊ฐ์ฉ๋ ํ์ฉ๋๋ฅผ ์๋ํ๋ ๊ธฐ์ ์ด๋ผ๊ณ ใ
ใ
2. SNSยท๋ฆฌ๋ทฐ ๋ฌธํ์ ํญ๋ฐ์ ์ฑ์ฅ: ์ฌ๋๋ค์ด ์จ๋ผ์ธ์์ ์๊ฒฌ์ ํํํ๋ ๊ฒ ์ผ์ํ๋๋ฉด์ ๋ถ์ํ ํ ์คํธ ๋ฐ์ดํฐ๊ฐ ๊ธฐํ๊ธ์์ ์ผ๋ก ์ฆ๊ฐ
3. AI ๊ธฐ์ ์ ๋ฐ์ : ์์ฐ์ด ์ฒ๋ฆฌ(NLP) ๊ธฐ์ ์ด ๋ฐ์ ํ๋ฉด์ ์์ ์ ๋ถ๊ฐ๋ฅํ๋ ์์ค์ ํ ์คํธ ์ดํด๊ฐ ๊ฐ๋ฅํด์ง
4. ๋น์ฆ๋์ค ์์ฌ๊ฒฐ์ ์ ํต์ฌ: ๊ณ ๊ฐ์ ๋ชฉ์๋ฆฌ(VOC)๋ฅผ ์ ๋์ ์ผ๋ก ๋ถ์ํด์ ์ ๋ต ์๋ฆฝ์ ํ์ฉํ๋ ๊ฒ ํ์๊ฐ ๋จ
๐ ์์ฐ์ด ์ฒ๋ฆฌ(NLP)์ ๊ธฐ์ด ๊ฐ๋ ๋ถํฐ ์ฐจ๊ทผ์ฐจ๊ทผ
ํ
์คํธ ๋ง์ด๋์ ์ ๋๋ก ์ดํดํ๋ ค๋ฉด ์์ฐ์ด ์ฒ๋ฆฌ(Natural Language Processing, NLP)์ ๋ํ ๊ธฐ๋ณธ ๊ฐ๋
์ด ํ์ํด.
์์ฐ์ด ์ฒ๋ฆฌ๋ ์ปดํจํฐ๊ฐ ์ธ๊ฐ์ ์ธ์ด๋ฅผ ์ดํดํ๊ณ ์ฒ๋ฆฌํ ์ ์๋๋ก ํ๋ ์ธ๊ณต์ง๋ฅ์ ํ ๋ถ์ผ์ผ ๐ค
๊ทผ๋ฐ ์ฌ๊ธฐ์ ๋ฌธ์ ๊ฐ ๋ญ๋๋ฉด, ์ปดํจํฐ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ซ์๋ง ์ดํดํ ์ ์๋ค๋ ๊ฑฐ์ ใ
ใ
ใ
์ฐ๋ฆฌ๊ฐ ์ฐ๋ ํ๊ธ, ์์ด ๊ฐ์ ์์ฐ์ด๋ ์ปดํจํฐ ์
์ฅ์์๋ ๊ทธ๋ฅ ์๋ฏธ ์๋ ๋ฌธ์์ด์ผ ๋ฟ์ด์ง.
๊ทธ๋์ NLP์ ํต์ฌ ๊ณผ์ ๋:
1. ํ
์คํธ๋ฅผ ์ปดํจํฐ๊ฐ ์ดํดํ ์ ์๋ ํํ๋ก ๋ณํํ๊ธฐ
2. ๋ณํ๋ ๋ฐ์ดํฐ๋ก ์๋ฏธ ์๋ ๋ถ์ ์ํํ๊ธฐ
3. ๊ฒฐ๊ณผ๋ฅผ ๋ค์ ์ฌ๋์ด ์ดํดํ ์ ์๋ ํํ๋ก ํํํ๊ธฐ
์ด ์ธ ๊ฐ์ง๋ฅผ ํด๊ฒฐํ๋ ๊ฒ ๋ฐ๋ก ์ฐ๋ฆฌ๊ฐ ๋ฐฐ์ธ NLTK์ spaCy ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ญํ ์ด์ผ ๐ช
| ๋จ๊ณ | ์ค๋ช | ์์ |
|---|---|---|
| ํ ํฐํ (Tokenization) |
ํ ์คํธ๋ฅผ ์๋ฏธ ์๋ ๋จ์๋ก ์ชผ๊ฐ๋ ์์ | "์๋ ํ์ธ์" โ ["์๋ ", "ํ", "์ธ์"] |
| ์ ๊ทํ (Normalization) |
ํ ์คํธ๋ฅผ ์ผ๊ด๋ ํํ๋ก ๋ณํ | "iPhone" โ "iphone" |
| ๋ถ์ฉ์ด ์ ๊ฑฐ (Stopword Removal) |
๋ถ์์ ๋ถํ์ํ ๋จ์ด ์ ๊ฑฐ | "the", "a", "์", "๋" ๋ฑ ์ ๊ฑฐ |
| ์ด๊ฐ ์ถ์ถ (Stemming) |
๋จ์ด๋ฅผ ๊ธฐ๋ณธ ํํ๋ก ์ถ์ฝ | "running" โ "run" |
| ํ์ ์ด ์ถ์ถ (Lemmatization) |
๋จ์ด๋ฅผ ์ฌ์ ์ ๊ธฐ๋ณธํ์ผ๋ก ๋ณํ | "better" โ "good" |
| ํ์ฌ ํ๊น
(POS Tagging) |
๊ฐ ๋จ์ด์ ํ์ฌ ์ ๋ณด ๋ถ์ฌ | "์ฌ๊ณผ" โ ๋ช ์ฌ or ๋์ฌ |
| ๊ฐ์ฒด๋ช
์ธ์ (NER) |
๊ณ ์ ๋ช ์ฌ, ๋ ์ง, ์ฅ์ ๋ฑ ์ธ์ | "์์ธ" โ ์ง๋ช |
์ฐ๋ฆฌ๋ ๊ฐ ๋จ๊ณ๊ฐ ์ ํ์ํ์ง๋ง ์ดํดํ๊ณ , ํ์ํ ๋ ์ ์ ํ ํ์ฉํ๋ฉด ๋ผ!
ํนํ ํ๊ตญ์ด ์ฒ๋ฆฌ๋ ์์ด๋ณด๋ค ํจ์ฌ ๊น๋ค๋ก์ด๋ฐ, ๊ทธ ์ด์ ๋:
1. ๊ต์ฐฉ์ด ํน์ฑ: "๋จน์์ต๋๋ค"์ฒ๋ผ ์ด๊ฐ์ ์ฌ๋ฌ ์ด๋ฏธ๊ฐ ๋ถ์ด์ ์๋ฏธ๊ฐ ๋ณํจ
2. ๋์ด์ฐ๊ธฐ ๋ชจํธ์ฑ: "์๋ฒ์ง๊ฐ๋ฐฉ์๋ค์ด๊ฐ์ ๋ค" ๊ฐ์ ๊ฒฝ์ฐ ๋์ด์ฐ๊ธฐ์ ๋ฐ๋ผ ์๋ฏธ๊ฐ ์์ ํ ๋ฌ๋ผ์ง
3. ๋์์ด์์ด: "๋ฐฐ"๊ฐ ๊ณผ์ผ์ธ์ง, ํ๊ฒ์ธ์ง, ์ ์ฒด๋ถ์์ธ์ง ๋ฌธ๋งฅ์ผ๋ก ํ๋จํด์ผ ํจ
๊ทธ๋์ ํ๊ตญ์ด NLP์๋ KoNLPy, Mecab ๊ฐ์ ์ ์ฉ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ง์ด ์ฐ์ด๋๋ฐ, ์ด๊ฑด ๋์ค์ ๋ ์์ธํ ๋ค๋ค๋ณผ๊ฒ ๐
๐ง NLTK: ์์ฐ์ด ์ฒ๋ฆฌ์ ์ค์์ค ์๋ฏธ ๋์ดํ
NLTK(Natural Language Toolkit)๋ ํ์ด์ฌ์์ ๊ฐ์ฅ ์ ๋ช
ํ NLP ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค ํ๋์ผ.
2001๋
์ ์ฒ์ ๋์์ผ๋๊น ๋ฒ์จ 20๋
์ด ๋์ ๋ฒ ํ
๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ง ใ
ใ
ใ
NLTK์ ๊ฐ์ฅ ํฐ ์ฅ์ ์ ๊ต์ก์ฉ์ผ๋ก ์ค๊ณ๋์ด์ ๋ฐฐ์ฐ๊ธฐ ์ฝ๋ค๋ ๊ฑฐ์ผ.
NLP์ ๊ฑฐ์ ๋ชจ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ฉด์๋, ๊ฐ ๊ธฐ๋ฅ์ด ์ด๋ป๊ฒ ์๋ํ๋์ง ์ดํดํ๊ธฐ ์ฝ๊ฒ ๊ตฌ์ฑ๋์ด ์์ด.
์ค๋ฌด์์๋ ์๋ ๋๋ฌธ์ spaCy๋ฅผ ๋ ๋ง์ด ์ฐ๊ธด ํ์ง๋ง, NLTK๋ ์ฌ์ ํ:
โข NLP ํ์ต์ฉ์ผ๋ก ์ต๊ณ
โข ํ๋กํ ํ์ดํํ ๋ ๋น ๋ฅด๊ฒ ํ
์คํธํ๊ธฐ ์ข์
โข ํน์ ์ธ์ดํ์ ๋ถ์์ด ํ์ํ ๋ ์ ์ฉํจ
์ด๋ฐ ์ด์ ๋ก ๋ง์ด ์ฌ์ฉ๋๊ณ ์์ด ๐
NLTK ์ค์น๋ ์ง์ง ๊ฐ๋จํจ. pip๋ก ํ ๋ฐฉ์ด์ผ:
pip install nltk
์ค์น ํ์๋ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ๋ค์ด๋ก๋ํด์ผ ํ๋๋ฐ, ์ด๊ฒ๋ ์ฝ๋ ๋ช ์ค์ด๋ฉด ๋:
import nltk
# ๊ธฐ๋ณธ ๋ฐ์ดํฐ ๋ค์ด๋ก๋
nltk.download('punkt') # ํ ํฐํ ๋๊ตฌ
nltk.download('stopwords') # ๋ถ์ฉ์ด ์ฌ์
nltk.download('averaged_perceptron_tagger') # ํ์ฌ ํ๊ฑฐ
nltk.download('wordnet') # WordNet ์ฌ์
nltk.download('omw-1.4') # ๋ค๊ตญ์ด WordNet
# ๋๋ ์ ์ฒด ๋ค์ด๋ก๋ (์ฉ๋ ํผ, ์๊ฐ ๊ฑธ๋ฆผ)
# nltk.download('all')
์ฒ์์ ํ์ํ ๊ฒ๋ง ๊ฐ๋ณ์ ์ผ๋ก ๋ค์ด๋ก๋ํ๋ ๊ฒ ์ข์. ๋์ค์ ์๋ฌ ๋๋ฉด ๊ทธ๋๊ทธ๋ ์ถ๊ฐ๋ก ๋ฐ์ผ๋ฉด ๋จ ใ ใ
์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก NLTK๋ก ๋ญ ํ ์ ์๋์ง ์ฝ๋์ ํจ๊ป ์์๋ณด์!
1๏ธโฃ ํ ํฐํ(Tokenization)
ํ ํฐํ๋ ํ
์คํธ๋ฅผ ๋ฌธ์ฅ์ด๋ ๋จ์ด ๋จ์๋ก ์ชผ๊ฐ๋ ์์
์ด์ผ.
NLTK๋ ์ฌ๋ฌ ์ข
๋ฅ์ ํ ํฌ๋์ด์ ๋ฅผ ์ ๊ณตํ๋๋ฐ, ์ํฉ์ ๋ง๊ฒ ๊ณจ๋ผ ์ฐ๋ฉด ๋ผ:
from nltk.tokenize import word_tokenize, sent_tokenize, TreebankWordTokenizer
text = "์๋
ํ์ธ์! NLTK๋ฅผ ๋ฐฐ์ฐ๊ณ ์์ต๋๋ค. ์ ๋ง ์ฌ๋ฏธ์๋ค์ ใ
ใ
"
# ๋ฌธ์ฅ ํ ํฐํ
sentences = sent_tokenize(text)
print("๋ฌธ์ฅ ํ ํฐํ:", sentences)
# ์ถ๋ ฅ: ['์๋
ํ์ธ์!', 'NLTK๋ฅผ ๋ฐฐ์ฐ๊ณ ์์ต๋๋ค.', '์ ๋ง ์ฌ๋ฏธ์๋ค์ ใ
ใ
']
# ๋จ์ด ํ ํฐํ
words = word_tokenize(text)
print("๋จ์ด ํ ํฐํ:", words)
# ์ถ๋ ฅ: ['์๋
ํ์ธ์', '!', 'NLTK๋ฅผ', '๋ฐฐ์ฐ๊ณ ', '์์ต๋๋ค', '.', '์ ๋ง', '์ฌ๋ฏธ์๋ค์', 'ใ
ใ
']
# ์์ด ํ
์คํธ ์์
eng_text = "I can't believe it's already 2024! Time flies."
eng_words = word_tokenize(eng_text)
print("์์ด ํ ํฐํ:", eng_words)
# ์ถ๋ ฅ: ['I', 'ca', "n't", 'believe', 'it', "'s", 'already', '2024', '!', 'Time', 'flies', '.']
๋ณด๋ฉด ์๊ฒ ์ง๋ง NLTK์ ๊ธฐ๋ณธ ํ ํฌ๋์ด์ ๋ ์์ด์ ์ต์ ํ๋์ด ์์ด.
ํ๊ตญ์ด๋ ์ข ์ด์ํ๊ฒ ๋์ฌ ์ ์๋๋ฐ, ์ด๊ฑด ๋์ค์ KoNLPy ๊ฐ์ ํ๊ตญ์ด ์ ์ฉ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋ณด์ํ ์ ์์ ๐
2๏ธโฃ ๋ถ์ฉ์ด(Stopwords) ์ ๊ฑฐ
๋ถ์ฉ์ด๋ "the", "a", "is" ๊ฐ์ด ์์ฃผ ๋์ค์ง๋ง ๋ถ์์๋ ํฐ ์๋ฏธ๊ฐ ์๋ ๋จ์ด๋ค์ด์ผ.
์ด๋ฐ ๊ฑธ ์ ๊ฑฐํ๋ฉด ๋ถ์ ์ ํ๋๊ฐ ์ฌ๋ผ๊ฐ๊ณ ์ฒ๋ฆฌ ์๋๋ ๋นจ๋ผ์ง:
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
# ์์ด ๋ถ์ฉ์ด ๋ชฉ๋ก ๊ฐ์ ธ์ค๊ธฐ
stop_words = set(stopwords.words('english'))
print(f"์์ด ๋ถ์ฉ์ด ๊ฐ์: {len(stop_words)}๊ฐ")
print("๋ถ์ฉ์ด ์์:", list(stop_words)[:10])
# ๋ถ์ฉ์ด ์ ๊ฑฐ ์ค์ต
text = "This is a sample sentence demonstrating the removal of stop words."
words = word_tokenize(text.lower())
filtered_words = [word for word in words if word not in stop_words and word.isalpha()]
print("์๋ณธ:", words)
print("๋ถ์ฉ์ด ์ ๊ฑฐ ํ:", filtered_words)
# ์ถ๋ ฅ: ['sample', 'sentence', 'demonstrating', 'removal', 'stop', 'words']
์๋ฅผ ๋ค์ด ์ํ ๋ฆฌ๋ทฐ ๋ถ์์ด๋ผ๋ฉด "movie", "film" ๊ฐ์ ๋จ์ด๋ ๋๋ฌด ํํด์ ๋ถ์ฉ์ด๋ก ์ถ๊ฐํ ์๋ ์๊ณ ,
๋ฐ๋๋ก ๊ฐ์ฑ ๋ถ์์์๋ "not", "no" ๊ฐ์ ๋ถ์ ์ด๋ ๋ถ์ฉ์ด์์ ์ ์ธํด์ผ ํจ!
3๏ธโฃ ์ด๊ฐ ์ถ์ถ(Stemming)๊ณผ ํ์ ์ด ์ถ์ถ(Lemmatization)
์ด ๋์ ๋น์ทํด ๋ณด์ด์ง๋ง ์ ๊ทผ ๋ฐฉ์์ด ๋ค๋ฅธ ๊ธฐ์ ์ด์ผ:
from nltk.stem import PorterStemmer, LancasterStemmer, WordNetLemmatizer
from nltk.corpus import wordnet
# Stemming (์ด๊ฐ ์ถ์ถ)
porter = PorterStemmer()
lancaster = LancasterStemmer()
words = ["running", "runs", "ran", "runner", "easily", "fairly"]
print("Porter Stemmer:")
for word in words:
print(f"{word} โ {porter.stem(word)}")
print("\nLancaster Stemmer:")
for word in words:
print(f"{word} โ {lancaster.stem(word)}")
# Lemmatization (ํ์ ์ด ์ถ์ถ)
lemmatizer = WordNetLemmatizer()
print("\nLemmatization:")
print(f"running (๋์ฌ) โ {lemmatizer.lemmatize('running', pos='v')}")
print(f"running (๋ช
์ฌ) โ {lemmatizer.lemmatize('running', pos='n')}")
print(f"better (ํ์ฉ์ฌ) โ {lemmatizer.lemmatize('better', pos='a')}")
print(f"cacti (๋ช
์ฌ) โ {lemmatizer.lemmatize('cacti', pos='n')}")
Stemming vs Lemmatization ์ฐจ์ด์ :
Stemming: ๊ท์น ๊ธฐ๋ฐ์ผ๋ก ๋จ์ด ๋์ ์๋ผ๋. ๋น ๋ฅด์ง๋ง ๋ถ์ ํํ ์ ์์
โข "running" โ "run" โ
โข "better" โ "better" โ (good์ผ๋ก ๋ชป ๋ฐ๊ฟ)
Lemmatization: ์ฌ์ ๊ธฐ๋ฐ์ผ๋ก ์ ํํ ๊ธฐ๋ณธํ ์ฐพ์. ๋๋ฆฌ์ง๋ง ์ ํํจ
โข "running" โ "run" โ
โข "better" โ "good" โ
์ค๋ฌด์์๋ ์ ํ๋๊ฐ ์ค์ํ๋ฉด Lemmatization, ์๋๊ฐ ์ค์ํ๋ฉด Stemming์ ์ฐ๋ ํธ์ด์ผ ใ
ใ
4๏ธโฃ ํ์ฌ ํ๊น (POS Tagging)
ํ์ฌ ํ๊น
์ ๊ฐ ๋จ์ด๊ฐ ๋ช
์ฌ์ธ์ง, ๋์ฌ์ธ์ง, ํ์ฉ์ฌ์ธ์ง ๋ฑ์ ํ๋ณํ๋ ์์
์ด์ผ.
์ด๊ฒ ์ ์ค์ํ๋๋ฉด, ๊ฐ์ ๋จ์ด๋ ํ์ฌ์ ๋ฐ๋ผ ์๋ฏธ๊ฐ ์์ ํ ๋ฌ๋ผ์ง๊ฑฐ๋ :
from nltk import pos_tag
from nltk.tokenize import word_tokenize
# ํ์ฌ ํ๊น
์์
text1 = "They refuse to permit us to obtain the refuse permit."
words1 = word_tokenize(text1)
pos_tags1 = pos_tag(words1)
print("ํ์ฌ ํ๊น
๊ฒฐ๊ณผ:")
for word, tag in pos_tags1:
print(f"{word}: {tag}")
# ์ฃผ์ ํ์ฌ ํ๊ทธ ์ค๋ช
# NN: ๋ช
์ฌ(๋จ์), NNS: ๋ช
์ฌ(๋ณต์), NNP: ๊ณ ์ ๋ช
์ฌ
# VB: ๋์ฌ(๊ธฐ๋ณธํ), VBD: ๋์ฌ(๊ณผ๊ฑฐํ), VBG: ๋์ฌ(ํ์ฌ๋ถ์ฌ)
# JJ: ํ์ฉ์ฌ, RB: ๋ถ์ฌ
# DT: ๊ด์ฌ, IN: ์ ์น์ฌ
2. ์ ๋ณด ์ถ์ถ: ๊ณ ์ ๋ช ์ฌ(NNP)๋ฅผ ์ฐพ์์ ์ธ๋ฌผ, ์ฅ์, ์กฐ์ง๋ช ์ถ์ถ
3. ํค์๋ ์ถ์ถ: ๋ช ์ฌ์ ํ์ฉ์ฌ ์กฐํฉ์ผ๋ก ์๋ฏธ ์๋ ํค์๋ ๋ฐ๊ตด
4. ๋ฌธ๋ฒ ๊ฒ์ฌ: ํ์ฌ ํจํด์ ๋ถ์ํด์ ๋ฌธ๋ฒ ์ค๋ฅ ํ์ง
5๏ธโฃ ๊ฐ์ฒด๋ช ์ธ์(Named Entity Recognition)
๊ฐ์ฒด๋ช ์ธ์์ ํ ์คํธ์์ ์ฌ๋ ์ด๋ฆ, ์ง๋ช , ์กฐ์ง๋ช , ๋ ์ง ๋ฑ์ ์๋์ผ๋ก ์ฐพ์๋ด๋ ๊ธฐ์ ์ด์ผ:
from nltk import ne_chunk, pos_tag, word_tokenize
from nltk.tree import Tree
text = "Apple Inc. was founded by Steve Jobs in Cupertino, California on April 1, 1976."
words = word_tokenize(text)
pos_tags = pos_tag(words)
named_entities = ne_chunk(pos_tags)
print("๊ฐ์ฒด๋ช
์ธ์ ๊ฒฐ๊ณผ:")
for chunk in named_entities:
if isinstance(chunk, Tree):
entity = " ".join([token for token, pos in chunk.leaves()])
entity_type = chunk.label()
print(f"{entity}: {entity_type}")
# ์ถ๋ ฅ ์์:
# Apple Inc.: ORGANIZATION
# Steve Jobs: PERSON
# Cupertino: GPE (์ง์ ํ์ ๊ฐ์ฒด)
# California: GPE
๊ฐ์ฒด๋ช
์ธ์์ ๋ด์ค ๊ธฐ์ฌ ๋ถ์, ๋ฌธ์ ์๋ ๋ถ๋ฅ, ์ฑ๋ด ๊ฐ๋ฐ ๋ฑ์์ ์์ฒญ ์ ์ฉํ๊ฒ ์ฐ์ฌ.
ํนํ ๋๋์ ๋ฌธ์์์ ํน์ ์ธ๋ฌผ์ด๋ ์กฐ์ง์ ๋ํ ์ธ๊ธ์ ์ถ์ ํ ๋ ๊ฐ๊ฟ์ ใ
ใ
ใ
โก spaCy: ์ฐ์ ์ฉ NLP์ ๊ฐ์
NLTK๊ฐ ๊ต์ก์ฉ ์ค์์ค ์๋ฏธ ๋์ดํ๋ผ๋ฉด, spaCy๋ ์ค์ ์ฉ ํ์ํด์ด๋ผ๊ณ ํ ์ ์์ด.
2015๋
์ ๋์จ ๋น๊ต์ ์ต์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ๋ฐ, ์๋์ ์ ํ๋ ๋ฉด์์ NLTK๋ฅผ ์๋ํ๋ ์ฑ๋ฅ์ ๋ณด์ฌ์ค ๐
spaCy์ ํต์ฌ ํน์ง:
1. ์๋์ ์ธ ์๋: Cython์ผ๋ก ์์ฑ๋์ด NLTK๋ณด๋ค ์์ญ ๋ฐฐ ๋น ๋ฆ
2. ๋ฅ๋ฌ๋ ๊ธฐ๋ฐ: ์ต์ ์ ๊ฒฝ๋ง ๋ชจ๋ธ์ ํ์ฉํ ๋์ ์ ํ๋
3. ํ๋ก๋์
๋ ๋: ์ค์ ์๋น์ค์ ๋ฐ๋ก ์ ์ฉ ๊ฐ๋ฅํ ์์ ์ฑ
4. ๋ค๊ตญ์ด ์ง์: 60๊ฐ ์ด์์ ์ธ์ด ๋ชจ๋ธ ์ ๊ณต
5. ํ์ดํ๋ผ์ธ ๊ตฌ์กฐ: ์ฌ๋ฌ ์ฒ๋ฆฌ ๋จ๊ณ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฐ๊ฒฐ
์ค๋ฌด์์ ๋์ฉ๋ ํ
์คํธ๋ฅผ ์ฒ๋ฆฌํด์ผ ํ๋ค๋ฉด spaCy๊ฐ ๊ฑฐ์ ํ์๋ผ๊ณ ๋ด๋ ๋จ ๐ช
# spaCy ์ค์น
pip install spacy
# ์์ด ๋ชจ๋ธ ๋ค์ด๋ก๋ (ํฌ๊ธฐ๋ณ๋ก 3๊ฐ์ง)
python -m spacy download en_core_web_sm # ์ํ (12MB)
python -m spacy download en_core_web_md # ์คํ (40MB)
python -m spacy download en_core_web_lg # ๋ํ (560MB)
# ํ๊ตญ์ด ๋ชจ๋ธ (๋น๊ณต์, ์ฑ๋ฅ ์ ํ์ )
pip install spacy-korean
โข md (medium): ๊ท ํ์กํ ์ฑ๋ฅ, ์ผ๋ฐ์ ์ธ ์ฉ๋์ ์ถ์ฒ
โข lg (large): ์ต๊ณ ์ ํ๋, ๋จ์ด ๋ฒกํฐ ํฌํจ, ๋ฉ๋ชจ๋ฆฌ ์ฌ์ ์์ ๋
์ฒ์์ sm์ผ๋ก ์์ํด์ ํ์ํ๋ฉด ์ ๊ทธ๋ ์ด๋ํ๋ ๊ฒ ์ข์!
1๏ธโฃ ๊ธฐ๋ณธ ํ์ดํ๋ผ์ธ ์ฌ์ฉ๋ฒ
spaCy์ ๊ฐ์ฅ ํฐ ํน์ง์ ํ ๋ฒ์ ์ฒ๋ฆฌ๋ก ํ ํฐํ, ํ์ฌ ํ๊น , ๊ฐ์ฒด๋ช ์ธ์ ๋ฑ์ ๋ชจ๋ ์ํํ๋ค๋ ๊ฑฐ์ผ:
import spacy
# ๋ชจ๋ธ ๋ก๋
nlp = spacy.load("en_core_web_sm")
# ํ
์คํธ ์ฒ๋ฆฌ
text = "Apple is looking at buying U.K. startup for $1 billion"
doc = nlp(text)
# ํ ํฐ ์ ๋ณด ์ถ๋ ฅ
print("ํ ํฐ ๋ถ์:")
for token in doc:
print(f"{token.text:12} {token.pos_:8} {token.dep_:10} {token.lemma_}")
# ๊ฐ์ฒด๋ช
์ธ์
print("\n๊ฐ์ฒด๋ช
:")
for ent in doc.ents:
print(f"{ent.text:20} {ent.label_:15} {spacy.explain(ent.label_)}")
์ด ์ฝ๋ ํ ๋ฒ ์คํํ๋ฉด:
โข ํ ํฐํ โ
โข ํ์ฌ ํ๊น
โ
โข ์์กด ๊ตฌ๋ฌธ ๋ถ์ โ
โข ํ์ ์ด ์ถ์ถ โ
โข ๊ฐ์ฒด๋ช
์ธ์ โ
์ด ๋ชจ๋ ๊ฒ ๋์์ ์ฒ๋ฆฌ๋จ. NLTK๋ก ํ๋ ค๋ฉด ๊ฐ๊ฐ ๋ฐ๋ก ํจ์ ํธ์ถํด์ผ ํ๋๋ฐ spaCy๋ ์์ท์ด์ผ ใ
ใ
ใ
2๏ธโฃ ๋ฌธ์ฅ ๋ถ๋ฆฌ์ ํ ํฐ ์์ฑ
import spacy
nlp = spacy.load("en_core_web_sm")
text = """
spaCy is amazing! It can process text super fast.
Let's see how it handles multiple sentences.
"""
doc = nlp(text)
# ๋ฌธ์ฅ ๋ถ๋ฆฌ
print("๋ฌธ์ฅ ๋ถ๋ฆฌ:")
for i, sent in enumerate(doc.sents, 1):
print(f"{i}. {sent.text.strip()}")
# ํ ํฐ ์์ธ ์์ฑ
print("\nํ ํฐ ์์ธ ๋ถ์:")
for token in doc[:10]: # ์ฒ์ 10๊ฐ๋ง
print(f"""
ํ
์คํธ: {token.text}
ํ์ ์ด: {token.lemma_}
ํ์ฌ: {token.pos_} ({spacy.explain(token.pos_)})
ํ๊ทธ: {token.tag_}
์์กด๊ด๊ณ: {token.dep_}
๋ถ์ฉ์ด ์ฌ๋ถ: {token.is_stop}
๊ตฌ๋์ ์ฌ๋ถ: {token.is_punct}
์ซ์ ์ฌ๋ถ: {token.like_num}
""")
spaCy์ ํ ํฐ ๊ฐ์ฒด๋ ์ง์ง ์ ๋ณด๊ฐ ํ๋ถํจ.
๊ฐ ํ ํฐ๋ง๋ค 20๊ฐ ์ด์์ ์์ฑ์ ์ ๊ณตํด์ ์ฌ๋งํ ๋ถ์์ ๋ค ๊ฐ๋ฅํด ๐
3๏ธโฃ ๋จ์ด ๋ฒกํฐ์ ์ ์ฌ๋ ๊ณ์ฐ
md๋ lg ๋ชจ๋ธ์ ์ฌ์ฉํ๋ฉด ๋จ์ด๋ฅผ ๋ฒกํฐ๋ก ํํํด์ ์๋ฏธ์ ์ ์ฌ๋๋ฅผ ๊ณ์ฐํ ์ ์์ด:
import spacy
# ๋ฒกํฐ๊ฐ ํฌํจ๋ ๋ชจ๋ธ ํ์ (md ๋๋ lg)
nlp = spacy.load("en_core_web_md")
# ๋จ์ด ์ ์ฌ๋
doc1 = nlp("dog")
doc2 = nlp("cat")
doc3 = nlp("banana")
print(f"dog vs cat: {doc1.similarity(doc2):.4f}")
print(f"dog vs banana: {doc1.similarity(doc3):.4f}")
print(f"cat vs banana: {doc2.similarity(doc3):.4f}")
# ๋ฌธ์ฅ ์ ์ฌ๋
sent1 = nlp("I love programming in Python")
sent2 = nlp("Python is my favorite programming language")
sent3 = nlp("I enjoy eating pizza")
print(f"\n๋ฌธ์ฅ ์ ์ฌ๋:")
print(f"sent1 vs sent2: {sent1.similarity(sent2):.4f}")
print(f"sent1 vs sent3: {sent1.similarity(sent3):.4f}")
์ด ๊ธฐ๋ฅ์ ์ถ์ฒ ์์คํ
, ๋ฌธ์ ๋ถ๋ฅ, ์ค๋ณต ํ์ง ๋ฑ์์ ์์ฒญ ์ ์ฉํ๊ฒ ์ฐ์ฌ.
์๋ฅผ ๋ค์ด ๊ณ ๊ฐ ๋ฌธ์๋ฅผ ์๋์ผ๋ก ๋ถ๋ฅํ ๋, ์๋ก์ด ๋ฌธ์์ ๊ธฐ์กด ์นดํ
๊ณ ๋ฆฌ์ ์ ์ฌ๋๋ฅผ ๊ณ์ฐํด์ ์๋ ๋ฐฐ์ ํ ์ ์์!
4๏ธโฃ ์ปค์คํ ํ์ดํ๋ผ์ธ ์ปดํฌ๋ํธ
spaCy์ ์ง์ง ๊ฐ๋ ฅํ ๊ธฐ๋ฅ ์ค ํ๋๋ ํ์ดํ๋ผ์ธ์ ์ปค์คํฐ๋ง์ด์งํ ์ ์๋ค๋ ๊ฑฐ์ผ:
import spacy
from spacy.language import Language
nlp = spacy.load("en_core_web_sm")
# ์ปค์คํ
์ปดํฌ๋ํธ ์ ์
@Language.component("custom_sentiment")
def custom_sentiment_component(doc):
# ๊ฐ๋จํ ๊ฐ์ฑ ๋ถ์ ๋ก์ง
positive_words = {"good", "great", "excellent", "amazing", "wonderful"}
negative_words = {"bad", "terrible", "awful", "horrible", "poor"}
pos_count = sum(1 for token in doc if token.text.lower() in positive_words)
neg_count = sum(1 for token in doc if token.text.lower() in negative_words)
# ๋ฌธ์์ ์ปค์คํ
์์ฑ ์ถ๊ฐ
doc._.sentiment_score = pos_count - neg_count
doc._.sentiment = "positive" if pos_count > neg_count else "negative" if neg_count > pos_count else "neutral"
return doc
# ์ปค์คํ
์์ฑ ๋ฑ๋ก
from spacy.tokens import Doc
Doc.set_extension("sentiment_score", default=0, force=True)
Doc.set_extension("sentiment", default="neutral", force=True)
# ํ์ดํ๋ผ์ธ์ ์ถ๊ฐ
nlp.add_pipe("custom_sentiment", last=True)
# ํ
์คํธ
texts = [
"This product is amazing and wonderful!",
"Terrible experience, very bad service.",
"It's okay, nothing special."
]
for text in texts:
doc = nlp(text)
print(f"ํ
์คํธ: {text}")
print(f"๊ฐ์ฑ: {doc._.sentiment} (์ ์: {doc._.sentiment_score})\n")
์ด๋ฐ ์์ผ๋ก ์๊ธฐ๋ง์ ๋ถ์ ๋ก์ง์ ํ์ดํ๋ผ์ธ์ ๋ผ์๋ฃ์ ์ ์์ด.
์ค๋ฌด์์๋ ๋๋ฉ์ธ ํนํ ๊ท์น์ด๋ ๋น์ฆ๋์ค ๋ก์ง์ ์ด๋ ๊ฒ ์ถ๊ฐํด์ ์ฐ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ ใ
ใ
| ํญ๋ชฉ | NLTK | spaCy |
|---|---|---|
| ์๋ | ๋๋ฆผ (์์ Python) | ๋งค์ฐ ๋น ๋ฆ (Cython) |
| ์ ํ๋ | ๋ณดํต | ๋์ (๋ฅ๋ฌ๋ ๊ธฐ๋ฐ) |
| ํ์ต ๊ณก์ | ์๋งํจ | ์ฝ๊ฐ ๊ฐํ๋ฆ |
| ์ฉ๋ | ๊ต์ก, ์ฐ๊ตฌ, ํ๋กํ ํ์ | ํ๋ก๋์ , ๋์ฉ๋ ์ฒ๋ฆฌ |
| ์ ์ฐ์ฑ | ๋งค์ฐ ๋์ | ์ค๊ฐ (ํ์ดํ๋ผ์ธ ๊ตฌ์กฐ) |
| ๋ฌธ์ํ | ํ๋ถํจ | ๋งค์ฐ ํ๋ถํจ |
| ์ปค๋ฎค๋ํฐ | ํฌ๊ณ ์ค๋๋จ | ๋น ๋ฅด๊ฒ ์ฑ์ฅ ์ค |
๊ฒฐ๋ก : ๋ฐฐ์ฐ๋ ๋จ๊ณ์์๋ NLTK๋ก ๊ฐ๋ ์ก๊ณ , ์ค์ ์์๋ spaCy ์ฐ๋ ๊ฒ ๋ฒ ์คํธ ์กฐํฉ!
๐ ํ ์คํธ ๋ง์ด๋ ์ค์ ํ๋ก์ ํธ: ์ํ ๋ฆฌ๋ทฐ ๊ฐ์ฑ ๋ถ์
์ด๋ก ๋ง ๋ฐฐ์ฐ๋ฉด ์ฌ๋ฏธ์์ผ๋๊น, ์ด์ ์ค์ ๋ก ํ
์คํธ ๋ง์ด๋ ํ๋ก์ ํธ๋ฅผ ์ฒ์๋ถํฐ ๋๊น์ง ํด๋ณด์!
์ํ ๋ฆฌ๋ทฐ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ๊ธ์ /๋ถ์ ์ ์๋์ผ๋ก ๋ถ๋ฅํ๋ ๊ฐ์ฑ ๋ถ์ ์์คํ
์ ๋ง๋ค์ด๋ณผ ๊ฑฐ์ผ ๐ฌ
์ด ํ๋ก์ ํธ๋ฅผ ํตํด ๋ฐฐ์ธ ๋ด์ฉ:
โข ์ค์ ๋ฐ์ดํฐ ์์ง ๋ฐ ์ ์ฒ๋ฆฌ
โข NLTK์ spaCy๋ฅผ ํ์ฉํ ํ
์คํธ ์ ์
โข ํน์ง ์ถ์ถ (Feature Extraction)
โข ๋จธ์ ๋ฌ๋ ๋ชจ๋ธ ํ์ต ๋ฐ ํ๊ฐ
โข ๊ฒฐ๊ณผ ์๊ฐํ
์ค์ต์ฉ์ผ๋ก IMDB ์ํ ๋ฆฌ๋ทฐ ๋ฐ์ดํฐ์ ์ ์ฌ์ฉํ ๊ฑฐ์ผ. ์ด๊ฑด 50,000๊ฐ์ ๋ฆฌ๋ทฐ๊ฐ ์๋ ์ ๋ช ํ ๋ฐ์ดํฐ์ ์:
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
# ๋ฐ์ดํฐ ๋ก๋ (์ค์ ๋ก๋ ํ์ผ์์ ์ฝ์ด์ด)
# ์ฌ๊ธฐ์๋ ์์ ๋ฐ์ดํฐ ์์ฑ
sample_reviews = [
("This movie was absolutely amazing! Best film I've seen this year.", "positive"),
("Terrible waste of time. I want my money back.", "negative"),
("Great acting and wonderful storyline. Highly recommended!", "positive"),
("Boring and predictable. Fell asleep halfway through.", "negative"),
("Masterpiece! The director outdid himself.", "positive"),
("Awful movie. Poor acting and terrible script.", "negative"),
]
# DataFrame ์์ฑ
df = pd.DataFrame(sample_reviews, columns=['review', 'sentiment'])
# ์ค์ ํ๋ก์ ํธ์์๋ ์ด๋ ๊ฒ ๋ก๋
# df = pd.read_csv('IMDB_Dataset.csv')
print(f"์ ์ฒด ๋ฆฌ๋ทฐ ์: {len(df)}")
print(f"๊ธ์ ๋ฆฌ๋ทฐ: {len(df[df['sentiment']=='positive'])}")
print(f"๋ถ์ ๋ฆฌ๋ทฐ: {len(df[df['sentiment']=='negative'])}")
print("\n์ํ ๋ฐ์ดํฐ:")
print(df.head())
์์ ํ ์คํธ๋ฅผ ๋ถ์ ๊ฐ๋ฅํ ํํ๋ก ์ ์ ํ๋ ๋จ๊ณ์ผ. ์ฌ๊ธฐ์ NLTK์ spaCy๊ฐ ํ์ฝํจ:
import re
import spacy
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
# spaCy ๋ชจ๋ธ ๋ก๋
nlp = spacy.load("en_core_web_sm")
# ๋ถ์ฉ์ด ์ธํธ
stop_words = set(stopwords.words('english'))
def preprocess_text(text):
"""ํ
์คํธ ์ ์ฒ๋ฆฌ ํจ์"""
# 1. ์๋ฌธ์ ๋ณํ
text = text.lower()
# 2. HTML ํ๊ทธ ์ ๊ฑฐ
text = re.sub(r'<.*?>', '', text)
# 3. URL ์ ๊ฑฐ
text = re.sub(r'http\S+|www\S+', '', text)
# 4. ํน์๋ฌธ์ ์ ๊ฑฐ (์ํ๋ฒณ๊ณผ ๊ณต๋ฐฑ๋ง ๋จ๊น)
text = re.sub(r'[^a-zA-Z\s]', '', text)
# 5. spaCy๋ก ์ฒ๋ฆฌ
doc = nlp(text)
# 6. ํ์ ์ด ์ถ์ถ + ๋ถ์ฉ์ด ์ ๊ฑฐ
tokens = [
token.lemma_ for token in doc
if not token.is_stop
and not token.is_punct
and len(token.text) > 2
]
return ' '.join(tokens)
# ์ ์ฒ๋ฆฌ ์ ์ฉ
df['cleaned_review'] = df['review'].apply(preprocess_text)
print("์ ์ฒ๋ฆฌ ์ ํ ๋น๊ต:")
for i in range(3):
print(f"\n์๋ณธ: {df['review'].iloc[i]}")
print(f"์ ์ฒ๋ฆฌ ํ: {df['cleaned_review'].iloc[i]}")
โข ๊ฐ์ฑ ๋ถ์: ์ด๋ชจํฐ์ฝ, ๋๋ํ ๋ฑ์ ์ ์งํ๋ ๊ฒ ์ข์ ์ ์์
โข ํ ํฝ ๋ชจ๋ธ๋ง: ๋ช ์ฌ ์์ฃผ๋ก ์ถ์ถ
โข ๋ฌธ์ ๋ถ๋ฅ: ๊ณ ์ ๋ช ์ฌ๋ ์ค์ํ๋ ๋ณด์กด
๋ฌด์กฐ๊ฑด ๋ง์ด ์ ๊ฑฐํ๋ค๊ณ ์ข์ ๊ฒ ์๋๋ผ, ๋ถ์ ๋ชฉ์ ์ ๋ง๊ฒ ์กฐ์ ํ๋ ๊ฒ ํต์ฌ!
๋จธ์ ๋ฌ๋ ๋ชจ๋ธ์ ์ซ์๋ง ์ดํดํ ์ ์์ผ๋๊น, ํ
์คํธ๋ฅผ ์ซ์ ๋ฒกํฐ๋ก ๋ณํํด์ผ ํด.
๋ํ์ ์ธ ๋ฐฉ๋ฒ์ด TF-IDF์ผ:
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split
# TF-IDF ๋ฒกํฐ๋ผ์ด์ ์์ฑ
tfidf = TfidfVectorizer(
max_features=5000, # ์์ 5000๊ฐ ๋จ์ด๋ง ์ฌ์ฉ
ngram_range=(1, 2), # 1-gram๊ณผ 2-gram ๋ชจ๋ ์ฌ์ฉ
min_df=2, # ์ต์ 2๋ฒ ์ด์ ๋ฑ์ฅํ ๋จ์ด๋ง
max_df=0.8 # 80% ์ด์ ๋ฌธ์์ ๋ฑ์ฅํ๋ ๋จ์ด ์ ์ธ
)
# ํน์ง ๋ฒกํฐ ์์ฑ
X = tfidf.fit_transform(df['cleaned_review'])
y = df['sentiment'].map({'positive': 1, 'negative': 0})
# ํ์ต/ํ
์คํธ ๋ฐ์ดํฐ ๋ถ๋ฆฌ
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
print(f"ํ์ต ๋ฐ์ดํฐ: {X_train.shape}")
print(f"ํ
์คํธ ๋ฐ์ดํฐ: {X_test.shape}")
print(f"ํน์ง ๋ฒกํฐ ์ฐจ์: {X.shape[1]}")
# ๊ฐ์ฅ ์ค์ํ ๋จ์ด๋ค ํ์ธ
feature_names = tfidf.get_feature_names_out()
print(f"\n์ถ์ถ๋ ํน์ง ์์: {feature_names[:20]}")
โข TF (Term Frequency): ํน์ ๋ฌธ์์์ ๋จ์ด๊ฐ ์ผ๋ง๋ ์์ฃผ ๋์ค๋๊ฐ
โข IDF (Inverse Document Frequency): ์ ์ฒด ๋ฌธ์์์ ๋จ์ด๊ฐ ์ผ๋ง๋ ํฌ๊ทํ๊ฐ
ํต์ฌ ์์ด๋์ด: ํน์ ๋ฌธ์์์ ์์ฃผ ๋์ค์ง๋ง ๋ค๋ฅธ ๋ฌธ์์์๋ ์ ์ ๋์ค๋ ๋จ์ด๊ฐ ๊ทธ ๋ฌธ์๋ฅผ ๋ํํ๋ ์ค์ํ ๋จ์ด!
์๋ฅผ ๋ค์ด "์ํ"๋ผ๋ ๋จ์ด๋ ๋ชจ๋ ์ํ ๋ฆฌ๋ทฐ์ ๋์ค๋๊น ์ค์๋๊ฐ ๋ฎ๊ณ ,
"์ค๋ฆด๋ฌ"๋ ํน์ ์ฅ๋ฅด ๋ฆฌ๋ทฐ์๋ง ๋์ค๋๊น ์ค์๋๊ฐ ๋์์ง๋ ์์ด์ผ ใ ใ
์ด์ ์ฌ๋ฌ ๋จธ์ ๋ฌ๋ ๋ชจ๋ธ์ ํ์ต์์ผ์ ์ฑ๋ฅ์ ๋น๊ตํด๋ณด์:
from sklearn.naive_bayes import MultinomialNB
from sklearn.linear_model import LogisticRegression
from sklearn.svm import LinearSVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
# ์ฌ๋ฌ ๋ชจ๋ธ ์ ์
models = {
'Naive Bayes': MultinomialNB(),
'Logistic Regression': LogisticRegression(max_iter=1000),
'Linear SVM': LinearSVC(max_iter=1000),
'Random Forest': RandomForestClassifier(n_estimators=100, random_state=42)
}
# ๊ฐ ๋ชจ๋ธ ํ์ต ๋ฐ ํ๊ฐ
results = {}
for name, model in models.items():
print(f"\n{'='*50}")
print(f"๋ชจ๋ธ: {name}")
print('='*50)
# ํ์ต
model.fit(X_train, y_train)
# ์์ธก
y_pred = model.predict(X_test)
# ํ๊ฐ
accuracy = accuracy_score(y_test, y_pred)
results[name] = accuracy
print(f"์ ํ๋: {accuracy:.4f}")
print("\n๋ถ๋ฅ ๋ฆฌํฌํธ:")
print(classification_report(y_test, y_pred,
target_names=['Negative', 'Positive']))
print("\nํผ๋ ํ๋ ฌ:")
print(confusion_matrix(y_test, y_pred))
# ์ต๊ณ ์ฑ๋ฅ ๋ชจ๋ธ
best_model = max(results, key=results.get)
print(f"\n๐ ์ต๊ณ ์ฑ๋ฅ ๋ชจ๋ธ: {best_model} (์ ํ๋: {results[best_model]:.4f})")
๋ชจ๋ธ์ด ์ด๋ค ๋จ์ด๋ฅผ ์ค์ํ๊ฒ ์๊ฐํ๋์ง ํ์ธํด๋ณด์:
import numpy as np
import matplotlib.pyplot as plt
# Logistic Regression ๋ชจ๋ธ์ ๊ณ์ ๋ถ์
lr_model = models['Logistic Regression']
feature_names = tfidf.get_feature_names_out()
coefficients = lr_model.coef_[0]
# ๊ธ์ ์ ์ํฅ์ ์ฃผ๋ ๋จ์ด Top 20
top_positive_idx = np.argsort(coefficients)[-20:]
top_positive_words = [(feature_names[i], coefficients[i]) for i in top_positive_idx]
print("๊ธ์ ๊ฐ์ฑ์ ๊ฐ์ฅ ์ํฅ์ ์ฃผ๋ ๋จ์ด:")
for word, coef in reversed(top_positive_words):
print(f"{word:20} {coef:.4f}")
# ๋ถ์ ์ ์ํฅ์ ์ฃผ๋ ๋จ์ด Top 20
top_negative_idx = np.argsort(coefficients)[:20]
top_negative_words = [(feature_names[i], coefficients[i]) for i in top_negative_idx]
print("\n๋ถ์ ๊ฐ์ฑ์ ๊ฐ์ฅ ์ํฅ์ ์ฃผ๋ ๋จ์ด:")
for word, coef in top_negative_words:
print(f"{word:20} {coef:.4f}")
์ด๋ ๊ฒ ํ๋ฉด ๋ชจ๋ธ์ด "amazing", "excellent" ๊ฐ์ ๋จ์ด๋ฅผ ๊ธ์ ์ผ๋ก,
"terrible", "awful" ๊ฐ์ ๋จ์ด๋ฅผ ๋ถ์ ์ผ๋ก ํ์ตํ๋ค๋ ๊ฑธ ํ์ธํ ์ ์์ด ใ
ใ
์ด์ ์๋ก์ด ๋ฆฌ๋ทฐ๊ฐ ๋ค์ด์์ ๋ ๋ฐ๋ก ๊ฐ์ฑ์ ์์ธกํ๋ ํจ์๋ฅผ ๋ง๋ค์ด๋ณด์:
def predict_sentiment(review_text, model, vectorizer, preprocessor):
"""
์๋ก์ด ๋ฆฌ๋ทฐ์ ๊ฐ์ฑ์ ์์ธกํ๋ ํจ์
Args:
review_text: ์์ธกํ ๋ฆฌ๋ทฐ ํ
์คํธ
model: ํ์ต๋ ๋ชจ๋ธ
vectorizer: ํ์ต๋ TF-IDF ๋ฒกํฐ๋ผ์ด์
preprocessor: ์ ์ฒ๋ฆฌ ํจ์
Returns:
sentiment: 'Positive' ๋๋ 'Negative'
probability: ์์ธก ํ๋ฅ
"""
# ์ ์ฒ๋ฆฌ
cleaned_text = preprocessor(review_text)
# ๋ฒกํฐํ
text_vector = vectorizer.transform([cleaned_text])
# ์์ธก
prediction = model.predict(text_vector)[0]
probability = model.predict_proba(text_vector)[0]
sentiment = "Positive" if prediction == 1 else "Negative"
confidence = probability[prediction]
return sentiment, confidence
# ํ
์คํธ
test_reviews = [
"This movie is absolutely fantastic! I loved every minute of it.",
"Worst movie ever. Complete waste of time and money.",
"It was okay, nothing special but not terrible either.",
]
best_model_obj = models['Logistic Regression']
print("์ค์๊ฐ ์์ธก ํ
์คํธ:\n")
for review in test_reviews:
sentiment, confidence = predict_sentiment(
review, best_model_obj, tfidf, preprocess_text
)
print(f"๋ฆฌ๋ทฐ: {review}")
print(f"์์ธก: {sentiment} (ํ์ ๋: {confidence:.2%})\n")
์ด์ ์์ ํ ์๋ํ๋ ๊ฐ์ฑ ๋ถ์ ์์คํ
์ด ์์ฑ๋์ด!
์ค์ ์๋น์ค์ ์ ์ฉํ๋ ค๋ฉด Flask๋ FastAPI๋ก API๋ฅผ ๋ง๋ค์ด์ ๋ฐฐํฌํ๋ฉด ๋จ ๐
๐จ ํ ์คํธ ๋ง์ด๋ ๊ณ ๊ธ ๊ธฐ๋ฒ๋ค
๊ธฐ๋ณธ์ ์ธ ๊ฐ์ฑ ๋ถ์์ ๋์ด์, ๋ ๊ณ ๊ธ ํ
์คํธ ๋ง์ด๋ ๊ธฐ๋ฒ๋ค์ ์์๋ณด์.
์ด๋ฐ ๊ธฐ๋ฒ๋ค์ ์ค๋ฌด์์ ์ง์ง ๋ง์ด ์ฐ์ด๋ ๊ฒ๋ค์ด์ผ ๐ก
ํ ํฝ ๋ชจ๋ธ๋ง์ ๋๋์ ๋ฌธ์์์ ์จ๊ฒจ์ง ์ฃผ์ ๋ฅผ ์๋์ผ๋ก ์ฐพ์๋ด๋ ๊ธฐ์ ์ด์ผ.
๋ํ์ ์ผ๋ก LDA (Latent Dirichlet Allocation)๊ฐ ๋ง์ด ์ฐ์:
from sklearn.decomposition import LatentDirichletAllocation
from sklearn.feature_extraction.text import CountVectorizer
# ์ํ ๋ฌธ์ (์ค์ ๋ก๋ ์๋ฐฑ~์์ฒ ๊ฐ)
documents = [
"Python is a great programming language for data science",
"Machine learning and deep learning are hot topics",
"Natural language processing helps understand text data",
"Data visualization is important for data analysis",
"Neural networks are used in deep learning models",
]
# CountVectorizer๋ก ๋ฌธ์-๋จ์ด ํ๋ ฌ ์์ฑ
vectorizer = CountVectorizer(max_features=100, stop_words='english')
doc_term_matrix = vectorizer.fit_transform(documents)
# LDA ๋ชจ๋ธ ํ์ต
n_topics = 2
lda = LatentDirichletAllocation(
n_components=n_topics,
random_state=42,
max_iter=10
)
lda.fit(doc_term_matrix)
# ํ ํฝ๋ณ ์ฃผ์ ๋จ์ด ์ถ๋ ฅ
feature_names = vectorizer.get_feature_names_out()
print("๋ฐ๊ฒฌ๋ ํ ํฝ๋ค:\n")
for topic_idx, topic in enumerate(lda.components_):
top_words_idx = topic.argsort()[-10:][::-1]
top_words = [feature_names[i] for i in top_words_idx]
print(f"ํ ํฝ {topic_idx + 1}: {', '.join(top_words)}")
ํ ํฝ ๋ชจ๋ธ๋ง์ ์ด๋ฐ ๊ณณ์ ํ์ฉ๋ผ:
โข ๋ด์ค ๊ธฐ์ฌ ์๋ ๋ถ๋ฅ
โข ๊ณ ๊ฐ ๋ฆฌ๋ทฐ์์ ์ฃผ์ ๋ถ๋ง์ฌํญ ํ์
โข ์ฐ๊ตฌ ๋
ผ๋ฌธ ํธ๋ ๋ ๋ถ์
โข SNS ๋ํ ์ฃผ์ ์ถ์ถ
Word2Vec์ ๋จ์ด๋ฅผ ๋ฒกํฐ ๊ณต๊ฐ์ ๋ฐฐ์นํด์ ๋จ์ด ๊ฐ ์๋ฏธ์ ๊ด๊ณ๋ฅผ ํํํ๋ ๊ธฐ์ ์ด์ผ.
"์ - ๋จ์ + ์ฌ์ = ์ฌ์" ๊ฐ์ ์ ๊ธฐํ ์ฐ์ฐ์ด ๊ฐ๋ฅํจ ใ
ใ
ใ
from gensim.models import Word2Vec
from nltk.tokenize import word_tokenize
# ์ํ ๋ฌธ์ฅ๋ค
sentences = [
"the king sits on the throne",
"the queen sits beside the king",
"the prince is the son of the king",
"the princess is the daughter of the queen",
]
# ํ ํฐํ
tokenized_sentences = [word_tokenize(sent.lower()) for sent in sentences]
# Word2Vec ๋ชจ๋ธ ํ์ต
model = Word2Vec(
sentences=tokenized_sentences,
vector_size=100, # ๋ฒกํฐ ์ฐจ์
window=5, # ๋ฌธ๋งฅ ์๋์ฐ ํฌ๊ธฐ
min_count=1, # ์ต์ ๋ฑ์ฅ ํ์
workers=4
)
# ์ ์ฌํ ๋จ์ด ์ฐพ๊ธฐ
print("'king'๊ณผ ์ ์ฌํ ๋จ์ด:")
similar_words = model.wv.most_similar('king', topn=5)
for word, similarity in similar_words:
print(f"{word}: {similarity:.4f}")
# ๋จ์ด ๊ฐ ์ ์ฌ๋
similarity = model.wv.similarity('king', 'queen')
print(f"\n'king'๊ณผ 'queen'์ ์ ์ฌ๋: {similarity:.4f}")
# ๋จ์ด ์ฐ์ฐ
result = model.wv.most_similar(
positive=['king', 'woman'],
negative=['man'],
topn=1
)
print(f"\nking - man + woman = {result[0][0]}")
๋ฐ์ดํฐ๊ฐ ๋ถ์กฑํ๋ฉด ์ฌ์ ํ์ต๋ ๋ชจ๋ธ(GloVe, FastText ๋ฑ)์ ์ฌ์ฉํ๋ ๊ฒ ์ข์!
spaCy์ NER์ ์ปค์คํฐ๋ง์ด์งํด์ ๋๋ฉ์ธ ํนํ ๊ฐ์ฒด๋ฅผ ์ธ์ํ๋๋ก ๋ง๋ค ์ ์์ด:
import spacy
from spacy.training import Example
from spacy.util import minibatch
import random
# ๊ธฐ๋ณธ ๋ชจ๋ธ ๋ก๋
nlp = spacy.blank("en")
# NER ํ์ดํ๋ผ์ธ ์ถ๊ฐ
if "ner" not in nlp.pipe_names:
ner = nlp.add_pipe("ner")
else:
ner = nlp.get_pipe("ner")
# ์ปค์คํ
๋ ์ด๋ธ ์ถ๊ฐ (์: ์ ํ๋ช
)
ner.add_label("PRODUCT")
# ํ์ต ๋ฐ์ดํฐ (ํ
์คํธ, {๊ฐ์ฒด ์์น์ ๋ ์ด๋ธ})
TRAIN_DATA = [
("I bought an iPhone 13 yesterday", {"entities": [(14, 23, "PRODUCT")]}),
("The new MacBook Pro is amazing", {"entities": [(8, 19, "PRODUCT")]}),
("Samsung Galaxy S21 has great camera", {"entities": [(0, 18, "PRODUCT")]}),
]
# ๋ชจ๋ธ ํ์ต
optimizer = nlp.begin_training()
for epoch in range(10):
random.shuffle(TRAIN_DATA)
losses = {}
for text, annotations in TRAIN_DATA:
doc = nlp.make_doc(text)
example = Example.from_dict(doc, annotations)
nlp.update([example], drop=0.5, losses=losses)
print(f"Epoch {epoch + 1}, Loss: {losses['ner']:.4f}")
# ํ
์คํธ
test_text = "I'm thinking about buying the new AirPods Pro"
doc = nlp(test_text)
print("\n์ธ์๋ ๊ฐ์ฒด:")
for ent in doc.ents:
print(f"{ent.text}: {ent.label_}")
์ด๋ฐ ์ปค์คํ
NER์ ํนํ ์ด๋ฐ ๋ถ์ผ์์ ์ ์ฉํด:
โข ์๋ฃ: ์ง๋ณ๋ช
, ์ฝ๋ฌผ๋ช
์ถ์ถ
โข ๋ฒ๋ฅ : ๋ฒ๋ฅ ์ฉ์ด, ํ๋ก ์ธ์
โข ๊ธ์ต: ํ์ฌ๋ช
, ๊ธ์ต์ํ ์๋ณ
โข ์ ์์๊ฑฐ๋: ์ ํ๋ช
, ๋ธ๋๋ ์ถ์ถ
ํ
์คํธ ๋ถ๋ฅ๋ ๋ฌธ์๋ฅผ ๋ฏธ๋ฆฌ ์ ์๋ ์นดํ
๊ณ ๋ฆฌ๋ก ์๋ ๋ถ๋ฅํ๋ ๊ฑฐ์ผ.
๋ฅ๋ฌ๋์ ํ์ฉํ๋ฉด ๋ ๋์ ์ ํ๋๋ฅผ ์ป์ ์ ์์ด:
# ๊ฐ๋จํ CNN ๊ธฐ๋ฐ ํ
์คํธ ๋ถ๋ฅ (๊ฐ๋
์ฝ๋)
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding, Conv1D, GlobalMaxPooling1D, Dense, Dropout
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
# ํ์ดํผํ๋ผ๋ฏธํฐ
vocab_size = 10000
embedding_dim = 100
max_length = 200
num_classes = 5
# ๋ชจ๋ธ ๊ตฌ์กฐ
model = Sequential([
Embedding(vocab_size, embedding_dim, input_length=max_length),
Conv1D(128, 5, activation='relu'),
GlobalMaxPooling1D(),
Dense(64, activation='relu'),
Dropout(0.5),
Dense(num_classes, activation='softmax')
])
model.compile(
optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy']
)
print(model.summary())
์ค๋ฌด์์๋ BERT, GPT ๊ฐ์ ํธ๋์คํฌ๋จธ ๋ชจ๋ธ์ ํ์ธํ๋ํด์ ์ฐ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์.
Hugging Face ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด ์ฝ๊ฒ ์ ์ฉํ ์ ์์ ๐
๐ ๏ธ ์ค๋ฌด์์ ์์ฃผ ๋ง์ฃผ์น๋ ๋ฌธ์ ๋ค๊ณผ ํด๊ฒฐ๋ฒ
์ด๋ก ์ ์๋ฒฝํด๋ ์ค์ ์์๋ ์์ ๋ชปํ ๋ฌธ์ ๋ค์ด ํฐ์ ธ ๋์ ใ
ใ
ใ
๋ด๊ฐ ์ค๋ฌด์์ ๊ฒช์๋ ๋ฌธ์ ๋ค๊ณผ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๊ณต์ ํด๋ณผ๊ฒ ๐ช
์ฆ์: NLTK๋ spaCy๋ก ํ๊ตญ์ด ์ฒ๋ฆฌํ๋ฉด ๊ฒฐ๊ณผ๊ฐ ์๋ง
์์ธ: ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ ๊ธฐ๋ณธ์ ์ผ๋ก ์์ด ์ค์ฌ์ผ๋ก ์ค๊ณ๋จ
ํด๊ฒฐ:
โข KoNLPy ์ฌ์ฉ (Okt, Komoran, Mecab ๋ฑ)
โข ํ๊ตญ์ด ํนํ ๋ชจ๋ธ ํ์ฉ (KoBERT, KoGPT ๋ฑ)
โข ํํ์ ๋ถ์๊ธฐ ์กฐํฉํด์ ์ฌ์ฉ
# KoNLPy ์์
from konlpy.tag import Okt
okt = Okt()
text = "์์ฐ์ด ์ฒ๋ฆฌ๋ ์ ๋ง ์ฌ๋ฏธ์์ด์!"
# ํํ์ ๋ถ์
morphs = okt.morphs(text)
print("ํํ์:", morphs)
# ๋ช
์ฌ ์ถ์ถ
nouns = okt.nouns(text)
print("๋ช
์ฌ:", nouns)
# ํ์ฌ ํ๊น
pos = okt.pos(text)
print("ํ์ฌ:", pos)
์ฆ์: ๋์ฉ๋ ํ ์คํธ ์ฒ๋ฆฌ ์ MemoryError ๋ฐ์
์์ธ: ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ํ ๋ฒ์ ๋ก๋
ํด๊ฒฐ:
โข ๋ฐฐ์น ์ฒ๋ฆฌ (Batch Processing)
โข ์ ๋๋ ์ดํฐ ํ์ฉ
โข ์ฒญํฌ ๋จ์๋ก ํ์ผ ์ฝ๊ธฐ
# ์ ๋๋ ์ดํฐ๋ฅผ ํ์ฉํ ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ฒ๋ฆฌ
def process_large_file(filename, batch_size=1000):
"""๋์ฉ๋ ํ์ผ์ ๋ฐฐ์น๋ก ์ฒ๋ฆฌ"""
batch = []
with open(filename, 'r', encoding='utf-8') as f:
for line in f:
batch.append(line.strip())
if len(batch) >= batch_size:
# ๋ฐฐ์น ์ฒ๋ฆฌ
yield process_batch(batch)
batch = []
# ๋จ์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ
if batch:
yield process_batch(batch)
def process_batch(texts):
"""๋ฐฐ์น ๋จ์ ์ฒ๋ฆฌ ๋ก์ง"""
# ์ฌ๊ธฐ์ ์ค์ NLP ์ฒ๋ฆฌ
return [preprocess_text(text) for text in texts]
# ์ฌ์ฉ
for processed_batch in process_large_file('huge_file.txt'):
# ์ฒ๋ฆฌ๋ ๋ฐฐ์น๋ก ์์
save_to_database(processed_batch)
์ฆ์: ์๋ง ๊ฐ ๋ฌธ์ ์ฒ๋ฆฌ์ ๋ช ์๊ฐ์ฉ ๊ฑธ๋ฆผ
์์ธ: ์์ฐจ ์ฒ๋ฆฌ, ๋นํจ์จ์ ์ธ ์๊ณ ๋ฆฌ์ฆ
ํด๊ฒฐ:
โข ๋ฉํฐํ๋ก์ธ์ฑ ํ์ฉ
โข spaCy์ nlp.pipe() ์ฌ์ฉ
โข GPU ๊ฐ์ (๊ฐ๋ฅํ ๊ฒฝ์ฐ)
import spacy
from multiprocessing import Pool
nlp = spacy.load("en_core_web_sm")
# ๋นํจ์จ์ ์ธ ๋ฐฉ๋ฒ โ
texts = ["text1", "text2", ...]
docs = [nlp(text) for text in texts] # ๋๋ฆผ!
# ํจ์จ์ ์ธ ๋ฐฉ๋ฒ โ
docs = list(nlp.pipe(texts, batch_size=50)) # ํจ์ฌ ๋น ๋ฆ!
# ๋ฉํฐํ๋ก์ธ์ฑ ํ์ฉ
def process_text(text):
doc = nlp(text)
return [token.lemma_ for token in doc]
if __name__ == '__main__':
with Pool(processes=4) as pool:
results = pool.map(process_text, texts)
์ฆ์: SNS ๋ฐ์ดํฐ์์ "ใ ใ ใ ", "ในใ ", "๊ฟ์ผ" ๊ฐ์ ํํ ์ฒ๋ฆฌ ์ ๋จ
์์ธ: ์ฌ์ ์ ์๋ ๋จ์ด๋ค
ํด๊ฒฐ:
โข ์ปค์คํ ์ฌ์ ๊ตฌ์ถ
โข ์ ๊ทํํ์์ผ๋ก ํจํด ์ฒ๋ฆฌ
โข ์คํ ๊ต์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ฉ
import re
from collections import defaultdict
# ์ ์กฐ์ด ์ฌ์
slang_dict = {
'ใ
ใ
ใ
': '์์',
'ในใ
': '๋ฆฌ์ผ',
'๊ฟ์ผ': '์ฌ๋ฏธ์์',
'ใ
ใ
': '์ธ์ ',
'ใดใด': '๋
ธ๋
ธ',
}
def normalize_slang(text):
"""์ ์กฐ์ด๋ฅผ ํ์ค์ด๋ก ๋ณํ"""
for slang, standard in slang_dict.items():
text = text.replace(slang, standard)
return text
# ๋ฐ๋ณต ๋ฌธ์ ์ ๊ทํ
def normalize_repeats(text):
"""ใ
ใ
ใ
ใ
ใ
โ ใ
ใ
"""
text = re.sub(r'(.)\1{2,}', r'\1\1', text)
return text
# ์คํ ๊ต์ (๊ฐ๋จํ ๋ฒ์ )
def simple_spell_check(word, dictionary):
"""ํธ์ง ๊ฑฐ๋ฆฌ ๊ธฐ๋ฐ ์คํ ๊ต์ """
if word in dictionary:
return word
# 1๊ธ์ ์ฐจ์ด๋๋ ๋จ์ด ์ฐพ๊ธฐ
candidates = []
for dict_word in dictionary:
if abs(len(word) - len(dict_word)) <= 1:
distance = edit_distance(word, dict_word)
if distance <= 1:
candidates.append((dict_word, distance))
if candidates:
return min(candidates, key=lambda x: x[1])[0]
return word
2. ๊ฐ์ธ์ ๋ณด ๋ณดํธ: ์ค์ ์ฌ์ฉ์ ๋ฐ์ดํฐ ๋ค๋ฃฐ ๋๋ ๊ฐ์ธ์ ๋ณด ๋ง์คํน ํ์
3. ๋ชจ๋ธ ์ ๋ฐ์ดํธ: ์ธ์ด๋ ๊ณ์ ๋ณํํจ. ์ ๊ธฐ์ ์ธ ๋ชจ๋ธ ์ฌํ์ต ํ์
4. ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง: ํ๋ก๋์ ํ๊ฒฝ์์ ์ง์์ ์ธ ์ฑ๋ฅ ์ถ์ ๋ฐ ๊ฐ์
๐ ํ์ต ๋ก๋๋งต๊ณผ ์ถ์ฒ ๋ฆฌ์์ค
ํ
์คํธ ๋ง์ด๋์ ์ ๋๋ก ๋ฐฐ์ฐ๊ณ ์ถ๋ค๋ฉด ์ฒด๊ณ์ ์ธ ํ์ต์ด ์ค์ํด.
๋ด๊ฐ ์ถ์ฒํ๋ ๋จ๊ณ๋ณ ๋ก๋๋งต์ ๊ณต์ ํ ๊ฒ ๐
1๏ธโฃ ๊ธฐ์ด ๋จ๊ณ (1-2๊ฐ์)
โข Python ๊ธฐ๋ณธ ๋ฌธ๋ฒ ์๋ฒฝํ ์ตํ๊ธฐ
โข ๋ฆฌ์คํธ, ๋์
๋๋ฆฌ, ํจ์, ํด๋์ค ๋ฑ
โข ์ ๊ทํํ์ ๋ง์คํฐ (re ๋ชจ๋)
โข ํ์ผ ์
์ถ๋ ฅ, ๋ฌธ์์ด ์ฒ๋ฆฌ
์ถ์ฒ ์ค์ต: ๊ฐ๋จํ ํ
์คํธ ํ์ผ ์ฝ์ด์ ๋จ์ด ๋น๋์ ์ธ๊ธฐ, ํน์ ํจํด ์ฐพ๊ธฐ ๋ฑ
2๏ธโฃ NLP ๊ธฐ์ด ๋จ๊ณ (2-3๊ฐ์)
โข NLTK ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ์ฒด ๊ธฐ๋ฅ ํ์ต
โข ํ ํฐํ, ํ์ฌ ํ๊น
, ๊ฐ์ฒด๋ช
์ธ์
โข ๋ถ์ฉ์ด ์ฒ๋ฆฌ, ์ด๊ฐ ์ถ์ถ
โข ๊ธฐ๋ณธ์ ์ธ ํ
์คํธ ์ ์ฒ๋ฆฌ ํ์ดํ๋ผ์ธ ๊ตฌ์ถ
์ถ์ฒ ์ค์ต: ๋ด์ค ๊ธฐ์ฌ ํฌ๋กค๋งํด์ ํค์๋ ์ถ์ถ, ๊ฐ๋จํ ์๋ํด๋ผ์ฐ๋ ์์ฑ
3๏ธโฃ ๊ณ ๊ธ NLP ๋จ๊ณ (2-3๊ฐ์)
โข spaCy๋ก ํจ์จ์ ์ธ ํ
์คํธ ์ฒ๋ฆฌ
โข Word2Vec, GloVe ๋ฑ ๋จ์ด ์๋ฒ ๋ฉ
โข TF-IDF, BM25 ๋ฑ ์ ๋ณด ๊ฒ์ ๊ธฐ๋ฒ
โข ์์กด ๊ตฌ๋ฌธ ๋ถ์, ๊ณต์ง์ ํด์
์ถ์ฒ ์ค์ต: ์ ์ฌ ๋ฌธ์ ์ฐพ๊ธฐ ์์คํ
, ๊ฐ๋จํ ๊ฒ์ ์์ง ๊ตฌํ
4๏ธโฃ ๋จธ์ ๋ฌ๋ ๋จ๊ณ (3-4๊ฐ์)
โข scikit-learn์ผ๋ก ํ
์คํธ ๋ถ๋ฅ
โข Naive Bayes, SVM, Random Forest
โข ๊ฐ์ฑ ๋ถ์, ์คํธ ํํฐ๋ง
โข ํ ํฝ ๋ชจ๋ธ๋ง (LDA, NMF)
์ถ์ฒ ์ค์ต: ์ํ ๋ฆฌ๋ทฐ ๊ฐ์ฑ ๋ถ์, ๋ด์ค ๊ธฐ์ฌ ์๋ ๋ถ๋ฅ
5๏ธโฃ ๋ฅ๋ฌ๋ ๋จ๊ณ (4-6๊ฐ์)
โข RNN, LSTM์ผ๋ก ์ํ์ค ๋ชจ๋ธ๋ง
โข Attention ๋ฉ์ปค๋์ฆ ์ดํด
โข Transformer, BERT ๋ฑ ์ต์ ๋ชจ๋ธ
โข Hugging Face Transformers ํ์ฉ
์ถ์ฒ ์ค์ต: ์ฑ๋ด ๊ตฌํ, ๊ธฐ๊ณ ๋ฒ์ญ, ๋ฌธ์ ์์ฝ
6๏ธโฃ ์ค์ ๋จ๊ณ (์ง์์ )
โข ์ค์ ๋น์ฆ๋์ค ๋ฌธ์ ํด๊ฒฐ
โข ๋์ฉ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๊ฒฝํ
โข ๋ชจ๋ธ ๋ฐฐํฌ ๋ฐ ์๋น
โข ์ฑ๋ฅ ์ต์ ํ ๋ฐ ๋ชจ๋ํฐ๋ง
์ถ์ฒ ์ค์ต: Kaggle ์ปดํผํฐ์
์ฐธ๊ฐ, ์คํ์์ค ๊ธฐ์ฌ, ํฌํธํด๋ฆฌ์ค ํ๋ก์ ํธ
2. ์์ผ๋ก ์ง์ ์ฝ๋ฉ: ๋ณต๋ถํ์ง ๋ง๊ณ ์ง์ ํ์ดํํ๋ฉด์ ์ตํ๊ธฐ
3. ์์ ํ๋ก์ ํธ๋ถํฐ: ๊ฑฐ์ฐฝํ ๊ฒ๋ณด๋ค ์์ฑ ๊ฐ๋ฅํ ์์ ํ๋ก์ ํธ๋ก ์์
4. ์ปค๋ฎค๋ํฐ ํ์ฉ: Stack Overflow, Reddit, ํ๊ตญ NLP ์ปค๋ฎค๋ํฐ ๋ฑ์์ ์ง๋ฌธํ๊ณ ๋ต๋ณํ๊ธฐ
5. ์ต์ ํธ๋ ๋ ํ๋ก์ฐ: arXiv, Papers with Code์์ ์ต์ ๋ ผ๋ฌธ ์ฝ๊ธฐ
ํนํ ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์ ์ค์ ํ๋ก์ ํธ๋ฅผ ์์ฃผํด๋ณด๋ ๊ฒ๋ ์์ฒญ ์ข์ ํ์ต ๋ฐฉ๋ฒ์ด์ผ.
์ค์ ๊ฒฝํ๋งํผ ๋น ๋ฅด๊ฒ ์ฑ์ฅํ๋ ๋ฐฉ๋ฒ์ ์๊ฑฐ๋ ใ ใ
๐ ํ ์คํธ ๋ง์ด๋์ ๋ฏธ๋์ ํธ๋ ๋
ํ
์คํธ ๋ง์ด๋ ๋ถ์ผ๋ ์ ๋ง ๋น ๋ฅด๊ฒ ๋ฐ์ ํ๊ณ ์์ด.
์์ผ๋ก ์ด๋ค ๋ฐฉํฅ์ผ๋ก ๋์๊ฐ์ง, ์ด๋ค ๊ธฐ์ ๋ค์ด ์ฃผ๋ชฉ๋ฐ์์ง ์์๋ณด์ ๐ฎ
GPT-3, GPT-4, Claude, Gemini ๊ฐ์ ๋๊ท๋ชจ ์ธ์ด ๋ชจ๋ธ์ด ๊ฒ์ ์ฒด์ธ์ ๊ฐ ๋๊ณ ์์ด.
์ด์ ๋ ๋ชจ๋ธ์ ์ฒ์๋ถํฐ ํ์ต์ํค๋ ๊ฒ ์๋๋ผ, ์ฌ์ ํ์ต๋ ๋ชจ๋ธ์ ํ์ธํ๋ํ๋ ๊ฒ ๋์ธ์ผ:
# Hugging Face Transformers ์์
from transformers import pipeline
# ๊ฐ์ฑ ๋ถ์ ํ์ดํ๋ผ์ธ (์ฌ์ ํ์ต ๋ชจ๋ธ ํ์ฉ)
classifier = pipeline("sentiment-analysis")
results = classifier([
"I love this product!",
"This is terrible.",
"It's okay, nothing special."
])
for result in results:
print(f"{result['label']}: {result['score']:.4f}")
# ํ
์คํธ ์์ฑ
generator = pipeline("text-generation", model="gpt2")
output = generator("Natural language processing is", max_length=50)
print(output[0]['generated_text'])
LLM์ ์ฅ์ :
โข ๋ณ๋ ํ์ต ์์ด ๋ฐ๋ก ์ฌ์ฉ ๊ฐ๋ฅ (Zero-shot Learning)
โข ์๋์ ์์๋ง์ผ๋ก ํ์ต (Few-shot Learning)
โข ๋ค์ํ ํ์คํฌ๋ฅผ ํ๋์ ๋ชจ๋ธ๋ก ์ฒ๋ฆฌ
โข ์ธ๊ฐ ์์ค์ ํ
์คํธ ์ดํด ๋ฐ ์์ฑ
์์ด ์ค์ฌ์์ ๋ฒ์ด๋ ๋ค์ํ ์ธ์ด๋ฅผ ๋์์ ์ฒ๋ฆฌํ๋ ๋ชจ๋ธ๋ค์ด ๋์ค๊ณ ์์ด:
| ๋ชจ๋ธ | ํน์ง | ์ง์ ์ธ์ด |
|---|---|---|
| mBERT | ๋ค๊ตญ์ด BERT | 104๊ฐ ์ธ์ด |
| XLM-R | ํฌ๋ก์ค๋ง๊ตฌ์ผ ๋ชจ๋ธ | 100๊ฐ ์ธ์ด |
| mT5 | ๋ค๊ตญ์ด T5 | 101๊ฐ ์ธ์ด |
| BLOOM | ์คํ์์ค LLM | 46๊ฐ ์ธ์ด |
ํ๊ตญ์ด NLP๋ ๋น ๋ฅด๊ฒ ๋ฐ์ ์ค:
โข KoBERT, KoGPT, KoBART ๋ฑ ํ๊ตญ์ด ํนํ ๋ชจ๋ธ
โข ๋ค์ด๋ฒ, ์นด์นด์ค ๋ฑ ๊ธฐ์
๋ค์ ๋๊ท๋ชจ ํฌ์
โข ํ๊ตญ์ด ๋ฐ์ดํฐ์
๊ณต๊ฐ ๋ฐ ๋ฒค์น๋งํฌ ๊ตฌ์ถ
๋ฒ์ฉ ๋ชจ๋ธ์์ ํน์ ๋ถ์ผ์ ํนํ๋ ๋ชจ๋ธ๋ก ์งํ ์ค:
์๋ฃ NLP
โข BioBERT, PubMedBERT: ์ํ ๋
ผ๋ฌธ ํ์ต
โข ์ ์์๋ฌด๊ธฐ๋ก(EMR) ์๋ ๋ถ์
โข ์ฝ๋ฌผ ์ํธ์์ฉ ์์ธก
๋ฒ๋ฅ NLP
โข LegalBERT: ๋ฒ๋ฅ ๋ฌธ์ ํนํ
โข ๊ณ์ฝ์ ์๋ ๊ฒํ
โข ํ๋ก ๊ฒ์ ๋ฐ ๋ถ์
๊ธ์ต NLP
โข FinBERT: ๊ธ์ต ๋ด์ค ๊ฐ์ฑ ๋ถ์
โข ๋ฆฌ์คํฌ ํ๊ฐ ์๋ํ
โข ์ฌ๊ธฐ ํ์ง ์์คํ
๊ธฐ์ ์ด ๋ฐ์ ํ ์๋ก ์ค๋ฆฌ์ ์ด์๋ ์ค์ํด์ง๊ณ ์์ด:
โข ์ฑ๋ณ, ์ธ์ข , ๋์ด ๋ฑ์ ๋ํ ์ฐจ๋ณ์ ๊ฒฐ๊ณผ
โข ํด๊ฒฐ: ๋ค์ํ ๋ฐ์ดํฐ ํ๋ณด, ๊ณต์ ์ฑ ๋ฉํธ๋ฆญ ๋ชจ๋ํฐ๋ง
2. ๊ฐ์ธ์ ๋ณด ๋ณดํธ: ํ ์คํธ์ ํฌํจ๋ ๋ฏผ๊ฐ ์ ๋ณด
โข ์ด๋ฆ, ์ฃผ์, ์ ํ๋ฒํธ ๋ฑ ๊ฐ์ธ ์๋ณ ์ ๋ณด
โข ํด๊ฒฐ: ๋ฐ์ดํฐ ์ต๋ช ํ, ์ฐจ๋ฑ ํ๋ผ์ด๋ฒ์ ์ ์ฉ
3. ํ์์ ๋ณด ์์ฑ: LLM์ ๊ทธ๋ด๋ฏํ ๊ฑฐ์ง๋ง
โข ๋ฅํ์ดํฌ ํ ์คํธ, ๊ฐ์ง ๋ด์ค ์๋ ์์ฑ
โข ํด๊ฒฐ: ํฉํธ ์ฒดํน ์์คํ , ์ถ์ฒ ํ์
4. ํฌ๋ช ์ฑ: ๋ธ๋๋ฐ์ค ๋ชจ๋ธ์ ์ค๋ช ๊ฐ๋ฅ์ฑ
โข ์ ๊ทธ๋ฐ ๊ฒฐ์ ์ ๋ด๋ ธ๋์ง ์ค๋ช ์ด๋ ค์
โข ํด๊ฒฐ: LIME, SHAP ๋ฑ ์ค๋ช ๊ฐ๋ฅ AI ๊ธฐ๋ฒ ํ์ฉ
ํด๋ผ์ฐ๋๊ฐ ์๋ ๋๋ฐ์ด์ค์์ ์ง์ NLP ์ฒ๋ฆฌํ๋ ์ถ์ธ:
โข ๋ชจ๋ธ ๊ฒฝ๋ํ: DistilBERT, TinyBERT ๋ฑ
โข ์์ํ: ๋ชจ๋ธ ํฌ๊ธฐ ์ค์ด๋ฉด์ ์ฑ๋ฅ ์ ์ง
โข ํ๋ฃจ๋: ๋ถํ์ํ ํ๋ผ๋ฏธํฐ ์ ๊ฑฐ
โข ์ง์ ์ฆ๋ฅ: ํฐ ๋ชจ๋ธ์ ์ง์์ ์์ ๋ชจ๋ธ๋ก ์ ๋ฌ
์ด๋ ๊ฒ ํ๋ฉด ์ค๋งํธํฐ, IoT ๊ธฐ๊ธฐ์์๋ ๊ณ ๊ธ NLP ๊ธฐ๋ฅ ์ฌ์ฉ ๊ฐ๋ฅ ๐ฑ
2. ์ค์๊ฐ ๋ฒ์ญ: ๊ฑฐ์ ์๋ฒฝํ ์์ค์ ๋์ํต์ญ ์คํ
3. ๊ฐ์ธํ AI ๋น์: ๊ฐ์ธ ๋ง์ถคํ ์ธ์ด ๋ชจ๋ธ์ด ์ผ์ํ
4. ์ฝ๋ ์์ฑ: ์์ฐ์ด๋ก ํ๋ก๊ทธ๋จ ์๋ ์์ฑ (GitHub Copilot ์์ค ์ด์)
5. ์ฐฝ์ ์ง์: ์์ค, ์๋๋ฆฌ์ค, ์์ ๊ฐ์ฌ ๋ฑ ์ฐฝ์ ํ๋ AI ํ์
ํ ์คํธ ๋ง์ด๋ ์ ๋ฌธ๊ฐ์ ์์๋ ๊ณ์ ์ฆ๊ฐํ ๊ฑฐ์ผ. ์ง๊ธ ๋ฐฐ์๋๋ฉด ๋ฏธ๋๊ฐ ๋ฐ์ ใ ใ
๐ผ ์ค๋ฌด ํ์ฉ ์ฌ๋ก์ ๋น์ฆ๋์ค ๊ฐ์น
์ด๋ก ๊ณผ ๊ธฐ์ ๋ ์ค์ํ์ง๋ง, ๊ฒฐ๊ตญ ์ค๋ฌด์์ ์ด๋ป๊ฒ ์ฐ์ด๋์ง๊ฐ ๊ฐ์ฅ ์ค์ํ์ง ใ
ใ
๋ค์ํ ์ฐ์
์์ ํ
์คํธ ๋ง์ด๋์ด ์ด๋ป๊ฒ ํ์ฉ๋๋์ง ์ดํด๋ณด์ ๐ผ
๋ฌธ์ : ํ๋ฃจ์ ์์ฒ ๊ฐ์ฉ ์์ด๋ ์ํ ๋ฆฌ๋ทฐ๋ฅผ ์ผ์ผ์ด ์ฝ์ ์ ์์
ํด๊ฒฐ: ํ
์คํธ ๋ง์ด๋์ผ๋ก ์๋ ๋ถ์
๊ตฌํ ๋ด์ฉ:
โข ๊ฐ์ฑ ๋ถ์์ผ๋ก ๊ธ์ /๋ถ์ ๋ฆฌ๋ทฐ ์๋ ๋ถ๋ฅ
โข ํ ํฝ ๋ชจ๋ธ๋ง์ผ๋ก ์ฃผ์ ๋ถ๋ง์ฌํญ ์ถ์ถ
โข ํค์๋ ๋ถ์์ผ๋ก ์ ํ ๊ฐ์ ์ ๋์ถ
โข ๊ฐ์ง ๋ฆฌ๋ทฐ ํ์ง ์์คํ
๋น์ฆ๋์ค ํจ๊ณผ:
โ
์ ํ ๊ฐ์ ์ฌ์ดํด 50% ๋จ์ถ
โ
๊ณ ๊ฐ ๋ง์กฑ๋ 15% ํฅ์
โ
๊ฐ์ง ๋ฆฌ๋ทฐ 90% ์ด์ ์ฐจ๋จ
# ๋ฆฌ๋ทฐ ๋ถ์ ํ์ดํ๋ผ์ธ ์์
class ReviewAnalyzer:
def __init__(self):
self.sentiment_model = load_sentiment_model()
self.topic_model = load_topic_model()
self.fake_detector = load_fake_detector()
def analyze_review(self, review_text):
"""๋ฆฌ๋ทฐ ์ข
ํฉ ๋ถ์"""
results = {
'sentiment': self.sentiment_model.predict(review_text),
'topics': self.topic_model.extract_topics(review_text),
'is_fake': self.fake_detector.predict(review_text),
'key_phrases': self.extract_key_phrases(review_text)
}
return results
def generate_insights(self, reviews):
"""์ ์ฒด ๋ฆฌ๋ทฐ์์ ์ธ์ฌ์ดํธ ์ถ์ถ"""
# ๊ฐ์ฑ ๋ถํฌ
sentiment_dist = self.get_sentiment_distribution(reviews)
# ์ฃผ์ ๋ถ๋ง์ฌํญ
complaints = self.extract_complaints(reviews)
# ๊ฐ์ ์ ์
suggestions = self.generate_suggestions(complaints)
return {
'sentiment_distribution': sentiment_dist,
'top_complaints': complaints,
'improvement_suggestions': suggestions
}
๋ฌธ์ : ์ค์๊ฐ์ผ๋ก ์์์ง๋ ๋ด์ค๋ฅผ ๋น ๋ฅด๊ฒ ๋ถ๋ฅํ๊ณ ์์ฝ ํ์
ํด๊ฒฐ: NLP ๊ธฐ๋ฐ ์๋ํ ์์คํ
๊ตฌํ ๋ด์ฉ:
โข ๋ด์ค ๊ธฐ์ฌ ์๋ ์นดํ
๊ณ ๋ฆฌ ๋ถ๋ฅ (์ ์น, ๊ฒฝ์ , ์ฌํ ๋ฑ)
โข ์ค์ ๋ฌธ์ฅ ์ถ์ถ๋ก 3์ค ์์ฝ ์์ฑ
โข ๊ฐ์ฒด๋ช
์ธ์์ผ๋ก ์ฃผ์ ์ธ๋ฌผ/์ฅ์ ํ๊น
โข ์ ์ฌ ๊ธฐ์ฌ ํด๋ฌ์คํฐ๋ง์ผ๋ก ์ค๋ณต ์ ๊ฑฐ
๋น์ฆ๋์ค ํจ๊ณผ:
โ
ํธ์ง ์๊ฐ 70% ์ ๊ฐ
โ
๋ด์ค ๋ฐํ ์๋ 3๋ฐฐ ํฅ์
โ
๋
์ ์ฒด๋ฅ ์๊ฐ 25% ์ฆ๊ฐ
๋ฌธ์ : ์์ฌ์ ์์ ํ์ ์ง๋ฃ ๊ธฐ๋ก์์ ์ ๋ณด ์ถ์ถ ์ด๋ ค์
ํด๊ฒฐ: ์๋ฃ ํนํ NLP ์์คํ
๊ตฌํ ๋ด์ฉ:
โข ์ฆ์, ์ง๋จ๋ช
, ์ฒ๋ฐฉ์ฝ ์๋ ์ถ์ถ
โข ์ํ ์ฉ์ด ํ์คํ (SNOMED CT, ICD-10)
โข ์ฝ๋ฌผ ์ํธ์์ฉ ์๋ ๊ฒฝ๊ณ
โข ์ ์ฌ ์ฌ๋ก ๊ฒ์์ผ๋ก ์ง๋จ ์ง์
๋น์ฆ๋์ค ํจ๊ณผ:
โ
์ง๋ฃ ๊ธฐ๋ก ์์ฑ ์๊ฐ 40% ๋จ์ถ
โ
์๋ฃ ์ค๋ฅ 30% ๊ฐ์
โ
์ฐ๊ตฌ ๋ฐ์ดํฐ ํ์ฉ๋ ๋ํญ ํฅ์
๋ฌธ์ : ๋ฐ๋ณต์ ์ธ ๊ณ ๊ฐ ๋ฌธ์ ์ฒ๋ฆฌ์ ์ธ๋ ฅ ๋ญ๋น
ํด๊ฒฐ: ์ง๋ฅํ ์ฑ๋ด ์์คํ
๊ตฌํ ๋ด์ฉ:
โข ์๋ ๋ถ๋ฅ(Intent Classification)๋ก ๋ฌธ์ ์ ํ ํ์
โข ๊ฐ์ฒด๋ช
์ธ์์ผ๋ก ์ฃผ๋ฌธ๋ฒํธ, ์ ํ๋ช
๋ฑ ์ถ์ถ
โข ์ง์ ๋ฒ ์ด์ค ๊ฒ์์ผ๋ก ์ ์ ํ ๋ต๋ณ ์ ๊ณต
โข ๊ฐ์ฑ ๋ถ์์ผ๋ก ๋ถ๋ง ๊ณ ๊ฐ ์ฐ์ ์ฒ๋ฆฌ
๋น์ฆ๋์ค ํจ๊ณผ:
โ
๋จ์ ๋ฌธ์ 80% ์๋ ์ฒ๋ฆฌ
โ
์๋ต ์๊ฐ 90% ๋จ์ถ
โ
๊ณ ๊ฐ ๋ง์กฑ๋ 20% ํฅ์
โ
์๋ด์ฌ ์
๋ฌด ํจ์จ 2๋ฐฐ ์ฆ๊ฐ
# ๊ฐ๋จํ ์ฑ๋ด ์๋ ๋ถ๋ฅ ์์
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import LinearSVC
class IntentClassifier:
def __init__(self):
self.vectorizer = TfidfVectorizer()
self.classifier = LinearSVC()
self.intents = {
'order_status': '์ฃผ๋ฌธ ์กฐํ',
'return': '๋ฐํ/๊ตํ',
'payment': '๊ฒฐ์ ๋ฌธ์',
'product_info': '์ ํ ์ ๋ณด',
'complaint': '๋ถ๋ง ์ ์'
}
def train(self, training_data):
"""ํ์ต ๋ฐ์ดํฐ๋ก ๋ชจ๋ธ ํ๋ จ"""
texts = [item['text'] for item in training_data]
labels = [item['intent'] for item in training_data]
X = self.vectorizer.fit_transform(texts)
self.classifier.fit(X, labels)
def predict(self, user_message):
"""์ฌ์ฉ์ ๋ฉ์์ง์ ์๋ ์์ธก"""
X = self.vectorizer.transform([user_message])
intent = self.classifier.predict(X)[0]
return {
'intent': intent,
'intent_name': self.intents.get(intent, '๊ธฐํ'),
'confidence': self.classifier.decision_function(X).max()
}
# ์ฌ์ฉ ์์
bot = IntentClassifier()
# bot.train(training_data) # ์ค์ ๋ก๋ ํ์ต ํ์
user_input = "์ ์ฃผ๋ฌธ์ด ์ธ์ ๋์ฐฉํ๋์?"
result = bot.predict(user_input)
print(f"์๋: {result['intent_name']}, ํ์ ๋: {result['confidence']:.2f}")
๋ฌธ์ : ๋์ถ ์ฌ์ฌ, ์ฌ๊ธฐ ๊ฑฐ๋ ํ์ง์ ์๊ฐ๊ณผ ๋น์ฉ ๊ณผ๋ค
ํด๊ฒฐ: ํ
์คํธ ๊ธฐ๋ฐ ๋ฆฌ์คํฌ ํ๊ฐ ์์คํ
๊ตฌํ ๋ด์ฉ:
โข ๋ด์ค, SNS ๋ถ์์ผ๋ก ๊ธฐ์
ํํ ๋ชจ๋ํฐ๋ง
โข ์ฌ๋ฌด์ ํ ํ
์คํธ ๋ถ์์ผ๋ก ๋ฆฌ์คํฌ ์์ธ ์ถ์ถ
โข ๊ฑฐ๋ ๋ฉ๋ชจ ๋ถ์์ผ๋ก ์ด์ ํจํด ํ์ง
โข ๊ฐ์ฑ ๋ถ์์ผ๋ก ์์ฅ ์ฌ๋ฆฌ ํ์
๋น์ฆ๋์ค ํจ๊ณผ:
โ
๋์ถ ์ฌ์ฌ ์๊ฐ 60% ๋จ์ถ
โ
์ฌ๊ธฐ ํ์ง์จ 45% ํฅ์
โ
๋ถ์ค ์ฑ๊ถ 30% ๊ฐ์
2. ROI ์ธก์ : ๋ช ํํ ์ฑ๊ณผ ์งํ ์ค์ (์๊ฐ ์ ๊ฐ, ๋น์ฉ ์ ๊ฐ ๋ฑ)
3. ์ฌ์ฉ์ ํผ๋๋ฐฑ: ์ค์ ์ฌ์ฉ์์ ์๊ฒฌ์ ์ง์์ ์ผ๋ก ๋ฐ์
4. ์ ์ง์ ๊ฐ์ : ์๋ฒฝํ ์์คํ ๋ณด๋ค ๋น ๋ฅธ ์ถ์ ํ ๊ฐ์
5. ๋๋ฉ์ธ ์ ๋ฌธ๊ฐ ํ์ : ๊ธฐ์ ๋ง์ผ๋ก๋ ๋ถ์กฑ, ์ ๋ฌด ์ดํด ํ์
์ฌ๋ฅ๋ท์์ ํ ์คํธ ๋ง์ด๋ ํ๋ก์ ํธ๋ฅผ ์ฐพ์๋ณด๋ฉด ์ค์ ๊ธฐ์ ๋ค์ด ์ด๋ค ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค ํ๋์ง ์ ์ ์์ด.
์ด๋ฐ ์ค์ ๊ฒฝํ์ด ํฌํธํด๋ฆฌ์ค์๋ ์ข๊ณ , ์ค๋ ฅ ํฅ์์๋ ์ต๊ณ ์ผ ใ ใ
๐ฏ ๋ง๋ฌด๋ฆฌํ๋ฉฐ
์... ์ฌ๊ธฐ๊น์ง ์ฝ๋๋ผ ์๊ณ ํ์ด ใ
ใ
ใ
ํ
์คํธ ๋ง์ด๋๊ณผ NLTK, spaCy์ ๋ํด ์ ๋ง ๋ง์ ๋ด์ฉ์ ๋ค๋ค์ง?
๊ฐ๋จํ๊ฒ ํต์ฌ๋ง ์ ๋ฆฌํด๋ณด๋ฉด:
โข ๋น์ ํ ํ ์คํธ ๋ฐ์ดํฐ์์ ์๋ฏธ ์๋ ์ ๋ณด ์ถ์ถ
โข ๊ฐ์ฑ ๋ถ์, ํ ํฝ ๋ชจ๋ธ๋ง, ๋ฌธ์ ๋ถ๋ฅ ๋ฑ ๋ค์ํ ํ์ฉ
โข ๋ฐ์ดํฐ์ 80%๊ฐ ๋น์ ํ์ด๋ผ ์ค์์ฑ ๊ธ์ฆ
2. NLTK
โข ๊ต์ก์ฉ์ผ๋ก ์ต์ ํ๋ NLP ๋ผ์ด๋ธ๋ฌ๋ฆฌ
โข ํ ํฐํ, ํ์ฌ ํ๊น , ๊ฐ์ฒด๋ช ์ธ์ ๋ฑ ๊ธฐ๋ณธ ๊ธฐ๋ฅ ์ถฉ์ค
โข ํ์ต๊ณผ ํ๋กํ ํ์ดํ์ ์ ํฉ
3. spaCy
โข ์ฐ์ ์ฉ ๊ณ ์ฑ๋ฅ NLP ๋ผ์ด๋ธ๋ฌ๋ฆฌ
โข ๋น ๋ฅธ ์๋์ ๋์ ์ ํ๋
โข ์ค์ ์๋น์ค ๋ฐฐํฌ์ ์ต์
4. ์ค์ ํ๋ก์ ํธ
โข ๋ฐ์ดํฐ ์์ง โ ์ ์ฒ๋ฆฌ โ ํน์ง ์ถ์ถ โ ๋ชจ๋ธ๋ง โ ํ๊ฐ
โข ๊ฐ์ฑ ๋ถ์, ํ ํฝ ๋ชจ๋ธ๋ง, ๋ฌธ์ ๋ถ๋ฅ ๋ฑ ๋ค์ํ ๊ธฐ๋ฒ
โข ์ค๋ฌด์์๋ ๋๋ฉ์ธ ์ง์๊ณผ ๊ธฐ์ ์ ์กฐํฉ์ด ํต์ฌ
5. ๋ฏธ๋ ํธ๋ ๋
โข LLM(๋๊ท๋ชจ ์ธ์ด ๋ชจ๋ธ)์ ๋ถ์
โข ๋ค๊ตญ์ด NLP ๋ฐ์
โข ๋๋ฉ์ธ ํนํ ๋ชจ๋ธ ์ฆ๊ฐ
โข ์ค๋ฆฌ์ ์ฑ ์ ์๋ AI ์ค์์ฑ ์ฆ๋
ํ
์คํธ ๋ง์ด๋์ ์ด์ ์ ํ์ด ์๋๋ผ ํ์ ๊ธฐ์ ์ด ๋์ด.
๋ฐ์ดํฐ ๋ถ์๊ฐ, ๊ฐ๋ฐ์, ๋ง์ผํฐ, ์ฐ๊ตฌ์ ๋ฑ ๋ค์ํ ๋ถ์ผ์์ ํ์ฉ๋๊ณ ์๊ณ ,
์์ผ๋ก ๊ทธ ์ค์์ฑ์ ๋์ฑ ์ปค์ง ๊ฑฐ์ผ ๐
์ฒ์์ ์ด๋ ต๊ฒ ๋๊ปด์ง ์ ์์ง๋ง, ํ๋์ฉ ์ฐจ๊ทผ์ฐจ๊ทผ ๋ฐ๋ผํ๋ค ๋ณด๋ฉด ์ด๋์ ์ ๋ฌธ๊ฐ๊ฐ ๋์ด ์์ ๊ฑฐ์ ใ
ใ
์์์ด ๋ฐ์ด๋ผ๊ณ ํ์์?
์ง๊ธ ๋ฐ๋ก Python ์ผ๊ณ NLTK๋ spaCy ์ค์นํด์ ๊ฐ๋จํ ์ฝ๋๋ถํฐ ์คํํด๋ด.
๊ทธ๊ฒ ํ
์คํธ ๋ง์ด๋ ์ ๋ฌธ๊ฐ๋ก ๊ฐ๋ ์ฒซ๊ฑธ์์ด์ผ ๐
๊ถ๊ธํ ์ ์์ผ๋ฉด ์ธ์ ๋ ์ปค๋ฎค๋ํฐ์ ๋ฌผ์ด๋ณด๊ณ ,
์ค์ ๊ฒฝํ ์๊ณ ์ถ์ผ๋ฉด ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์ ํ๋ก์ ํธ๋ ์ฐพ์๋ณด๊ณ ,
๊พธ์คํ ํ์ตํ๋ฉด์ ํฌํธํด๋ฆฌ์ค ๋ง๋ค์ด๊ฐ๋ฉด ๋ผ!
ํ์ดํ
! ๐ช๐ช๐ช
๐
ํ ์คํธ ๋ง์ด๋์ ์ธ๊ณ์ ์ค์ ๊ฒ์ ํ์ํฉ๋๋ค!
์ด์ ๋น์ ๋ ํ ์คํธ ๋ฐ์ดํฐ์ ์จ๊ฒจ์ง ๋ณด๋ฌผ์ ์ฐพ์๋ผ ์ ์์ด์ โจ
๐ ์ด ๊ธ์ด ๋์์ด ๋์๋ค๋ฉด ์ฃผ๋ณ ์ฌ๋๋ค๊ณผ ๊ณต์ ํด์ฃผ์ธ์!
๐ฌ ๊ถ๊ธํ ์ ์ด๋ ์ถ๊ฐ๋ก ์๊ณ ์ถ์ ๋ด์ฉ์ด ์๋ค๋ฉด ๋๊ธ๋ก ๋จ๊ฒจ์ฃผ์ธ์.
๐ ์ฌ๋ฌ๋ถ์ ํ
์คํธ ๋ง์ด๋ ์ฌ์ ์ ์์ํฉ๋๋ค!
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.