はじめに
ColumnTransformerを使うと、列ごと(特徴量ごと)に異なった操作を適用するという変換を行うことができます。
ドキュメントを読んでいてそのうち必要になりそうだと思ったので、理解を深めるために記事を書いておきます。
使い方
ドキュメントはこちらです。
sklearn.compose.ColumnTransformer — scikit-learn 0.21.2 documentation
いちばん大切なコンストラクタの引数は、第一引数のtransformersです。これは3つの要素を持つtupleのlistとする必要があります。numpy風にいうと、(n, 3)のshapeでないといけない、ということです。
内側のtupleは、先頭の要素から
- name
適当な名前(なんでも構いません)の文字列
- transformer
fitとtransformメソッドのあるtransformer, または"drop", "passthrough"の文字列。文字列の場合は、次の要素で指定した列を脱落させるか(drop)、そのまま出力するか(passthrough)を選べます。
- column(s)
列を指定するためのオブジェクト。pandasのDataFrameの列名、またはスライスやnumpy風のindicies、boolean mask、挙句の果てには列を取り出すために使われる関数など、いろいろなものが渡せます。
という塩梅です。
あと、remainderという引数もあります。これはtransformersの中で処理が明記されなかった列に対する操作を指定するもので、こちらも"drop", "passthrough"が選べます。デフォルトは"drop"なのでちょっと注意が要ります。
使ってみる
irisの0つめの変数(sepal length (cm))だけ標準化してみる、というテストです。
>>> from sklearn.datasets import load_iris >>> iris = load_iris() >>> iris.feature_names ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)'] >>> from sklearn.compose import ColumnTransformer >>> from sklearn.preprocessing import StandardScaler >>> ct = ColumnTransformer([("sl", StandardScaler(), [0])]) # [0]としないで0にすると1D-arrayになってエラー >>> iris.data[:3] array([[5.1, 3.5, 1.4, 0.2], [4.9, 3. , 1.4, 0.2], [4.7, 3.2, 1.3, 0.2]]) >>> ct.fit_transform(iris.data)[:3] array([[-0.90068117], [-1.14301691], [-1.38535265]]) >>> ct = ColumnTransformer([("sl", StandardScaler(), [0])], remainder="passthrough") # 他の列を残す >>> ct.fit_transform(iris.data)[:3] array([[-0.90068117, 3.5 , 1.4 , 0.2 ], [-1.14301691, 3. , 1.4 , 0.2 ], [-1.38535265, 3.2 , 1.3 , 0.2 ]])
そんなに難しい部分はないので、普通に使えると思います。
OneHotEncoderとの組み合わせ
カテゴリ変数のone-hot表現への変換に威力を発揮するOneHotEncoderは、かつてはcategoricalとnumericが混ざったデータに対しても柔軟に処理を行えるような実装とされていましたが、関連機能がDeprecated since version 0.20になっています(0.22で消滅)。
そういうことにはColumnTransformerを使え、とドキュメントで案内されているので、使ってみます。
sklearn.preprocessing.OneHotEncoder — scikit-learn 0.21.2 documentation
>>> import pandas as pd >>> df = pd.DataFrame([["hoge", 0.1], ["fuga", 0.2]]) # 変換して[[0, 1, 0.1], [1, 0, 0.2]]が得たい >>> from sklearn.preprocessing import OneHotEncoder >>> from sklearn.compose import ColumnTransformer >>> ct = ColumnTransformer([("category", OneHotEncoder(), [0])], remainder="passthrough") >>> ct.fit_transform(df) array([[0. , 1. , 0.1], [1. , 0. , 0.2]])
面倒くさいような気もしますが、直交性と柔軟性のことを考えるとこの方が良いのでしょう。
まとめ
まだ新しい(ほとんど使われていない)機能ですが、柔軟なデータ操作には欠かせないものなので、積極的に使いましょう。
pandasのDataFrameを標準でサポートしている辺り、かなり対抗を意識しているな、というのが率直な感想です。pandasで前処理をしてしまう人が多いですが、私はできるだけscikit-learnの枠組みでやるべきと考えるので、こういうところには好感が持てます。