Ich bin völlig neu im maschinellen Lernen und habe mit unbeaufsichtigten Lerntechniken gearbeitet.
Das Bild zeigt meine Beispieldaten (nach allen Reinigungen). Screenshot: Beispieldaten
Ich habe diese zwei Pipline gebaut, um die Daten zu bereinigen:
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())
])
Dann habe ich die Vereinigung dieser beiden Pipelines durchgeführt und der Code für dieselbe ist unten gezeigt:
from sklearn.pipeline import FeatureUnion
full_pipeline = FeatureUnion(transformer_list=[
("num_pipeline", num_pipeline),
("cat_pipeline", cat_pipeline),
])
Jetzt versuche ich, fit_transform für die Daten durchzuführen, aber es zeigt mir den Fehler.
Code für die Transformation:
housing_prepared = full_pipeline.fit_transform(housing)
housing_prepared
Fehlermeldung:
fit_transform () akzeptiert 2 Positionsargumente, aber 3 wurden angegeben
python
scikit-learn
data-science
Viraler Parmar
quelle
quelle
pandas.get_dummies()
.Antworten:
Das Problem:
Die Pipeline geht davon aus, dass die
fit_transform
Methode von LabelBinarizer für drei Positionsargumente definiert ist:def fit_transform(self, x, y) ...rest of the code
während es definiert ist, nur zwei zu nehmen:
def fit_transform(self, x): ...rest of the code
Mögliche Lösung:
Dies kann gelöst werden, indem ein benutzerdefinierter Transformator erstellt wird, der drei Positionsargumente verarbeiten kann:
Importiere und erstelle eine neue Klasse:
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)
Behalten Sie Ihren Code nur bei, anstatt LabelBinarizer () zu verwenden. Verwenden Sie die von uns erstellte Klasse: MyLabelBinarizer ().
Hinweis: Wenn Sie auf LabelBinarizer-Attribute (z. B. classes_) zugreifen möchten, fügen Sie der
fit
Methode die folgende Zeile hinzu :quelle
Ich glaube, Ihr Beispiel stammt aus dem Buch Hands-On Machine Learning mit Scikit-Learn & TensorFlow . Leider bin ich auch auf dieses Problem gestoßen. Eine kürzlich vorgenommene Änderung in
scikit-learn
(0.19.0
) hatLabelBinarizer
diefit_transform
Methode geändert . LeiderLabelBinarizer
sollte nie funktionieren, wie dieses Beispiel es verwendet. Informationen zur Änderung finden Sie hier und hier .Bis sie eine Lösung dafür finden, können Sie die vorherige Version (
0.18.0
) wie folgt installieren :$ pip install scikit-learn==0.18.0
Danach sollte Ihr Code ohne Probleme ausgeführt werden.
In Zukunft sieht es so aus, als ob die richtige Lösung darin bestehen könnte, eine
CategoricalEncoder
Klasse oder ähnliches zu verwenden. Sie haben offenbar jahrelang versucht, dieses Problem zu lösen. Sie können die neue Klasse hier sehen und das Problem hier weiter diskutieren .quelle
X
) verwendet werden, sondern nur für Labels (y
). Daher haben sie aufgehört, sowohl X als auch y an die Methode zu senden.Ich denke, Sie gehen die Beispiele aus dem Buch durch: Praktisches maschinelles Lernen mit Scikit Learn und Tensorflow . Beim Durchlaufen des Beispiels in Kapitel 2 bin ich auf dasselbe Problem gestoßen.
Wie von anderen erwähnt, liegt das Problem im LabelBinarizer von sklearn. Die Methode fit_transform benötigt weniger Argumente als andere Transformatoren in der Pipeline. (Nur y, wenn andere Transformatoren normalerweise sowohl X als auch y verwenden, siehe hier für Details). Deshalb haben wir beim Ausführen von Pipeline.fit_transform mehr Argumente in diesen Transformator eingespeist als erforderlich.
Eine einfache Lösung, die ich verwendet habe, besteht darin, nur OneHotEncoder zu verwenden und "sparse" auf "False" zu setzen, um sicherzustellen, dass die Ausgabe ein numpy-Array ist, das mit der Ausgabe von num_pipeline identisch ist. (Auf diese Weise müssen Sie Ihren eigenen benutzerdefinierten Encoder nicht codieren.)
Ihre ursprüngliche cat_pipeline:
cat_pipeline = Pipeline([ ('selector', DataFrameSelector(cat_attribs)), ('label_binarizer', LabelBinarizer()) ])
Sie können diesen Teil einfach ändern in:
cat_pipeline = Pipeline([ ('selector', DataFrameSelector(cat_attribs)), ('one_hot_encoder', OneHotEncoder(sparse=False)) ])
Sie können von hier aus gehen und alles sollte funktionieren.
quelle
Da LabelBinarizer nicht mehr als 2 Positionsargumente zulässt, sollten Sie Ihren benutzerdefinierten Binarizer wie folgt erstellen
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)
quelle
Ich bin auf dasselbe Problem gestoßen und habe es zum Laufen gebracht, indem ich die im Github-Repo des Buches angegebene Problemumgehung angewendet habe .
Um Ihnen einige Probleme zu ersparen, fügen Sie die Problemumgehung ein und führen Sie sie in einer vorherigen Zelle aus:
# 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
quelle
Sie können einfach die folgende Klasse kurz vor Ihrer Pipeline definieren:
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)
Dann ist der Rest des Codes wie der im Buch erwähnte mit einer winzigen Änderung
cat_pipeline
vor der Verkettung der Pipeline - folgen Sie wie folgt:cat_pipeline = Pipeline([ ("selector", DataFrameSelector(cat_attribs)), ("label_binarizer", NewLabelBinarizer())])
Bist du fertig!
quelle
Vergessen Sie LaberBinarizer und verwenden Sie stattdessen OneHotEncoder.
Wenn Sie vor OneHotEncoder einen LabelEncoder verwenden, um Kategorien in Ganzzahlen zu konvertieren, können Sie den OneHotEncoder jetzt direkt verwenden.
quelle
Ich habe auch das gleiche Problem konfrontiert. Der folgende Link hat mir bei der Behebung dieses Problems geholfen. https://github.com/ageron/handson-ml/issues/75
Zusammenfassende Änderungen
1) Definieren Sie die folgende Klasse in Ihrem Notizbuch
class SupervisionFriendlyLabelBinarizer(LabelBinarizer): def fit_transform(self, X, y=None): return super(SupervisionFriendlyLabelBinarizer,self).fit_transform(X)
2) Ändern Sie den folgenden Code
cat_pipeline = Pipeline([('selector', DataFrameSelector(cat_attribs)), ('label_binarizer', SupervisionFriendlyLabelBinarizer()),])
3) Führen Sie das Notebook erneut aus. Sie können jetzt laufen
quelle
Ich habe das gleiche Problem und wurde mithilfe von DataFrameMapper behoben (sklearn_pandas muss installiert werden):
from sklearn_pandas import DataFrameMapper cat_pipeline = Pipeline([ ('label_binarizer', DataFrameMapper([(cat_attribs, LabelBinarizer())])), ])
quelle
Sie können einen weiteren benutzerdefinierten Transformer erstellen, der die Codierung für Sie übernimmt.
class CustomLabelEncode(BaseEstimator, TransformerMixin): def fit(self, X, y=None): return self def transform(self, X): return LabelEncoder().fit_transform(X);
In diesem Beispiel haben wir LabelEncoding durchgeführt, aber Sie können auch LabelBinarizer verwenden
quelle
Am Ende rollte ich meine eigenen
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
Scheint zu funktionieren
lbn = LabelBinarizer() thingy = np.array([['male','male','female', 'male'], ['A', 'B', 'A', 'C']]).T lbn.fit(thingy) lbn.transform(thingy)
kehrt zurück
array([[1, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 1]])
quelle
So führen Sie eine One-Hot-Codierung für mehrere kategoriale Funktionen durch: wir eine neue Klasse erstellen, die unseren eigenen Binärisierer für mehrere kategoriale Features anpasst und ihn wie folgt in die kategoriale Pipeline einfügt.
Angenommen, es
CAT_FEATURES = ['cat_feature1', 'cat_feature2']
handelt sich um eine Liste kategorialer Merkmale. Die folgenden Skripte sollen das Problem beheben und das produzieren, was wir wollen.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)) ])
quelle
Wir können einfach das Attribut sparce_output = False hinzufügen
cat_pipeline = Pipeline([ ('selector', DataFrameSelector(cat_attribs)), ('label_binarizer', LabelBinarizer(sparse_output=False)), ])
quelle