fit_transform ()은 2 개의 위치 인수를 사용하지만 3 개는 LabelBinarizer로 제공되었습니다.
저는 기계 학습을 처음 접했고 감독되지 않은 학습 기술로 작업 해 왔습니다.
이미지는 내 샘플 데이터를 보여줍니다 (모든 청소 후) 스크린 샷 : 샘플 데이터
데이터 정리를 위해 빌드 된이 두 개의 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())
])
그런 다음이 두 파이프 라인의 결합을 수행했으며 동일한 코드는 아래와 같습니다.
from sklearn.pipeline import FeatureUnion
full_pipeline = FeatureUnion(transformer_list=[
("num_pipeline", num_pipeline),
("cat_pipeline", cat_pipeline),
])
이제 데이터 에 대해 fit_transform을 시도하고 있지만 오류가 표시됩니다.
변환 코드 :
housing_prepared = full_pipeline.fit_transform(housing)
housing_prepared
오류 메시지 : fit_transform ()은 2 개의 위치 인수를 사용하지만 3 개가 제공되었습니다.
문제 :
파이프 라인은 LabelBinarizer의 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_
귀하의 예는 Hands-On Machine Learning with Scikit-Learn & TensorFlow 책에서 나온 것이라고 생각합니다 . 불행히도이 문제도 발생했습니다. 최근 변경된 scikit-learn
( 0.19.0
) LabelBinarizer
의 fit_transform
방법이 변경되었습니다 . 불행히도 LabelBinarizer
그 예제가 그것을 사용하는 방식으로 작동하도록 의도되지 않았습니다. 여기 와 여기 에서 변경 사항에 대한 정보를 볼 수 있습니다 .
이에 대한 해결책을 찾을 때까지 0.18.0
다음과 같이 이전 버전 ( )을 설치할 수 있습니다 .
$ pip install scikit-learn==0.18.0
이를 실행하면 코드가 문제없이 실행됩니다.
미래에는 CategoricalEncoder
클래스 나 이와 유사한 것을 사용하는 것이 올바른 해결책이 될 것 같습니다 . 그들은 분명히 수년 동안이 문제를 해결하려고 노력해 왔습니다. 당신은 새로운 클래스 볼 수 있습니다 여기에 문제의 추가 논의를 여기에 .
LabelBinarizer는 2 개 이상의 위치 인수를 허용하지 않으므로 다음과 같은 사용자 지정 이진화기를 만들어야합니다.
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)
동일한 문제가 발생하여 책의 Github repo에 지정된 해결 방법을 적용하여 작동했습니다 .
경고 : 이전 버전의 책은이 시점에서 LabelBinarizer 클래스를 사용했습니다. 다시 말하지만 이것은 잘못된 것입니다. LabelEncoder 클래스와 마찬가지로 LabelBinarizer 클래스는 입력 기능이 아닌 레이블을 전처리하도록 설계되었습니다. 더 나은 솔루션은 Scikit-Learn의 곧 출시 될 CategoricalEncoder 클래스를 사용하는 것입니다. 곧 Scikit-Learn에 추가 될 예정이며 그 동안 아래 코드를 사용할 수 있습니다 (Pull Request # 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
Scikit Learn 및 Tensorflow를 사용한 Hands on Machine Learning 책의 예제를 살펴보고 있다고 생각합니다 . 2 장의 예제를 진행할 때 동일한 문제가 발생했습니다.
다른 사람들이 언급했듯이 문제는 sklearn의 LabelBinarizer와 관련이 있습니다. 파이프 라인의 다른 변환기에 비해 fit_transform 메서드에서 인수가 덜 걸립니다. (다른 트랜스포머가 일반적으로 X와 y를 모두 사용하는 경우에만 y, 자세한 내용은 여기 를 참조하십시오). 그래서 pipeline.fit_transform을 실행할 때 필요한 것보다 더 많은 인수를이 변환기에 입력했습니다.
내가 사용한 쉬운 수정은 OneHotEncoder를 사용하고 "sparse"를 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))
])
여기에서 갈 수 있으며 모든 것이 작동합니다.
간단히 말해, 파이프 라인 바로 전에 다음 클래스를 정의하면됩니다.
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())])
완료했습니다!
LaberBinarizer를 잊어 버리고 대신 OneHotEncoder를 사용하십시오.
OneHotEncoder 이전에 LabelEncoder를 사용하여 범주를 정수로 변환하는 경우 이제 OneHotEncoder를 직접 사용할 수 있습니다.
동일한 문제가 발생하여 DataFrameMapper를 사용하여 해결되었습니다 (sklearn_pandas를 설치해야 함).
from sklearn_pandas import DataFrameMapper
cat_pipeline = Pipeline([
('label_binarizer', DataFrameMapper([(cat_attribs, LabelBinarizer())])),
])
나는 결국 내 자신을 굴려
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]])
인코딩을 수행하는 사용자 지정 변환기를 하나 더 만들 수 있습니다.
class CustomLabelEncode(BaseEstimator, TransformerMixin):
def fit(self, X, y=None):
return self
def transform(self, X):
return LabelEncoder().fit_transform(X);
이 예에서는 LabelEncoding을 수행했지만 LabelBinarizer도 사용할 수 있습니다.
나는 또한 같은 문제에 직면했습니다. 다음 링크는이 문제를 해결하는 데 도움이되었습니다. https://github.com/ageron/handson-ml/issues/75
변경 사항 요약
1) Define following class in your notebook
class SupervisionFriendlyLabelBinarizer(LabelBinarizer):
def fit_transform(self, X, y=None):
return super(SupervisionFriendlyLabelBinarizer, self).fit_transform(X)
2) Modify following piece of code
cat_pipeline = Pipeline([('selector', DataFrameSelector(cat_attribs)),
('label_binarizer', SupervisionFriendlyLabelBinarizer()),])
3) Re-run the notebook. You will be able to run now
To perform one-hot encoding for multiple categorical features, we can create a new class which customizes our own multiple categorical features binarizer and plug it into categorical pipeline as follows.
Suppose CAT_FEATURES = ['cat_feature1', 'cat_feature2']
is a list of categorical features. The following scripts shall resolve the issue and produce what we want.
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))
])
'IT박스' 카테고리의 다른 글
XML 레이아웃에 조각을 추가하는 방법 (0) | 2020.11.14 |
---|---|
“Non Zero Exit Status”R 3.0.1 'XML'및 'RCurl' (0) | 2020.11.14 |
내 Perl 스크립트에 다른 파일의 함수를 어떻게 포함합니까? (0) | 2020.11.14 |
큰 수의 계수를 계산하는 방법은 무엇입니까? (0) | 2020.11.14 |
SQL Server Management Studio에서 "실제"CSV 형식으로 내보내기 출력을 얻는 방법은 무엇입니까? (0) | 2020.11.14 |