scikit learn で DataFrameから色々なスパースな型に変換して学習
背景
scikit learn で学習しようとすると、メモリーを使い尽くす。
色々なスパースな型に変換して学習
準備
まず、データは次のものを利用。
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}, ]
ただし変換をして、DataFrame用に。
x_column_dict = {} for d in measurements: for c, v in d.items(): if c in x_column_dict: x_column_dict[c].append(v) else: x_column_dict[c] = [v] x_column_dict
{'city': ['Dubai', 'London', 'San Fransisco'],
'country': ['U.A.E.', 'U.K.', 'U.S.'],
'temperature': [31.0, 27.0, 24.0]}
import pandas as pd df = pd.DataFrame(x_column_dict) df
city | country | temperature | |
---|---|---|---|
0 | Dubai | U.A.E. | 31.0 |
1 | London | U.K. | 27.0 |
2 | San Fransisco | U.S. | 24.0 |
教師データを準備
import numpy as np y = np.array([1,0,0])
get_dummies で sparse=True
を使う。
X = pd.get_dummies(df, sparse=True)
X.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3 entries, 0 to 2
Data columns (total 7 columns):
temperature 3 non-null float64
city_Dubai 3 non-null uint8
city_London 3 non-null uint8
city_San Fransisco 3 non-null uint8
country_U.A.E. 3 non-null uint8
country_U.K. 3 non-null uint8
country_U.S. 3 non-null uint8
dtypes: float64(1), uint8(6)
memory usage: 114.0 bytes
↑ SparseDataFrame
型ではないのですが、詐欺ですか?
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)
一応学習はできる(DataFrame
型なので)
to_sparse()
を使う。
X = pd.get_dummies(df).to_sparse() X.info()
<class 'pandas.core.sparse.frame.SparseDataFrame'>
RangeIndex: 3 entries, 0 to 2
Data columns (total 7 columns):
temperature 3 non-null float64
city_Dubai 3 non-null uint8
city_London 3 non-null uint8
city_San Fransisco 3 non-null uint8
country_U.A.E. 3 non-null uint8
country_U.K. 3 non-null uint8
country_U.S. 3 non-null uint8
dtypes: float64(1), uint8(6)
memory usage: 114.0 bytes
確かに SparseDataFrame
型に変換されている。ただしメモリの使用量は同じ。
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)
学習できたことを確認。
さらに、fill_value=0
を使う。
X = pd.get_dummies(df).to_sparse(fill_value=0)
X.info()
<class 'pandas.core.sparse.frame.SparseDataFrame'>
RangeIndex: 3 entries, 0 to 2
Data columns (total 7 columns):
temperature 3 non-null float64
city_Dubai 3 non-null uint8
city_London 3 non-null uint8
city_San Fransisco 3 non-null uint8
country_U.A.E. 3 non-null uint8
country_U.K. 3 non-null uint8
country_U.S. 3 non-null uint8
dtypes: float64(1), uint8(6)
memory usage: 102.0 bytes
↑メモリの使用量が減っている。ただしこれは学習前の話。
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)
↑実際には上記の処理を行っても、かなりメモリを使ってしまう。
New!! さらに coo に変換する。
[https://pandas.pydata.org/pandas-docs/stable/generated/pandas.SparseSeries.to_coo.html]
さらに、scipy の sparse matrix に変換できるらしい。(@hagino3000 さんに教えてもらった)
X = pd.get_dummies(df).to_sparse(fill_value=0) Xcoo = X.to_coo() print Xcoo
(0, 0) 31.0
(1, 0) 27.0
(2, 0) 24.0
(0, 1) 1.0
(1, 2) 1.0
(2, 3) 1.0
(0, 4) 1.0
(1, 5) 1.0
(2, 6) 1.0
logistic.fit(Xcoo, 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.01603272, 0.43215653, -0.25978198, -0.26661549, 0.43215653,
-0.25978198, -0.26661549]])
w = dict(zip(X.columns.tolist(), 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.016032719041480594}
b = logistic.intercept_[0]
b
-0.094240937106201669
まとめ
get_dummies
のsparse=True
オプションは意味がないto_sparse(fill_value=0)
で0を除去。to_coo()
で学習時のメモリを最小化。(@hagino3000 さん感謝)
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()
で取得
jupyter notebook から dataflow する超短いメモ
背景
jupyter notebook から dataflow 使いたい。
やること
- python2
- 次のチュートリアルを cloud shell とローカルのマシンで実行 TensorFlow と Cloud Dataflow を使用したバッチ予測 | ソリューション | Google Cloud Platform
- qiita.com ただし、utils を options に置換
- NameError の対応 よくある質問 | Cloud Dataflow のドキュメント | Google Cloud Platform
- pipでインストールしたい Managing Pipeline Dependencies (Python) | Cloud Dataflow Documentation | Google Cloud Platform
setup_options = options.view_as( beam.options.pipeline_options.SetupOptions) setup_options.save_main_session = True setup_options.requirements_file = 'requirements.txt'
requirements.txt:
ipython==5.5.0
これがないと、IPython.core
がないみたなエラー。
liblinear の切片を忘れていませんか?
背景
liblinear の学習で、切片を忘れているのを見た。幸いプロダクトではない。
切片とは、英語で言うと intercept (知っとるわw)
このページを見に来た人は特に切片の説明自体はしなくてもよいと思う。どのように取得するのかは、
scikit-learn だと、
sklearn.linear_model.LogisticRegression — scikit-learn 0.19.0 documentation
Attributes という項目にあるので、忘れないように。
intercept_ : array, shape (1,) or (n_classes,) Intercept (a.k.a. bias) added to the decision function. If fit_intercept is set to False, the intercept is set to zero. intercept_ is of shape(1,) when the problem is binary.
とある。どのように使うかはいい例が見つからなかったので書かないが、切片の意味が分かっていれば特に必要ないと思う。
python ライブラリの gcloud(google.cloud) の storage の blob_name とは
背景
python ライブラリの gcloud(google.cloud) の storage の get_blob において、
とあるが、試してみると、google cloud storage 上の
gs://my-bucket
に、/path/to/blob.txt
は存在するのに、なぜか、 None
が返ってくる。ほえ?
blob_name
には 始めのスラッシュはいりません
すなわち、blob_name
は
path/to/blob.txt
ということです。だったらそのように例を(次のように)
>>> from google.cloud import storage >>> client = storage.Client() >>> bucket = client.get_bucket('my-bucket') >>> print(bucket.get_blob('path/to/blob.txt')) <Blob: my-bucket, path/to/blob.txt> >>> print(bucket.get_blob('does-not-exist.txt')) None
と書いてよ、と思う。
sklearn にて `class_weight` が `balanced` か「なし」の探索
背景
sklearn の GridSearchCV
はパラメータサーチに利用される。
sklearn.model_selection.GridSearchCV — scikit-learn 0.19.0 documentation
ところが、パラメータなし、の設定例はみつからない。
sklearn.linear_model.LogisticRegression — scikit-learn 0.19.0 documentation
には、dict か "balanced"
かと書いてある。
パラメータなしは、None
class_weight
が balanced
か「なし」の探索
"class_weight": ["balanced", None]