LoginSignup
2
3

More than 3 years have passed since last update.

sklearn.feature_extraction.text.CountVectrizerのanalyzerを試してみた

Last updated at Posted at 2019-05-29

概要

前回の記事で取り上げた、scikit-learnのCountVectorizeranalyzerキーワード引数について、変えると具体的にどう結果が変化するんだろう?
と思ったので一式コードを書いて確認。

環境

  • Windows10 Pro
  • Python 3.7.3
  • scikit-learn 0.21.2

コード

一通りのanalyzerキーワード引数を使ったインスタンスを作成する

from sklearn.feature_extraction.text import CountVectorizer

# 単語でN-gram
cv_word = CountVectorizer(analyzer = 'word')
# 文字でN-gram
cv_char = CountVectorizer(analyzer = 'char')
# 'char_wb'でN-gram
cv_wb = CountVectorizer(analyzer = 'char_wb')
# 呼び出し可能オブジェクト
cv_callable = CountVectorizer(analyzer = lambda x: [x])

対象にする単語と文章の配列を作成する

即興で書いたので、英文の不味さには目をつぶってください……

words = ['Tokyo', 'Osaka', 'Sendai', 'Fukuoka', 'Sapporo', 'Kouchi']
texts = ['Tokyo is the biggest city in japan.', 
    'Osaka is the secondary biggest city in japan.', 
    'Fukuoka is most nearly city from Koria, China in japan.',
    'Sendai called we ''Mori no Miyako''.',
    'Sapporo is most nearly city from Russia in japan.',
    'Kouchi is a japanese city, in japanese region in ''Shikoku''.']

単語の配列で、fit_transformでの特徴抽出と特徴を出力

print("CountVectorizer: target is words")

X = cv_word.fit_transform(words)
print("CountVectorizer: analyzer is word")
print("results array:")
print(str(X.toarray()))
print("feature_names:")
print(str(cv_word.get_feature_names()))

X = cv_char.fit_transform(words)
print("CountVectorizer: analyzer is char")
print("results array:")
print(str(X.toarray()))
print("feature_names:")
print(str(cv_char.get_feature_names()))

X = cv_wb.fit_transform(words)
print("CountVectorizer: analyzer is char_wb")
print("results array:")
print(str(X.toarray()))
print("feature_names:")
print(str(cv_wb.get_feature_names()))

X = cv_callable.fit_transform(words)
print("CountVectorizer: analyzer is callable object")
print("results array:")
print(str(X.toarray()))
print("feature_names:")
print(str(cv_callable.get_feature_names()))

単語で試した出力結果

CountVectorizer: target is words
CountVectorizer: analyzer is word
results array:
[[0 0 0 0 0 1]
 [0 0 1 0 0 0]
 [0 0 0 0 1 0]
 [1 0 0 0 0 0]
 [0 0 0 1 0 0]
 [0 1 0 0 0 0]]
feature_names:
['fukuoka', 'kouchi', 'osaka', 'sapporo', 'sendai', 'tokyo']
CountVectorizer: analyzer is char
results array:
[[0 0 0 0 0 0 0 1 0 2 0 0 0 1 0 1]
 [2 0 0 0 0 0 0 1 0 1 0 0 1 0 0 0]
 [1 0 1 1 0 0 1 0 1 0 0 0 1 0 0 0]
 [1 0 0 0 1 0 0 2 0 1 0 0 0 0 2 0]
 [1 0 0 0 0 0 0 0 0 2 2 1 1 0 0 0]
 [0 1 0 0 0 1 1 1 0 1 0 0 0 0 1 0]]
feature_names:
['a', 'c', 'd', 'e', 'f', 'h', 'i', 'k', 'n', 'o', 'p', 'r', 's', 't', 'u', 'y']
CountVectorizer: analyzer is char_wb
results array:
[[2 0 0 0 0 0 0 0 1 0 2 0 0 0 1 0 1]
 [2 2 0 0 0 0 0 0 1 0 1 0 0 1 0 0 0]
 [2 1 0 1 1 0 0 1 0 1 0 0 0 1 0 0 0]
 [2 1 0 0 0 1 0 0 2 0 1 0 0 0 0 2 0]
 [2 1 0 0 0 0 0 0 0 0 2 2 1 1 0 0 0]
 [2 0 1 0 0 0 1 1 1 0 1 0 0 0 0 1 0]]
feature_names:
[' ', 'a', 'c', 'd', 'e', 'f', 'h', 'i', 'k', 'n', 'o', 'p', 'r', 's', 't', 'u', 'y']
CountVectorizer: analyzer is callable object
results array:
[[0 0 0 0 0 1]
 [0 0 1 0 0 0]
 [0 0 0 0 1 0]
 [1 0 0 0 0 0]
 [0 0 0 1 0 0]
 [0 1 0 0 0 0]]
feature_names:
['Fukuoka', 'Kouchi', 'Osaka', 'Sapporo', 'Sendai', 'Tokyo']

結果から見えるもの

  • fit_transformした結果の配列をDataFrameの値部分と考えると、Indexを元の配列、Columnを特徴(feature_name)とすることが出来る。
    例として、一番最初の結果を表とすると以下のようになる。
