fit_transform() принимает 2 позиционных аргумента, но 3 были заданы с помощью LabelBinarizer
Я совершенно не знаком с машинным обучением, и я работаю с неконтролируемой методикой обучения.
Изображение показывает мой образец данных (после очистки) Скриншот: пример данных
У меня есть два построенных канала для очистки данных:
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())
])
Затем я сделал объединение этих двух конвейеров, и код для этого показан ниже:
from sklearn.pipeline import FeatureUnion
full_pipeline = FeatureUnion(transformer_list=[
("num_pipeline", num_pipeline),
("cat_pipeline", cat_pipeline),
])
Теперь я пытаюсь сделать fit_transform на Data But It, показывая мне ошибку.
Код для трансформации:
housing_prepared = full_pipeline.fit_transform(housing)
housing_prepared
Сообщение об ошибке: fit_transform() принимает 2 позиционных аргумента, но 3 даны
Ответы
Ответ 1
Эта проблема:
Конвейер предполагает, что метод label_transform fit_transform
определен для принятия трех позиционных аргументов:
def fit_transform(self, x, y)
...rest of the code
в то время как он определяется только двумя:
def fit_transform(self, x):
...rest of the code
Возможное решение:
Это можно решить, создав собственный трансформатор, который может обрабатывать 3 позиционных аргумента:
-
Импортируйте и создайте новый класс:
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)
-
Держите свой код таким же, но вместо использования LabelBinarizer() используйте класс, который мы создали: MyLabelBinarizer().
Примечание. Если вы хотите получить доступ к атрибутам LabelBinarizer (например, classes_), добавьте следующую строку в метод fit
: self.classes_, self.y_type_, self.sparse_input_ = self.encoder.classes_, self.encoder.y_type_, self.encoder.sparse_input_
Ответ 2
Полагаю, ваш пример взят из книги "Практическое машинное обучение с Scikit-Learn & TensorFlow". К сожалению, я столкнулся и с этой проблемой. Недавнее изменение в scikit-learn
(0.19.0
) изменило метод LabelBinarizer
fit_transform
. К сожалению, LabelBinarizer
никогда не предназначался для того, чтобы использовать его в этом примере. Вы можете увидеть информацию об изменениях здесь и здесь.
Пока они не 0.18.0
решение для этого, вы можете установить предыдущую версию (0.18.0
) следующим образом:
$ pip install scikit-learn==0.18.0
После этого ваш код должен работать без проблем.
В будущем, похоже, правильное решение может заключаться в использовании класса CategoricalEncoder
или чего-то подобного. Они пытались решить эту проблему в течение многих лет. Вы можете увидеть новый класс здесь и дальнейшее обсуждение проблемы здесь.
Ответ 3
Поскольку LabelBinarizer не допускает более двух позиционных аргументов, вы должны создать свой собственный бинаризатор, например
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)
Ответ 4
Я столкнулся с той же проблемой и заставил ее работать, применив обходной путь, указанный в книге Github repo.
Предупреждение: более ранние версии книги использовали класс LabelBinarizer на этом этапе. Опять же, это было неправильно: так же, как класс LabelEncoder, класс LabelBinarizer был разработан для предварительной обработки меток, а не входных объектов. Лучшим решением является использование нового класса Scorit-Learn, который будет добавлен в Scikit-Learn, а тем временем вы можете использовать приведенный ниже код (скопировано из запроса на извлечение № 9151).
Чтобы сэкономить время, просто вставьте и запустите его в предыдущей ячейке:
# 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
Ответ 5
Я думаю, что вы просматриваете примеры из книги: Практика машинного обучения с Scikit Learn и Tensorflow. Я столкнулся с той же проблемой при рассмотрении примера в Главе 2.
Как уже упоминали другие люди, проблема заключается в склеарне LabelBinarizer. Он требует меньше аргументов в своем методе fit_transform по сравнению с другими преобразователями в конвейере. (только y, когда другие преобразователи обычно принимают и X, и y, подробнее см. здесь). Вот почему, когда мы запускаем pipe.fit_transform, мы подали в этот преобразователь больше аргументов, чем требовалось.
Простое исправление, которое я использовал, - это просто использовать OneHotEncoder и установить для "sparse" значение False, чтобы гарантировать, что выходные данные будут массивом numpy, таким же, как выходные данные num_pipeline. (таким образом, вам не нужно кодировать свой собственный кодер)
ваш оригинальный 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))
])
Вы можете пойти отсюда, и все должно работать.
Ответ 6
Просто вы можете определить следующий класс непосредственно перед конвейером:
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())])
Ты сделал!
Ответ 7
Забудьте о LaberBinarizer и используйте вместо него OneHotEncoder.
Если вы используете LabelEncoder перед OneHotEncoder для преобразования категорий в целые числа, теперь вы можете напрямую использовать OneHotEncoder.
Ответ 8
Я получил ту же проблему и получил разрешение с помощью DataFrameMapper (необходимо установить sklearn_pandas):
from sklearn_pandas import DataFrameMapper
cat_pipeline = Pipeline([
('label_binarizer', DataFrameMapper([(cat_attribs, LabelBinarizer())])),
])
Ответ 9
Я закончил свой собственный
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]])
Ответ 10
Вы можете создать еще один Custom Transformer, который выполняет кодирование для вас.
class CustomLabelEncode(BaseEstimator, TransformerMixin):
def fit(self, X, y=None):
return self
def transform(self, X):
return LabelEncoder().fit_transform(X);
В этом примере мы сделали LabelEncoding, но вы также можете использовать LabelBinarizer
Ответ 11
Использование OneHotEncoder работало для меня
Ответ 12
Я также столкнулся с той же проблемой. Следующая ссылка помогла мне решить эту проблему.
https://github.com/ageron/handson-ml/issues/75
Подведение итогов изменений
1) Определите следующий класс в своей записной книжке
Класс SupervisionFriendlyLabelBinarizer (LabelBinarizer):
def fit_transform(self, X, y=None):
return super(SupervisionFriendlyLabelBinarizer, self).fit_transform(X)
2) Изменить следующий фрагмент кода
cat_pipeline = Pipeline([('selector', DataFrameSelector(cat_attribs)),
('label_binarizer', SupervisionFriendlyLabelBinarizer()),])
3) Перезапустите ноутбук. Вы сможете бежать сейчас
Ответ 13
Чтобы выполнить однострунную кодировку для множества категориальных функций, мы можем создать новый класс, который настраивает наши собственные множественные категориальные функции бинаризатора и подключает его к категориальному конвейеру следующим образом.
Предположим, что CAT_FEATURES = ['cat_feature1', 'cat_feature2']
- список категориальных функций. Следующие сценарии должны решить проблему и произвести то, что мы хотим.
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))
])