scikit-learn.feature_extraction.textのTfidfVectorizerを検証する
arXivのRSSで取得できる最新情報から自分に合うものをレコメンドしてくれるSlack Botを作っています。
まずはTF-IDFを使ってレコメンドを作る予定なので、scikit-learnのTfidfVectorizerを初めて触ってみました。
以下では、 http://scikit-learn.org/stable/modules/feature_extraction.html#common-vectorizer-usage を元にして、使う機能を検証してみます。
テストで使うコーパスは上記のURLにあるものを使います。
corpus = [ 'This is the first document.', 'This is the second second document.', 'And the third one.', 'Is this the first document?', ]
TF-IDFを計算する
初めにTfidfVectorizerクラスのインスタンスを作成して設定を確認してみます。
from sklearn.feature_extraction.text import TfidfVectorizer vectorizer = TfidfVectorizer() vectorizer
TfidfVectorizer(analyzer='word', binary=False, decode_error='strict',
dtype=<class 'numpy.int64'>, encoding='utf-8', input='content',
lowercase=True, max_df=1.0, max_features=None, min_df=1,
ngram_range=(1, 1), norm='l2', preprocessor=None, smooth_idf=True,
stop_words=None, strip_accents=None, sublinear_tf=False,
token_pattern='(?u)\\b\\w\\w+\\b', tokenizer=None, use_idf=True,
vocabulary=None)
パラメータが多いですが、現在考えている用途で使いそうなのは次の2つです。
ngram_range: N-gramのNの下限と上限をタプルで指定します。
ngram_range : tuple (min_n, max_n)
The lower and upper boundary of the range of n-values for different n-grams to be extracted. All values of n such that min_n <= n <= max_n will be used.
stop_words: ストップワード。現在の用途では"english"を選択しておけば良さそう。
stop_words : string {‘english’}, list, or None (default)
If a string, it is passed to _check_stop_list and the appropriate stop list is returned. ‘english’ is currently the only supported string value.
If a list, that list is assumed to contain stop words, all of which will be removed from the resulting tokens. Only applies if analyzer == 'word'.
If None, no stop words will be used. max_df can be set to a value in the range [0.7, 1.0) to automatically detect and filter stop words based on intra corpus document frequency of terms.
(引用部分の出所) TfidfVectorizerのAPIリファレンス
fit_transform
メソッドでコーパスをトークン化して対応するTF-IDFの値を計算してくれます。
X = vectorizer.fit_transform(corpus) X
<4x9 sparse matrix of type '<class 'numpy.float64'>'
with 19 stored elements in Compressed Sparse Row format>
上の行列の中身を確認するためにprint(X)
とすると...
print(X)
(0, 8) 0.438776742859
(0, 3) 0.438776742859
(0, 6) 0.358728738248
(0, 2) 0.541976569726
(0, 1) 0.438776742859
(1, 8) 0.272301467523
(1, 3) 0.272301467523
(1, 6) 0.222624292325
(1, 1) 0.272301467523
(1, 5) 0.853225736145
(2, 6) 0.28847674875
(2, 0) 0.552805319991
(2, 7) 0.552805319991
(2, 4) 0.552805319991
(3, 8) 0.438776742859
(3, 3) 0.438776742859
(3, 6) 0.358728738248
(3, 2) 0.541976569726
(3, 1) 0.438776742859
となります。
初めてこのアウトプットを見た時、「"(0, 8)"というのは行列の0行8列を指している」と思いましたが、行列の構造がまったく分からなかったので、このような簡単な検証をすることにしました。
構造を理解してからこのアウトプットを見ると、下の行列よりも見やすいと言えそうです。
行列の構造を理解する
TF-IDFの行列はtoarray
メソッドで取り出すことができます。
X.toarray()
array([[ 0. , 0.43877674, 0.54197657, 0.43877674, 0. ,
0. , 0.35872874, 0. , 0.43877674],
[ 0. , 0.27230147, 0. , 0.27230147, 0. ,
0.85322574, 0.22262429, 0. , 0.27230147],
[ 0.55280532, 0. , 0. , 0. , 0.55280532,
0. , 0.28847675, 0.55280532, 0. ],
[ 0. , 0.43877674, 0.54197657, 0.43877674, 0. ,
0. , 0.35872874, 0. , 0.43877674]])
上で取り出した行列の行はコーパスの各文のインデックスに対応し、列は各文から抽出されたトークンになっています。
実際にコーパスは
corpus
['This is the first document.',
'This is the second second document.',
'And the third one.',
'Is this the first document?']
となっています。
一方でトークンは
vectorizer.get_feature_names()
['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']
で、文に含まれているトークンのところにTF-IDFの値が入っています。
まとめ
sklearnでTF-IDFを算出する方法を検証しました。これでレコメンド部分が書けそうです。
ちなみに、sklearn.feature_extraction.text
のVectorizerにはCountVectorizer
もありますが、基本的な動作は一緒です。
したがって、これまでTfidfVectorizer
で行ってきた操作はCountVectorizer
でも同じように動きます。
参考URL
- TfidfVectorizerのAPIリファレンス
http://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#sklearn.feature_extraction.text.TfidfVectorizer sklearn.feature_extraction.text
のVectorizerの共通した利用方法
http://scikit-learn.org/stable/modules/feature_extraction.html#common-vectorizer-usage