web-dev-qa-db-ja.com

fit_transform()は2つの位置引数を取りますが、3つはLabelBinarizerで指定されました

機械学習はまったく新しいので、教師なしの学習手法を使用しています。

画像は私のサンプルデータを示しています(すべてのクリーニング後)スクリーンショット: サンプルデータ

データをクリーンにするために、次の2つのPiplineを作成しました。

num_attribs = list(housing_num)
cat_attribs = ["ocean_proximity"]

print(type(num_attribs))

num_pipeline = Pipeline([
    ('selector', DataFrameSelector(num_attribs)),
    ('imputer', Imputer(strategy="median")),
    ('attribs_adder', CombinedAttributesAdder()),
    ('std_scaler', StandardScaler()),
])

cat_pipeline = Pipeline([
    ('selector', DataFrameSelector(cat_attribs)),
    ('label_binarizer', LabelBinarizer())
])

次に、この2つのパイプラインの結合を行いました。同じコードを以下に示します。

from sklearn.pipeline import FeatureUnion

full_pipeline = FeatureUnion(transformer_list=[
        ("num_pipeline", num_pipeline),
        ("cat_pipeline", cat_pipeline),
    ])

Data でfit_transformを実行しようとしていますが、エラーが表示されます。

変換のためのコード:

housing_prepared = full_pipeline.fit_transform(housing)
housing_prepared

エラーメッセージ:fit_transform()は2つの位置引数を取りますが、3つが指定されました

64
Viral Parmar

あなたの例は本のScikit-LearnとTensorFlowによるハンズオン機械学習からのものだと思います。残念ながら、私もこの問題に遭遇しました。 scikit-learn0.19.0)の最近の変更により、LabelBinarizerfit_transformメソッドが変更されました。残念ながら、LabelBinarizerは、その例がそれをどのように使用するかを機能させることを意図していませんでした。変更に関する情報 here および here を確認できます。

この解決策が見つかるまで、次のように以前のバージョン(0.18.0)をインストールできます。

$ pip install scikit-learn==0.18.0

それを実行した後、コードは問題なく実行されるはずです。

将来、正しい解決策はCategoricalEncoderクラスまたはそれに類似したものを使用することになると思われます。彼らは明らかにこの問題を何年も解決しようとしている。新しいクラス here および問題の詳細な議論 here を確認できます。

51
Steven Oxley

LabelBinarizerは3つ以上の位置引数を許可しないため、次のようなカスタムバイナライザーを作成する必要があります。

class CustomLabelBinarizer(BaseEstimator, TransformerMixin):
    def __init__(self, sparse_output=False):
        self.sparse_output = sparse_output
    def fit(self, X, y=None):
        return self
    def transform(self, X, y=None):
        enc = LabelBinarizer(sparse_output=self.sparse_output)
        return enc.fit_transform(X)

num_attribs = list(housing_num)
cat_attribs = ['ocean_proximity']

num_pipeline = Pipeline([
    ('selector', DataFrameSelector(num_attribs)),
    ('imputer', Imputer(strategy='median')),
    ('attribs_adder', CombinedAttributesAdder()),
    ('std_scalar', StandardScaler())
])

cat_pipeline = Pipeline([
    ('selector', DataFrameSelector(cat_attribs)),
    ('label_binarizer', CustomLabelBinarizer())
])

full_pipeline = FeatureUnion(transformer_list=[
    ('num_pipeline', num_pipeline),
    ('cat_pipeline', cat_pipeline)
])

housing_prepared = full_pipeline.fit_transform(new_housing)
8
shyam padia

私は同じ問題にぶつかり、 bookのGithubリポジトリ で指定された回避策を適用することで動作するようになりました。

