sklearn scikit onehotencoder one learn inverse_transform hot estimator categorical_features categorical scikit-learn data-science

scikit learn - scikit - fit_transform() toma 2 argumentos posicionales pero 3 se dieron con LabelBinarizer



onehotencoder pandas (11)

Como LabelBinarizer no permite más de 2 argumentos posicionales, debe crear su binarizador personalizado como

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)

Soy totalmente nuevo en Machine Learning y he estado trabajando con técnicas de aprendizaje sin supervisión.

La imagen muestra mis datos de muestra (después de toda limpieza) Captura de pantalla: Datos de muestra

Tengo estos dos Pipline construidos para limpiar los datos:

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()) ])

Luego hice la unión de estas dos tuberías y el código de la misma se muestra a continuación:

from sklearn.pipeline import FeatureUnion full_pipeline = FeatureUnion(transformer_list=[ ("num_pipeline", num_pipeline), ("cat_pipeline", cat_pipeline), ])

Ahora estoy tratando de hacer fit_transform en los Data pero me muestra el error.

Código para la transformación:

housing_prepared = full_pipeline.fit_transform(housing) housing_prepared

Mensaje de error: fit_transform () toma 2 argumentos posicionales pero se dieron 3


Creo que está analizando los ejemplos del libro: Aprendizaje práctico con Scikit Learn y Tensorflow . Me encontré con el mismo problema al leer el ejemplo en el Capítulo 2.

Como lo mencionaron otras personas, el problema está relacionado con LabelBinarizer de sklearn. Toma menos args en su método fit_transform en comparación con otros transformadores en la tubería. (solo y cuando otros transformadores normalmente toman X e y, vea here para más detalles). Es por eso que cuando ejecutamos pipeline.fit_transform, alimentamos más args en este transformador de lo requerido.

Una solución fácil que utilicé es usar OneHotEncoder y establecer "sparse" en False para asegurar que la salida sea una matriz numpy igual que la salida num_pipeline. (de esta manera no necesita codificar su propio codificador personalizado)

tu cat_pipeline original:

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

simplemente puede cambiar esta parte a:

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

Puedes ir desde aquí y todo debería funcionar.


Creo que su ejemplo es del libro Aprendizaje automático práctico con Scikit-Learn y TensorFlow . Desafortunadamente, me encontré con este problema también. Un cambio reciente en scikit-learn ( 0.19.0 ) cambió el método fit_transform . Desafortunadamente, LabelBinarizer nunca tuvo la intención de funcionar como ese ejemplo lo usa. Puede ver información sobre el cambio here y here .

Hasta que encuentren una solución para esto, puede instalar la versión anterior ( 0.18.0 ) de la siguiente manera:

$ pip install scikit-learn==0.18.0

Después de ejecutar eso, su código debería ejecutarse sin problemas.

En el futuro, parece que la solución correcta puede ser usar una clase CategoricalEncoder o algo similar. Han estado tratando de resolver este problema durante años aparentemente. Puede ver la nueva clase here y más discusión sobre el problema here .


Me encontré con el mismo problema y lo puse a trabajar aplicando la solución especificada en el repositorio de Github del libro .

Advertencia: las versiones anteriores del libro usaban la clase LabelBinarizer en este punto. Nuevamente, esto era incorrecto: al igual que la clase LabelEncoder, la clase LabelBinarizer fue diseñada para preprocesar etiquetas, no funciones de entrada. Una mejor solución es usar la próxima clase CategoricalEncoder de Scikit-Learn: pronto se agregará a Scikit-Learn, y mientras tanto puede usar el código a continuación (copiado de la Solicitud de here ).

Para ahorrarle un poco de grepping, esta es la solución, simplemente péguela y ejecútela en una celda anterior:

# 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


Olvídese de LaberBinarizer y use OneHotEncoder en su lugar.

En caso de que use un LabelEncoder antes de OneHotEncoder para convertir categorías a enteros, ahora puede usar OneHotEncoder directamente.


Para realizar una codificación única para múltiples características categóricas, podemos crear una nueva clase que personalice nuestro propio binarizador de múltiples características categóricas y conectarlo a la canalización categórica de la siguiente manera.

Supongamos que CAT_FEATURES = [''cat_feature1'', ''cat_feature2''] es una lista de características categóricas. Los siguientes scripts resolverán el problema y producirán lo que queramos.

import pandas as pd from sklearn.pipeline import Pipeline from sklearn.base import BaseEstimator, TransformerMixin class CustomLabelBinarizer(BaseEstimator, TransformerMixin): """Perform one-hot encoding to categorical features.""" def __init__(self, cat_features): self.cat_features = cat_features def fit(self, X_cat, y=None): return self def transform(self, X_cat): X_cat_df = pd.DataFrame(X_cat, columns=self.cat_features) X_onehot_df = pd.get_dummies(X_cat_df, columns=self.cat_features) return X_onehot_df.values # Pipeline for categorical features. cat_pipeline = Pipeline([ (''selector'', DataFrameSelector(CAT_FEATURES)), (''onehot_encoder'', CustomLabelBinarizer(CAT_FEATURES)) ])


Puede crear un transformador personalizado más que haga la codificación por usted.

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

En este ejemplo, hemos realizado LabelEncoding pero también puede usar LabelBinarizer


Simplemente, lo que puede hacer es definir la siguiente clase justo antes de su canalización:

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

Luego, el resto del código es como el que se menciona en el libro con una pequeña modificación en cat_pipeline antes de la concatenación de la tubería: siga estos pasos:

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)

¡Lo hiciste!


Terminé rodando la mía

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

Parece funcionar

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

devoluciones

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


Tuve el mismo problema y me resolví usando DataFrameMapper (necesito instalar sklearn_pandas):

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


El problema:

La canalización supone que el método fit_transform de fit_transform está definido para tomar tres argumentos posicionales:

def fit_transform(self, x, y) ...rest of the code

mientras se define para tomar solo dos:

def fit_transform(self, x): ...rest of the code

Solución posible:

Esto se puede resolver haciendo un transformador personalizado que pueda manejar 3 argumentos posicionales:

  1. Importa y crea una nueva clase:

    from sklearn.base import TransformerMixin #gives fit_transform method for free class MyLabelBinarizer(TransformerMixin): def __init__(self, *args, **kwargs): self.encoder = LabelBinarizer(*args, **kwargs) def fit(self, x, y=0): self.encoder.fit(x) return self def transform(self, x, y=0): return self.encoder.transform(x)

  2. Mantenga su código igual solo en lugar de usar LabelBinarizer (), use la clase que creamos: MyLabelBinarizer ().

Nota: Si desea acceder a los atributos de LabelBinarizer (por ejemplo, clases_), agregue la siguiente línea al método de fit :

self.classes_, self.y_type_, self.sparse_input_ = self.encoder.classes_, self.encoder.y_type_, self.encoder.sparse_input_