Index fukuoka kouchi osaka sapporo sendai tokyo
Tokyo 0 0 0 0 0 1
Osaka 0 0 1 0 0 0
Sendai 0 0 0 0 1 0
Fukuoka 1 0 0 0 0 0
Sapporo 0 0 0 1 0 0
Kouchi 0 1 0 0 0 0
  • 文字列で指定した場合は特徴(feature_name)は基本的にlower case
    • 公式を見ると、キーワード引数としてlowercaseが存在し、デフォルト値がTrueとなっているので、ここの設定を変えることで変わるかも
  • 特徴(feature_name)は文字の昇順で格納される
  • analyzerchar_wbを指定した場合は、特徴(feature_name)に' 'が含まれる
    • おそらくは単語境界を' 'としている、2回カウントされるのは、前後を1回ずつ単語境界とカウントしているから?
  • カテゴリ変数のエンコーディングに使う場合、lower caseな単語のみが格納されていて、単純にOne-hotエンコードの結果を取得するだけだけなら、analyzer = 'word'でいけるのでは?

文章の配列で、fit_transformでの特徴抽出と特徴を出力

print("CountVectorizer: target is texts")

X = cv_word.fit_transform(texts)
print("CountVectorizer: analyzer is word")
print("results array:")
print(str(X.toarray()))
print("feature_names:")
print(str(cv_word.get_feature_names()))

X = cv_char.fit_transform(texts)
print("CountVectorizer: analyzer is char")
print("results array:")
print(str(X.toarray()))
print("feature_names:")
print(str(cv_char.get_feature_names()))

X = cv_wb.fit_transform(texts)
print("CountVectorizer: analyzer is char_wb")
print("results array:")
print(str(X.toarray()))
print("feature_names:")
print(str(cv_wb.get_feature_names()))

X = cv_callable.fit_transform(texts)
print("CountVectorizer: analyzer is callable object")
print("results array:")
print(str(X.toarray()))
print("feature_names:")
print(str(cv_callable.get_feature_names()))

文章で試した出力結果

CountVectorizer: target is texts
CountVectorizer: analyzer is word
results array:
[[1 0 0 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0]
 [1 0 0 1 0 0 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0]
 [0 0 1 1 1 1 1 1 1 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0]
 [0 1 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 1 0 0 0 1]
 [0 0 0 1 1 0 1 1 1 0 0 0 0 0 1 1 0 0 0 1 1 0 0 0 0 0 0]
 [0 0 0 1 0 0 2 1 0 2 0 1 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0]]
feature_names:
['biggest', 'called', 'china', 'city', 'from', 'fukuoka', 'in', 'is', 'japan', 'japanese', 'koria', 'kouchi', 'miyako', 'mori', 'most', 'nearly', 'no', 'osaka', 'region', 'russia', 'sapporo', 'secondary', 'sendai', 'shikoku', 'the', 'tokyo', 'we']
CountVectorizer: analyzer is char
results array:
[[6 0 1 2 1 1 0 2 0 2 1 4 1 1 0 0 2 2 1 0 2 4 0 0 2]
 [7 0 1 5 1 2 1 3 0 2 1 4 1 1 0 0 3 2 1 1 4 3 0 0 2]
 [9 1 1 6 0 2 0 1 2 0 1 5 1 3 1 2 4 4 1 3 2 2 2 0 2]
 [5 0 1 3 0 1 2 3 0 0 0 3 0 1 2 2 2 3 0 1 1 0 0 1 1]
 [8 0 1 5 0 1 0 1 1 0 0 4 1 0 1 2 3 4 3 4 5 2 1 0 2]
 [9 1 1 5 0 2 0 5 0 1 2 7 2 3 0 0 5 3 2 1 4 1 2 0 1]]
feature_names:
[' ', ',', '.', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'w', 'y']
CountVectorizer: analyzer is char_wb
results array:
[[14  0  1  2  1  1  0  2  0  2  1  4  1  1  0  0  2  2  1  0  2  4  0  0
   2]
 [16  0  1  5  1  2  1  3  0  2  1  4  1  1  0  0  3  2  1  1  4  3  0  0
   2]
 [20  1  1  6  0  2  0  1  2  0  1  5  1  3  1  2  4  4  1  3  2  2  2  0
   2]
 [12  0  1  3  0  1  2  3  0  0  0  3  0  1  2  2  2  3  0  1  1  0  0  1
   1]
 [18  0  1  5  0  1  0  1  1  0  0  4  1  0  1  2  3  4  3  4  5  2  1  0
   2]
 [20  1  1  5  0  2  0  5  0  1  2  7  2  3  0  0  5  3  2  1  4  1  2  0
   1]]
feature_names:
[' ', ',', '.', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'w', 'y']
CountVectorizer: analyzer is callable object
results array:
[[0 0 0 0 0 1]
 [0 0 1 0 0 0]
 [1 0 0 0 0 0]
 [0 0 0 0 1 0]
 [0 0 0 1 0 0]
 [0 1 0 0 0 0]]
feature_names:
['Fukuoka is most nearly city from Koria, China in japan.', 'Kouchi is a japanese city, in japanese region in Shikoku.', 'Osaka is the secondary biggest city in japan.', 'Sapporo is most nearly city from Russia in japan.', 'Sendai called we Mori no Miyako.', 'Tokyo is the biggest city in japan.']

結果から見えるもの

  • analyzercharchar_wbを指定した場合の結果を比較すると、analyzer = 'char'の場合の' 'の抽出回数をxとしたとき、analyzer = 'char_wb'の場合の' 'の抽出回数は2x+2回になる
    • analyzer = 'char'の場合は単純に文章中に含まれる' 'の数、analyzer = 'char_wb'の場合は加えて単語の前後が' 'ではない場合も境界として' 'に計上している
  • analyzer = lambda x: [x]としたインスタンスで実行した場合、入力した文章が特徴(feature_name)としてそのまま戻ってくる。
2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3