警告:この本の以前のバージョンでは、この時点でLabelBinarizerクラスを使用していました。繰り返しますが、これは間違っていました。LabelEncoderクラスと同様に、LabelBinarizerクラスは、入力フィーチャではなくラベルを前処理するように設計されています。より良い解決策は、Scikit-Learnの今後のCategoricalEncoderクラスを使用することです。間もなくScikit-Learnに追加されます。その間、以下のコードを使用できます(プルリクエスト #9151 からコピー)。

いくつかのgrepを保存するための回避策は、前のセルに貼り付けて実行するだけです:

# Definition of the CategoricalEncoder class, copied from PR #9151.
# Just run this cell, or copy it to your code, do not try to understand it (yet).

from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.utils import check_array
from sklearn.preprocessing import LabelEncoder
from scipy import sparse

class CategoricalEncoder(BaseEstimator, TransformerMixin):
    def __init__(self, encoding='onehot', categories='auto', dtype=np.float64,
                 handle_unknown='error'):
        self.encoding = encoding
        self.categories = categories
        self.dtype = dtype
        self.handle_unknown = handle_unknown

    def fit(self, X, y=None):
        """Fit the CategoricalEncoder to X.
        Parameters
        ----------
        X : array-like, shape [n_samples, n_feature]
            The data to determine the categories of each feature.
        Returns
        -------
        self
        """

        if self.encoding not in ['onehot', 'onehot-dense', 'ordinal']:
            template = ("encoding should be either 'onehot', 'onehot-dense' "
                        "or 'ordinal', got %s")
            raise ValueError(template % self.handle_unknown)

        if self.handle_unknown not in ['error', 'ignore']:
            template = ("handle_unknown should be either 'error' or "
                        "'ignore', got %s")
            raise ValueError(template % self.handle_unknown)

        if self.encoding == 'ordinal' and self.handle_unknown == 'ignore':
            raise ValueError("handle_unknown='ignore' is not supported for"
                             " encoding='ordinal'")

        X = check_array(X, dtype=np.object, accept_sparse='csc', copy=True)
        n_samples, n_features = X.shape

        self._label_encoders_ = [LabelEncoder() for _ in range(n_features)]

        for i in range(n_features):
            le = self._label_encoders_[i]
            Xi = X[:, i]
            if self.categories == 'auto':
                le.fit(Xi)
            else:
                valid_mask = np.in1d(Xi, self.categories[i])
                if not np.all(valid_mask):
                    if self.handle_unknown == 'error':
                        diff = np.unique(Xi[~valid_mask])
                        msg = ("Found unknown categories {0} in column {1}"
                               " during fit".format(diff, i))
                        raise ValueError(msg)
                le.classes_ = np.array(np.sort(self.categories[i]))

        self.categories_ = [le.classes_ for le in self._label_encoders_]

        return self

    def transform(self, X):
        """Transform X using one-hot encoding.
        Parameters
        ----------
        X : array-like, shape [n_samples, n_features]
            The data to encode.
        Returns
        -------
        X_out : sparse matrix or a 2-d array
            Transformed input.
        """
        X = check_array(X, accept_sparse='csc', dtype=np.object, copy=True)
        n_samples, n_features = X.shape
        X_int = np.zeros_like(X, dtype=np.int)
        X_mask = np.ones_like(X, dtype=np.bool)

        for i in range(n_features):
            valid_mask = np.in1d(X[:, i], self.categories_[i])

            if not np.all(valid_mask):
                if self.handle_unknown == 'error':
                    diff = np.unique(X[~valid_mask, i])
                    msg = ("Found unknown categories {0} in column {1}"
                           " during transform".format(diff, i))
                    raise ValueError(msg)
                else:
                    # Set the problematic rows to an acceptable value and
                    # continue `The rows are marked `X_mask` and will be
                    # removed later.
                    X_mask[:, i] = valid_mask
                    X[:, i][~valid_mask] = self.categories_[i][0]
            X_int[:, i] = self._label_encoders_[i].transform(X[:, i])

        if self.encoding == 'ordinal':
            return X_int.astype(self.dtype, copy=False)

        mask = X_mask.ravel()
        n_values = [cats.shape[0] for cats in self.categories_]
        n_values = np.array([0] + n_values)
        indices = np.cumsum(n_values)

        column_indices = (X_int + indices[:-1]).ravel()[mask]
        row_indices = np.repeat(np.arange(n_samples, dtype=np.int32),
                                n_features)[mask]
        data = np.ones(n_samples * n_features)[mask]

        out = sparse.csc_matrix((data, (row_indices, column_indices)),
                                shape=(n_samples, indices[-1]),
                                dtype=self.dtype).tocsr()
        if self.encoding == 'onehot-dense':
            return out.toarray()
        else:
            return out
6
Rui Liu

あなたは本からの例を通り抜けていると思います: Scikit LearnとTensorflowによる機械学習の実践 。第2章の例を見ると、同じ問題に遭遇しました。

他の人が言ったように、問題はsklearnのLabelBinarizerに関係しています。 fit_transformメソッドの引数は、パイプラインの他のトランスフォーマーに比べて少なくなります。 (他のトランスフォーマーが通常Xとyの両方を取る場合はyのみ。詳細については here を参照してください)。そのため、pipeline.fit_transformを実行するときに、必要以上に多くの引数をこのトランスフォーマーに送りました。

私が使用した簡単な修正方法は、OneHotEncoderを使用し、「スパース」をFalseに設定して、出力がnum_pipeline出力と同じnumpy配列になるようにすることです。 (この方法では、独自のカスタムエンコーダーをコーディングする必要はありません)

元のcat_pipeline:

cat_pipeline = Pipeline([
('selector', DataFrameSelector(cat_attribs)),
('label_binarizer', LabelBinarizer())
])

この部分を単に次のように変更できます。

cat_pipeline = Pipeline([
('selector', DataFrameSelector(cat_attribs)),
('one_hot_encoder', OneHotEncoder(sparse=False))
])

ここから行くことができ、すべてが機能するはずです。

4
Norman Yan

LaberBinarizerを忘れて、代わりにOneHotEncoderを使用してください。

OneHotEncoderの前にLabelEncoderを使用してカテゴリを整数に変換する場合、OneHotEncoderを直接使用できるようになりました。

3
blacksheep

単純に、できることは、パイプラインの直前に次のクラスを定義することです。

class NewLabelBinarizer(LabelBinarizer):
    def fit(self, X, y=None):
        return super(NewLabelBinarizer, self).fit(X)
    def transform(self, X, y=None):
        return super(NewLabelBinarizer, self).transform(X)
    def fit_transform(self, X, y=None):
        return super(NewLabelBinarizer, self).fit(X).transform(X)

その後、残りのコードは、パイプラインの連結の前にcat_pipelineを少し修正した本で言及したものと同じです。

cat_pipeline = Pipeline([
    ("selector", DataFrameSelector(cat_attribs)),
    ("label_binarizer", NewLabelBinarizer())])

できました!

2
Navid

私は同じ問題を抱え、DataFrameMapperを使用して解決しました(sklearn_pandasをインストールする必要があります):

from sklearn_pandas import DataFrameMapper
cat_pipeline = Pipeline([
    ('label_binarizer', DataFrameMapper([(cat_attribs, LabelBinarizer())])),
])
1
user3871008

私は自分で転がしてしまいました

class LabelBinarizer(BaseEstimator, TransformerMixin):
    def fit(self, X, y=None):
        X = self.prep(X)
        unique_vals = []
        for column in X.T:
            unique_vals.append(np.unique(column))
        self.unique_vals = unique_vals
    def transform(self, X, y=None):
        X = self.prep(X)
        unique_vals = self.unique_vals
        new_columns = []
        for i, column in enumerate(X.T):
            num_uniq_vals = len(unique_vals[i])
            encoder_ring = dict(Zip(unique_vals[i], range(len(unique_vals[i]))))
            f = lambda val: encoder_ring[val]
            f = np.vectorize(f, otypes=[np.int])
            new_column = np.array([f(column)])
            if num_uniq_vals <= 2:
                new_columns.append(new_column)
            else:
                one_hots = np.zeros([num_uniq_vals, len(column)], np.int)
                one_hots[new_column, range(len(column))]=1
                new_columns.append(one_hots)
        new_columns = np.concatenate(new_columns, axis=0).T        
        return new_columns

    def fit_transform(self, X, y=None):
        self.fit(X)
        return self.transform(X)

    @staticmethod
    def prep(X):
        shape = X.shape
        if len(shape) == 1:
            X = X.values.reshape(shape[0], 1)
        return X

働くようです

lbn = LabelBinarizer()
thingy = np.array([['male','male','female', 'male'], ['A', 'B', 'A', 'C']]).T
lbn.fit(thingy)
lbn.transform(thingy)

返却値

array([[1, 1, 0, 0],
       [1, 0, 1, 0],
       [0, 1, 0, 0],
       [1, 0, 0, 1]])
0
JnBrymn

エンコードを行うカスタムトランスフォーマーをもう1つ作成できます。

class CustomLabelEncode(BaseEstimator, TransformerMixin):
    def fit(self, X, y=None):
        return self
    def transform(self, X):
        return LabelEncoder().fit_transform(X);

この例では、LabelEncodingを実行しましたが、LabelBinarizerも使用できます

0
Rupinder Singh