TfidfVectorizer - smart1004/doc GitHub Wiki
from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.pipeline import Pipeline
tfidf = TfidfVectorizer(tokenizer=tokenizer, ngram_range=(2,2), min_df=2, stop_words = stops, max_features = 20000, lowercase = True, sublinear_tf=True, use_idf=True)
tfidf_matrix ์๋ค๋ค์ ์ ์ฅํด๋๊ณ ๋ถ๋ฌ์ ์ฌ์ฉํ ์ ์๋๊ฐ?
๋ฏธ๋ฆฌ ์ ์ฒ๋ฆฌ๋ฅผ ํด๋์ง ์์ผ๋ฉด ๋ง๋๋๋ฐ ์๊ฐ์ด ๋ง์ด ๊ฑธ๋ฆด ๊ฒ ๊ฐ๋ค
https://datascienceschool.net/view-notebook/3e7aadbf88ed4f0d87a76f9ddc925d69/
Scikit-Learn์ ๋ฌธ์ ์ ์ฒ๋ฆฌ ๊ธฐ๋ฅยถ BOW (Bag of Words)ยถ ๋ฌธ์๋ฅผ ์ซ์ ๋ฒกํฐ๋ก ๋ณํํ๋ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ์ BOW (Bag of Words) ์ด๋ค. BOW ๋ฐฉ๋ฒ์์๋ ์ ์ฒด ๋ฌธ์ {d1,d2,โฆ,dn} ๋ฅผ ๊ตฌ์ฑํ๋ ๊ณ ์ ๋ ๋จ์ด์ฅ(vocabulary) {t1,t2,โฆ,tm} ๋ฅผ ๋ง๋ค๊ณ di ๋ผ๋ ๊ฐ๋ณ ๋ฌธ์์ ๋จ์ด์ฅ์ ํด๋นํ๋ ๋จ์ด๋ค์ด ํฌํจ๋์ด ์๋์ง๋ฅผ ํ์ํ๋ ๋ฐฉ๋ฒ์ด๋ค.
xi,j=๋ฌธ์ di๋ด์ ๋จ์ด tj์ ์ถํ ๋น๋
๋๋
xi,j={0,1.๋ง์ฝ ๋จ์ด tj๊ฐ ๋ฌธ์ di ์์ ์์ผ๋ฉด๋ง์ฝ ๋จ์ด tj๊ฐ ๋ฌธ์ di ์์ ์์ผ๋ฉด
Scikit-Learn ์ ๋ฌธ์ ์ ์ฒ๋ฆฌ ๊ธฐ๋ฅยถ Scikit-Learn ์ feature_extraction ์๋ธํจํค์ง์ feature_extraction.text ์๋ธ ํจํค์ง๋ ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ์ ์ฒ๋ฆฌ์ฉ ํด๋์ค๋ฅผ ์ ๊ณตํ๋ค.
DictVectorizer:
๊ฐ ๋จ์ด์ ์๋ฅผ ์ธ์ด๋์ ์ฌ์ ์์ BOW ๋ฒกํฐ๋ฅผ ๋ง๋ ๋ค. CountVectorizer:
๋ฌธ์ ์งํฉ์์ ๋จ์ด ํ ํฐ์ ์์ฑํ๊ณ ๊ฐ ๋จ์ด์ ์๋ฅผ ์ธ์ด BOW ์ธ์ฝ๋ฉํ ๋ฒกํฐ๋ฅผ ๋ง๋ ๋ค. TfidfVectorizer:
CountVectorizer์ ๋น์ทํ์ง๋ง TF-IDF ๋ฐฉ์์ผ๋ก ๋จ์ด์ ๊ฐ์ค์น๋ฅผ ์กฐ์ ํ BOW ๋ฒกํฐ๋ฅผ ๋ง๋ ๋ค. HashingVectorizer:
ํด์ ํจ์(hash function)์ ์ฌ์ฉํ์ฌ ์ ์ ๋ฉ๋ชจ๋ฆฌ์ ๋น ๋ฅธ ์๋๋ก BOW ๋ฒกํฐ๋ฅผ ๋ง๋ ๋ค. DictVectorizerยถ DictVectorizer๋ feature_extraction ์๋ธ ํจํค์ง์์ ์ ๊ณตํ๋ค. ๋ฌธ์์์ ๋จ์ด์ ์ฌ์ฉ ๋น๋๋ฅผ ๋ํ๋ด๋ ๋์ ๋๋ฆฌ ์ ๋ณด๋ฅผ ์ ๋ ฅ๋ฐ์ BOW ์ธ์ฝ๋ฉํ ์์น ๋ฒกํฐ๋ก ๋ณํํ๋ค.
In [1]: from sklearn.feature_extraction import DictVectorizer v = DictVectorizer(sparse=False) D = [{'A': 1, 'B': 2}, {'B': 3, 'C': 1}] X = v.fit_transform(D) X array([[1., 2., 0.], [0., 3., 1.]])
In [2]: v.feature_names_ ['A', 'B', 'C'] In [3]: v.transform({'C': 4, 'D': 3}) array(0., 0., 4.)
@@ CountVectorizerยถ CountVectorizer๋ ๋ค์๊ณผ ๊ฐ์ ์ธ๊ฐ์ง ์์ ์ ์ํํ๋ค.
๋ฌธ์๋ฅผ ํ ํฐ ๋ฆฌ์คํธ๋ก ๋ณํํ๋ค.
๊ฐ ๋ฌธ์์์ ํ ํฐ์ ์ถํ ๋น๋๋ฅผ ์ผ๋ค.
๊ฐ ๋ฌธ์๋ฅผ BOW ์ธ์ฝ๋ฉ ๋ฒกํฐ๋ก ๋ณํํ๋ค.
In [4]:
from sklearn.feature_extraction.text import CountVectorizer
corpus = [
'This is the first document.',
'This is the second second document.',
'And the third one.',
'Is this the first document?',
'The last document?',
]
vect = CountVectorizer()
vect.fit(corpus)
vect.vocabulary_
{'this': 9,
'is': 3,
'the': 7,
'first': 2,
'document': 1,
'second': 6,
'and': 0,
'third': 8,
'one': 5,
'last': 4}
In [5]:
vect.transform(['This is the second document.']).toarray()
array(0, 1, 0, 1, 0, 0, 1, 1, 0, 1)
In [6]:
vect.transform(['Something completely new.']).toarray()
array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
In [7]:
vect.transform(corpus).toarray()
array([[0, 1, 1, 1, 0, 0, 0, 1, 0, 1],
[0, 1, 0, 1, 0, 0, 2, 1, 0, 1],
[1, 0, 0, 0, 0, 1, 0, 1, 1, 0],
[0, 1, 1, 1, 0, 0, 0, 1, 0, 1],
[0, 1, 0, 0, 1, 0, 0, 1, 0, 0]])
CountVectorizer๋ ์ด๋ฌํ ์์ ์ ํ๊ธฐ ์ํ ๋ค์๊ณผ ๊ฐ์ ์ธ์๋ฅผ ๊ฐ์ง ์ ์๋ค.
stop_words : ๋ฌธ์์ด {โenglishโ}, ๋ฆฌ์คํธ ๋๋ None (๋ํดํธ) stop words ๋ชฉ๋ก.โenglishโ์ด๋ฉด ์์ด์ฉ ์คํ ์๋ ์ฌ์ฉ. analyzer : ๋ฌธ์์ด {โwordโ, โcharโ, โchar_wbโ} ๋๋ ํจ์ ๋จ์ด n-๊ทธ๋จ, ๋ฌธ์ n-๊ทธ๋จ, ๋จ์ด ๋ด์ ๋ฌธ์ n-๊ทธ๋จ token_pattern : string ํ ํฐ ์ ์์ฉ ์ ๊ท ํํ์ tokenizer : ํจ์ ๋๋ None (๋ํดํธ) ํ ํฐ ์์ฑ ํจ์ . ngram_range : (min_n, max_n) ํํ n-๊ทธ๋จ ๋ฒ์ max_df : ์ ์ ๋๋ [0.0, 1.0] ์ฌ์ด์ ์ค์. ๋ํดํธ 1 ๋จ์ด์ฅ์ ํฌํจ๋๊ธฐ ์ํ ์ต๋ ๋น๋ min_df : ์ ์ ๋๋ [0.0, 1.0] ์ฌ์ด์ ์ค์. ๋ํดํธ 1 ๋จ์ด์ฅ์ ํฌํจ๋๊ธฐ ์ํ ์ต์ ๋น๋ Stop Wordsยถ Stop Words ๋ ๋ฌธ์์์ ๋จ์ด์ฅ์ ์์ฑํ ๋ ๋ฌด์ํ ์ ์๋ ๋จ์ด๋ฅผ ๋งํ๋ค. ๋ณดํต ์์ด์ ๊ด์ฌ๋ ์ ์์ฌ, ํ๊ตญ์ด์ ์กฐ์ฌ ๋ฑ์ด ์ฌ๊ธฐ์ ํด๋นํ๋ค. stop_words ์ธ์๋ก ์กฐ์ ํ ์ ์๋ค.
In [8]: vect = CountVectorizer(stop_words=["and", "is", "the", "this"]).fit(corpus) vect.vocabulary_ {'first': 1, 'document': 0, 'second': 4, 'third': 5, 'one': 3, 'last': 2} In [9]: vect = CountVectorizer(stop_words="english").fit(corpus) vect.vocabulary_ {'document': 0, 'second': 1} ํ ํฐยถ analyzer, tokenizer, token_pattern ๋ฑ์ ์ธ์๋ก ์ฌ์ฉํ ํ ํฐ ์์ฑ๊ธฐ๋ฅผ ์ ํํ ์ ์๋ค.
In [10]: vect = CountVectorizer(analyzer="char").fit(corpus) vect.vocabulary_ {'t': 16, 'h': 8, 'i': 9, 's': 15, ' ': 0, 'e': 6, 'f': 7, 'r': 14, 'd': 5, 'o': 13, 'c': 4, 'u': 17, 'm': 11, 'n': 12, '.': 1, 'a': 3, '?': 2, 'l': 10} In [11]: vect = CountVectorizer(token_pattern="t\w+").fit(corpus) vect.vocabulary_ {'this': 2, 'the': 0, 'third': 1} In [12]: import nltk
vect = CountVectorizer(tokenizer=nltk.word_tokenize).fit(corpus) vect.vocabulary_ {'this': 11, 'is': 5, 'the': 9, 'first': 4, 'document': 3, '.': 0, 'second': 8, 'and': 2, 'third': 10, 'one': 7, '?': 1, 'last': 6} n-๊ทธ๋จยถ n-๊ทธ๋จ์ ๋จ์ด์ฅ ์์ฑ์ ์ฌ์ฉํ ํ ํฐ์ ํฌ๊ธฐ๋ฅผ ๊ฒฐ์ ํ๋ค. ๋ชจ๋ ธ๊ทธ๋จ(1-๊ทธ๋จ)์ ํ ํฐ ํ๋๋ง ๋จ์ด๋ก ์ฌ์ฉํ๋ฉฐ ๋ฐ์ด๊ทธ๋จ(2-๊ทธ๋จ)์ ๋ ๊ฐ์ ์ฐ๊ฒฐ๋ ํ ํฐ์ ํ๋์ ๋จ์ด๋ก ์ฌ์ฉํ๋ค.
In [13]: vect = CountVectorizer(ngram_range=(2, 2)).fit(corpus) vect.vocabulary_ {'this is': 12, 'is the': 2, 'the first': 7, 'first document': 1, 'the second': 9, 'second second': 6, 'second document': 5, 'and the': 0, 'the third': 10, 'third one': 11, 'is this': 3, 'this the': 13, 'the last': 8, 'last document': 4} In [14]: vect = CountVectorizer(ngram_range=(1, 2), token_pattern="t\w+").fit(corpus) vect.vocabulary_ {'this': 3, 'the': 0, 'this the': 4, 'third': 2, 'the third': 1} ๋น๋์ยถ max_df, min_df ์ธ์๋ฅผ ์ฌ์ฉํ์ฌ ๋ฌธ์์์ ํ ํฐ์ด ๋ํ๋ ํ์๋ฅผ ๊ธฐ์ค์ผ๋ก ๋จ์ด์ฅ์ ๊ตฌ์ฑํ ์๋ ์๋ค. ํ ํฐ์ ๋น๋๊ฐ max_df๋ก ์ง์ ํ ๊ฐ์ ์ด๊ณผ ํ๊ฑฐ๋ min_df๋ก ์ง์ ํ ๊ฐ๋ณด๋ค ์์ ๊ฒฝ์ฐ์๋ ๋ฌด์ํ๋ค. ์ธ์ ๊ฐ์ ์ ์์ธ ๊ฒฝ์ฐ ํ์, ๋ถ๋์์์ ์ธ ๊ฒฝ์ฐ ๋น์ค์ ๋ปํ๋ค.
In [15]: vect = CountVectorizer(max_df=4, min_df=2).fit(corpus) vect.vocabulary_, vect.stop_words_ ({'this': 3, 'is': 2, 'first': 1, 'document': 0}, {'and', 'last', 'one', 'second', 'the', 'third'}) In [16]: vect.transform(corpus).toarray().sum(axis=0) array([4, 2, 3, 3]) TF-IDFยถ TF-IDF(Term Frequency โ Inverse Document Frequency) ์ธ์ฝ๋ฉ์ ๋จ์ด๋ฅผ ๊ฐฏ์ ๊ทธ๋๋ก ์นด์ดํธํ์ง ์๊ณ ๋ชจ๋ ๋ฌธ์์ ๊ณตํต์ ์ผ๋ก ๋ค์ด์๋ ๋จ์ด์ ๊ฒฝ์ฐ ๋ฌธ์ ๊ตฌ๋ณ ๋ฅ๋ ฅ์ด ๋จ์ด์ง๋ค๊ณ ๋ณด์ ๊ฐ์ค์น๋ฅผ ์ถ์ํ๋ ๋ฐฉ๋ฒ์ด๋ค.
๊ตฌ์ ์ ์ผ๋ก๋ ๋ฌธ์ d (document)์ ๋จ์ด t ์ ๋ํด ๋ค์๊ณผ ๊ฐ์ด ๊ณ์ฐํ๋ค.
tf-idf(d,t)=tf(d,t)โ idf(t)
์ฌ๊ธฐ์์
tf(d,t) : term frequency. ํน์ ํ ๋จ์ด์ ๋น๋์ idf(t) : inverse document frequency. ํน์ ํ ๋จ์ด๊ฐ ๋ค์ด ์๋ ๋ฌธ์์ ์์ ๋ฐ๋น๋กํ๋ ์
idf(d,t)=logn1+df(t)
n : ์ ์ฒด ๋ฌธ์์ ์
df(t) : ๋จ์ด t ๋ฅผ ๊ฐ์ง ๋ฌธ์์ ์ In [17]: from sklearn.feature_extraction.text import TfidfVectorizer In [18]: tfidv = TfidfVectorizer().fit(corpus) tfidv.transform(corpus).toarray() array([[0. , 0.38947624, 0.55775063, 0.4629834 , 0. , 0. , 0. , 0.32941651, 0. , 0.4629834 ], [0. , 0.24151532, 0. , 0.28709733, 0. , 0. , 0.85737594, 0.20427211, 0. , 0.28709733], [0.55666851, 0. , 0. , 0. , 0. , 0.55666851, 0. , 0.26525553, 0.55666851, 0. ], [0. , 0.38947624, 0.55775063, 0.4629834 , 0. , 0. , 0. , 0.32941651, 0. , 0.4629834 ], [0. , 0.45333103, 0. , 0. , 0.80465933, 0. , 0. , 0.38342448, 0. , 0. ]]) Hashing Trickยถ CountVectorizer๋ ๋ชจ๋ ์์ ์ ๋ฉ๋ชจ๋ฆฌ ์์์ ์ํํ๋ฏ๋ก ์ฒ๋ฆฌํ ๋ฌธ์์ ํฌ๊ธฐ๊ฐ ์ปค์ง๋ฉด ์๋๊ฐ ๋๋ ค์ง๊ฑฐ๋ ์คํ์ด ๋ถ๊ฐ๋ฅํด์ง๋ค. ์ด ๋ HashingVectorizer๋ฅผ ์ฌ์ฉํ๋ฉด ํด์ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๋จ์ด์ ๋ํ ์ธ๋ฑ์ค ๋ฒํธ๋ฅผ ์์ฑํ๊ธฐ ๋๋ฌธ์ ๋ฉ๋ชจ๋ฆฌ ๋ฐ ์คํ ์๊ฐ์ ์ค์ผ ์ ์๋ค.
In [19]: from sklearn.datasets import fetch_20newsgroups twenty = fetch_20newsgroups() len(twenty.data) 11314 In [20]: %time CountVectorizer().fit(twenty.data).transform(twenty.data); CPU times: user 8.33 s, sys: 120 ms, total: 8.45 s Wall time: 8.46 s <11314x130107 sparse matrix of type '' with 1787565 stored elements in Compressed Sparse Row format> In [21]: from sklearn.feature_extraction.text import HashingVectorizer hv = HashingVectorizer(n_features=300000) In [22]: %time hv.transform(twenty.data); CPU times: user 3.97 s, sys: 80 ms, total: 4.05 s Wall time: 2.49 s <11314x300000 sparse matrix of type '' with 1786336 stored elements in Compressed Sparse Row format> ์ยถ ๋ค์์ Scikit-Learn์ ๋ฌธ์์ด ๋ถ์๊ธฐ๋ฅผ ์ฌ์ฉํ์ฌ ์น์ฌ์ดํธ์ ํน์ ํ ๋จ์ด๊ฐ ์ด๋ ์ ๋ ์ฌ์ฉ๋์๋์ง ๋น๋์๋ฅผ ์์๋ณด๋ ์ฝ๋์ด๋ค.
In [23]: from urllib.request import urlopen import json import string from konlpy.utils import pprint from konlpy.tag import Hannanum hannanum = Hannanum()
f = urlopen("https://www.datascienceschool.net/download-notebook/708e711429a646818b9dcbb581e0c10a/") json = json.loads(f.read()) cell = ["\n".join(c["source"]) for c in json["cells"] if c["cell_type"] == "markdown"] docs = [w for w in hannanum.nouns(" ".join(cell)) if ((not w[0].isnumeric()) and (w[0] not in string.punctuation))] ์ฌ๊ธฐ์์๋ ํ๋์ ๋ฌธ์๊ฐ ํ๋์ ๋จ์ด๋ก๋ง ์ด๋ฃจ์ด์ ธ ์๋ค. ๋ฐ๋ผ์ CountVectorizer๋ก ์ด ๋ฌธ์ ์งํฉ์ ์ฒ๋ฆฌํ๋ฉด ๊ฐ ๋ฌธ์๋ ํ๋์ ์์๋ง 1์ด๊ณ ๋๋จธ์ง ์์๋ 0์ธ ๋ฒกํฐ๊ฐ ๋๋ค. ์ด ๋ฒกํฐ์ ํฉ์ผ๋ก ๋น๋๋ฅผ ์์๋ณด์๋ค.
In [24]: vect = CountVectorizer().fit(docs) count = vect.transform(docs).toarray().sum(axis=0) idx = np.argsort(-count) count = count[idx] feature_name = np.array(vect.get_feature_names())[idx] plt.bar(range(len(count)), count) plt.show()
In [25]: pprint(list(zip(feature_name, count))[:10]) [('์ปจํ ์ด๋', 81), ('๋์ปค', 41), ('๋ช ๋ น', 34), ('์ด๋ฏธ์ง', 33), ('์ฌ์ฉ', 26), ('๊ฐ๋', 14), ('์ค์ง', 13), ('mingw64', 13), ('์ญ์ ', 12), ('์ด๋ฆ', 11)]