中野智文のブログ

データ・マエショリストのメモ

sklearn の DictVectorizer を使って学習して再び重みを dict 形式にする

背景

sklearn のライブラリに、学習データがdict の配列のときに、sklearn で使えるスパース(疎)な形式に変換する DictVectorizer がある。 この DictVectorizer の説明を見ると、たしかに色々な形式に変換できるようではあるが、実際にどのような形式に変換すれば学習が行えるかまでは書かれていない。 学習器の種類によりスパースな形式が扱えないものも存在するが、liblinear はスパースに対応しているので、liblinear でも使用例が多そうな logistic regression の例を示そうと思う。

DictVectorizer を使って logistic regression で学習する例

次のようなデータを学習したい、すなわち、dict 形式がリストになっている。

measurements = [
    {'city': 'Dubai', 'temperature': 31.0, 'country': 'U.A.E.'},
    {'city': 'London', 'country': 'U.K.', 'temperature': 27.0},
    {'city': 'San Fransisco', 'country': 'U.S.', 'temperature': 24.0},
]

DictVectorizerを初期化する。下記ではデフォルトで初期化するが、separator などが設定できることが分かる。

from sklearn.feature_extraction import DictVectorizer
vec = DictVectorizer()
vec
DictVectorizer(dtype=<type 'numpy.float64'>, separator='=', sort=True,
        sparse=True)

そして、sklearn で学習できる、sparse matrix に変換

X = vec.fit_transform(measurements)
print X
  (0, 0)    1.0
  (0, 3)    1.0
  (0, 6)    31.0
  (1, 1)    1.0
  (1, 4)    1.0
  (1, 6)    27.0
  (2, 2)    1.0
  (2, 5)    1.0
  (2, 6)    24.0

次のようにすれば、sparse matrix の各番号に対応した素性名が取得できる。

print vec.get_feature_names()
['city=Dubai', 'city=London', 'city=San Fransisco', 'country=U.A.E.', 'country=U.K.', 'country=U.S.', 'temperature']

では、学習を始めるために、教師データ(y)を作成

import numpy as np
y = np.array([1,0,0])

この y と先に作った sparce matrix の X で学習。

from sklearn.linear_model import LogisticRegression
logistic = LogisticRegression()
logistic.fit(X, y)
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
          intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
          penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
          verbose=0, warm_start=False)

学習は完了したので、重みを取り出してみよう。

logistic.coef_
array([[ 0.43215653, -0.25978198, -0.26661549,  0.43215653, -0.25978198,
        -0.26661549, -0.01603272]])

今回は2クラス分類なので、配列の0番目のを取れば良い。これを再び先の素性名と組み合わせ、辞書の形式にしてみる。

w = dict(zip(vec.get_feature_names(), logistic.coef_[0]))
w
{'city=Dubai': 0.43215653143933291,
 'city=London': -0.25978198285599019,
 'city=San Fransisco': -0.26661548568954441,
 'country=U.A.E.': 0.43215653143933291,
 'country=U.K.': -0.25978198285599019,
 'country=U.S.': -0.26661548568954441,
 'temperature': -0.016032719041480584}

切片を決して忘れるなよ。

b = logistic.intercept_[0]
b
-0.094240937106201683

まとめ

  • vec.fit_transform(dict) でdict形式から学習形式に変換できる
  • 変換後の素性名は vec.get_feature_names() で取得