sklearn.compose.ColumnTransformer:fit_transform() 接受 2 个位置参数,但给出了 3 个
Posted
技术标签:
【中文标题】sklearn.compose.ColumnTransformer:fit_transform() 接受 2 个位置参数,但给出了 3 个【英文标题】:sklearn.compose.ColumnTransformer: fit_transform() takes 2 positional arguments but 3 were given 【发布时间】:2019-09-21 00:35:56 【问题描述】:我正在研究一个使用ColumnTransformer
和LabelEncoder
预处理著名的泰坦尼克号数据集X
的示例:
Age Embarked Fare Sex
0 22.0 S 7.2500 male
1 38.0 C 71.2833 female
2 26.0 S 7.9250 female
3 35.0 S 53.1000 female
4 35.0 S 8.0500 male
像这样调用转换器:
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import LabelEncoder
ColumnTransformer(
transformers=[
("label-encode categorical", LabelEncoder(), ["Sex", "Embarked"])
]
).fit(X).transform(X)
结果:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-54-fd5a05b7e47e> in <module>
4 ("label-encode categorical", LabelEncoder(), ["Sex", "Embarked"])
5 ]
----> 6 ).fit(X).transform(X)
~/anaconda3/lib/python3.7/site-packages/sklearn/compose/_column_transformer.py in fit(self, X, y)
418 # we use fit_transform to make sure to set sparse_output_ (for which we
419 # need the transformed data) to have consistent output type in predict
--> 420 self.fit_transform(X, y=y)
421 return self
422
~/anaconda3/lib/python3.7/site-packages/sklearn/compose/_column_transformer.py in fit_transform(self, X, y)
447 self._validate_remainder(X)
448
--> 449 result = self._fit_transform(X, y, _fit_transform_one)
450
451 if not result:
~/anaconda3/lib/python3.7/site-packages/sklearn/compose/_column_transformer.py in _fit_transform(self, X, y, func, fitted)
391 _get_column(X, column), y, weight)
392 for _, trans, column, weight in self._iter(
--> 393 fitted=fitted, replace_strings=True))
394 except ValueError as e:
395 if "Expected 2D array, got 1D array instead" in str(e):
~/anaconda3/lib/python3.7/site-packages/sklearn/externals/joblib/parallel.py in __call__(self, iterable)
915 # remaining jobs.
916 self._iterating = False
--> 917 if self.dispatch_one_batch(iterator):
918 self._iterating = self._original_iterator is not None
919
~/anaconda3/lib/python3.7/site-packages/sklearn/externals/joblib/parallel.py in dispatch_one_batch(self, iterator)
757 return False
758 else:
--> 759 self._dispatch(tasks)
760 return True
761
~/anaconda3/lib/python3.7/site-packages/sklearn/externals/joblib/parallel.py in _dispatch(self, batch)
714 with self._lock:
715 job_idx = len(self._jobs)
--> 716 job = self._backend.apply_async(batch, callback=cb)
717 # A job can complete so quickly than its callback is
718 # called before we get here, causing self._jobs to
~/anaconda3/lib/python3.7/site-packages/sklearn/externals/joblib/_parallel_backends.py in apply_async(self, func, callback)
180 def apply_async(self, func, callback=None):
181 """Schedule a func to be run"""
--> 182 result = ImmediateResult(func)
183 if callback:
184 callback(result)
~/anaconda3/lib/python3.7/site-packages/sklearn/externals/joblib/_parallel_backends.py in __init__(self, batch)
547 # Don't delay the application, to avoid keeping the input
548 # arguments in memory
--> 549 self.results = batch()
550
551 def get(self):
~/anaconda3/lib/python3.7/site-packages/sklearn/externals/joblib/parallel.py in __call__(self)
223 with parallel_backend(self._backend, n_jobs=self._n_jobs):
224 return [func(*args, **kwargs)
--> 225 for func, args, kwargs in self.items]
226
227 def __len__(self):
~/anaconda3/lib/python3.7/site-packages/sklearn/externals/joblib/parallel.py in <listcomp>(.0)
223 with parallel_backend(self._backend, n_jobs=self._n_jobs):
224 return [func(*args, **kwargs)
--> 225 for func, args, kwargs in self.items]
226
227 def __len__(self):
~/anaconda3/lib/python3.7/site-packages/sklearn/pipeline.py in _fit_transform_one(transformer, X, y, weight, **fit_params)
612 def _fit_transform_one(transformer, X, y, weight, **fit_params):
613 if hasattr(transformer, 'fit_transform'):
--> 614 res = transformer.fit_transform(X, y, **fit_params)
615 else:
616 res = transformer.fit(X, y, **fit_params).transform(X)
TypeError: fit_transform() takes 2 positional arguments but 3 were given
**fit_params
这里有什么问题?对我来说,这看起来像是 sklearn
中的一个错误,或者至少是不兼容。
【问题讨论】:
我知道有很多变通方法,但我特意寻找一种解决方案,它使用单个管道对象进行整个预处理并应用标签编码 【参考方案1】:我相信这实际上是LabelEncoder
的问题。 LabelEncoder.fit
方法只接受 self
和 y
作为参数(这很奇怪,因为大多数转换器对象都有 fit(X, y=None, **fit_params)
的范例)。无论如何,在管道中,无论您通过了什么,都会使用fit_params
调用转换器。在这种特殊情况下,传递给LabelEncoder.fit
的确切参数是X
和一个空字典。从而引发错误。
在我看来,这是 LabelEncoder
中的一个错误,但您应该与 sklearn 人员一起解决这个问题,因为他们可能有某些原因以不同的方式实现 fit
方法。
【讨论】:
这是正确答案。没有理由不能/不应该将 LabelEncoder 用于功能。 OneHotEncoding 与标签编码不同。在某些情况下,使用大型稀疏结构或序数编码可能没有意义。 但是你的解决方案是什么?【参考方案2】:这对您的目的不起作用有两个主要原因。
LabelEncoder()
旨在用于目标变量 (y)。这就是在columnTransformer()
尝试提供X, y=None, fit_params=
时出现位置参数错误的原因。
来自Documentation:
使用 0 和 n_classes-1 之间的值对标签进行编码。
适合(y) 拟合标签编码器
参数:y : 类似数组的形状 (n_samples,) 目标值。
-
即使您采取了一种解决方法来删除空字典,那么
LabelEncoder()
也不能采用 2D 数组(基本上一次使用多个特征),因为它只采用 1D y
值。
简短回答 - 我们不应该将 LabelEncoder()
用于输入功能。
现在,对输入特征进行编码的解决方案是什么?
如果您的特征是有序特征,请使用OrdinalEncoder()
,如果是名义特征,请使用OneHotEncoder()
。
例子:
>>> from sklearn.compose import ColumnTransformer
>>> from sklearn.preprocessing import OrdinalEncoder, OneHotEncoder
>>> X = np.array([[1000., 100., 'apple', 'green'],
... [1100., 100., 'orange', 'blue']])
>>> ct = ColumnTransformer(
... [("ordinal", OrdinalEncoder(), [0, 1]),
("nominal", OneHotEncoder(), [2, 3])])
>>> ct.fit_transform(X)
array([[0., 0., 1., 0., 0., 1.],
[1., 0., 0., 1., 1., 0.]])
【讨论】:
这就解释了。我经常看到 LabelEncoder 被“误用”于特征编码,以至于我认为它就是为此而设计的。 只是为了清楚空字典实际上是fit_params
。如果您浏览代码,您将看到sklearn.pipeline._fit_transform_one
被LabelEncoder
实例、数据框(X
)、None
(y
)和
(fit_params
)调用。 【参考方案3】:
它被称为 label 编码器,因为它旨在与数据集的 labels 一起使用,即y 值。这门课让我很困惑,直到我意识到这一点。
这令人困惑,因为在文献中,我们要么对我们的特征进行 One-Hot 编码,要么对它们进行标签编码。从这个意义上说,Sklearn 对新手并不是超级友好。
请改用OrdinalEncoder
,它旨在使用功能。
【讨论】:
以上是关于sklearn.compose.ColumnTransformer:fit_transform() 接受 2 个位置参数,但给出了 3 个的主要内容,如果未能解决你的问题,请参考以下文章