これは私の初めての機械学習プロジェクトであり、初めてColumnTransformerを使用します。私の目的は、2つのデータ前処理ステップを実行し、それぞれにColumnTransformerを使用することです。
最初の手順では、データフレームの欠損値を一部の機能の文字列「missing_value」に置き換え、残りの機能の最も頻度の高い値を置き換えます。したがって、ColumnTransformerを使用してこれら2つの操作を組み合わせ、それにデータフレームの対応する列を渡します。
2番目のステップでは、前処理したばかりのデータを使用して、機能に応じてOrdinalEncoderまたはOneHotEncoderを適用します。そのために、再びColumnTransformerを使用します。
次に、2つのステップを1つのパイプラインに結合します。
Kaggle Houses Priceデータセットを使用しています。scikit-learnバージョン0.20があり、これは私のコードの簡略化されたバージョンです。
cat_columns_fill_miss = ['PoolQC', 'Alley']
cat_columns_fill_freq = ['Street', 'MSZoning', 'LandContour']
cat_columns_ord = ['Street', 'Alley', 'PoolQC']
ord_mapping = [['Pave', 'Grvl'], # Street
['missing_value', 'Pave', 'Grvl'], # Alley
['missing_value', 'Fa', 'TA', 'Gd', 'Ex'] # PoolQC
]
cat_columns_onehot = ['MSZoning', 'LandContour']
imputer_cat_pipeline = ColumnTransformer([
('imp_miss', SimpleImputer(strategy='constant'), cat_columns_fill_miss), # fill_value='missing_value' by default
('imp_freq', SimpleImputer(strategy='most_frequent'), cat_columns_fill_freq),
])
encoder_cat_pipeline = ColumnTransformer([
('ordinal', OrdinalEncoder(categories=ord_mapping), cat_columns_ord),
('pass_ord', OneHotEncoder(), cat_columns_onehot),
])
cat_pipeline = Pipeline([
('imp_cat', imputer_cat_pipeline),
('cat_encoder', encoder_cat_pipeline),
])
残念ながら、私のデータをサブセットとして使用する私のデータフレームのサブセットであるHousing_catに適用すると、
cat_pipeline.fit_transform(housing_cat)
エラーが発生します:
AttributeError: 'numpy.ndarray' object has no attribute 'columns'
上記の例外の処理中に、別の例外が発生しました:
...
ValueError:文字列を使用した列の指定は、pandas DataFramesでのみサポートされています
私はこの簡略化されたパイプラインを試してみましたが、正しく機能します:
new_cat_pipeline = Pipeline([
('imp_cat', imputer_cat_pipeline),
('onehot', OneHotEncoder()),
])
ただし、私が試した場合:
enc_one = ColumnTransformer([
('onehot', OneHotEncoder(), cat_columns_onehot),
('pass_ord', 'passthrough', cat_columns_ord)
])
new_cat_pipeline = Pipeline([
('imp_cat', imputer_cat_pipeline),
('onehot_encoder', enc_one),
])
同じエラーが出始めます。
このエラーは2番目のステップでのColumnTransformerの使用に関連しているのではないかと思いますが、実際にはそれがどこから来たのかわかりません。 2番目のステップで列を特定する方法は最初のステップと同じなので、2番目のステップでのみ属性エラーが発生する理由は不明のままです...
ここで他の回答に追加します。私はPythonまたはデータサイエンスのエキスパートではありませんが、ColumnTransformer
に別のパイプラインを渡して、列に複数のトランスフォーマーを追加する必要があることを実行できます。私は来ましたここで同じ質問に対する答えを探して、この解決策を見つけました。
すべてをパイプライン経由で行うと、テスト/トレーニングデータを非常に簡単に制御してリークを回避でき、グリッド検索の可能性も広がります。私は個人的にpandasアプローチのファンではありません。これらの理由により、別の回答でアプローチしますが、それでも問題ありません。
encoder_cat_pipeline = Pipeline([
('ordinal', OrdinalEncoder(categories=ord_mapping)),
('pass_ord', OneHotEncoder()),
])
imputer_cat_pipeline = ColumnTransformer([
('imp_miss', SimpleImputer(strategy='constant'), cat_columns_fill_miss),
('new_pipeline', encoder_cat_pipeline, cat_columns_fill_freq)
])
cat_pipeline = Pipeline([
('imp_cat', imputer_cat_pipeline),
])