Пользовательский кодировщик scikit выдает ошибку преобразования

Я адаптирую некоторый онлайн-код для создания своей собственной версии One Hot Encoder для обучения scikit. Пользовательский класс делает для меня несколько вещей, в основном он позволяет установить порог, ниже которого редкие уровни категориальной переменной сбрасываются в "другой" класс. Я могу соответствовать правильно, но когда я пытаюсь преобразовать, я получаю ошибку преобразования, как будто встроенный LabelEncoder, который запускается до того, как OHE не работает должным образом.

from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.utils.validation import check_is_fitted
import pandas as pd
import numpy as np

#my custom OHE-er
class CustomPandasTransformer(BaseEstimator, TransformerMixin):
    def _validate_input(self, X):
        if not isinstance(X, pd.DataFrame):
            raise TypeError('X must be a DataFrame, but gor type=%s' % type(x))
        return X

    @staticmethod
    def _validate_columns(X, cols):
        scols = set(X.columns)
        if not all(c in scols for c in cols):
            raise ValueError("all columns must be present in X")

class DummyEncoder(CustomPandasTransformer):
    def __init__(self, columns, sep='_', drop_one_level=True, tmp_nan_rep='MISSING',other_treshold=20):
        self.columns=columns
        self.sep = sep
        self.drop_one_level = drop_one_level
        self.tmp_nan_rep = tmp_nan_rep
        self.other_treshold = other_treshold


    def fit(self, X, y=None):
        X = self._validate_input(X).copy()

        tmp_nan = self.tmp_nan_rep
        oth_thr = self.other_treshold

        cols = self.columns
        self._validate_columns(X, cols)

        lab_encoders = {}
        for col in cols:
            #group low freq levels into a 'OTHER' level
            tmp_vc = X[col].value_counts()
            high_volume_levels = list(tmp_vc[tmp_vc>oth_thr].index)
            vec = [v if v in high_volume_levels else 'OTHER' for v in X[col].tolist()]

            vec = [tmp_nan if pd.isnull(v) else v for v in vec]
            svec = list(set(vec))
            if tmp_nan not in svec:
                svec.append(tmp_nan)

            le = LabelEncoder()
            lab_encoders[col] = le.fit(svec)

            X[col] = le.transform(vec)

        ohe_set = X[cols]
        ohe_nan_row = {c: lab_encoders[c].transform([tmp_nan])[0] for c in cols}
        ohe_set = ohe_set.append(ohe_nan_row, ignore_index=True)
        ohe = OneHotEncoder(sparse=False).fit(ohe_set)

        self.ohe_ = ohe
        self.le_ = lab_encoders
        self.cols_ = cols

        return self

    def transform(self, X):
        check_is_fitted(self, 'ohe_')
        X = self._validate_input(X).copy()

        ohe = self.ohe_
        lenc = self.le_
        cols = self.cols_
        tmp_nan = self.tmp_nan_rep
        sep = self.sep
        drop = self.drop_one_level

        self._validate_columns(X, cols)
        col_order = []
        drops = []

        for col in cols:
            le = lenc[col]

            vec = [v if v in list(le.classes_) else 'OTHER' for v in X[col].tolist()]
            vec = [tmp_nan if pd.isnull(v) else v for v in vec]

            vec_trans = le.transform(vec)
            X[col] = vec_trans

            le_clz = le.classes_.tolist()
            classes = ['%s%s%s' % (col,sep,clz) for clz in le_clz]
            col_order.extend(classes)

            if drop and len(le_clz)>1:
                drops.append(classes[-1])

            ohe_trans = pd.DataFrame.from_records(data=ohe.transform(X[cols]),
                                                columns = col_order)

            ohe_trans.index=X.index

            if drops:
                ohe_trans = ohe_trans.drop(drops, axis=1)

            X = X.drop(cols, axis=1)

            X = pd.concat([X, ohe_trans], axis=1)
            return X

#the data
dicpd = {
 u'BILL_CLASS': {0: np.nan, 1: np.nan},
 u'CL_SUB_TYPE': {0: 'M', 1: 'M'},
 u'COB_TYPE': {0: np.nan, 1: np.nan},
 u'DUP_BILL_CLASS': {0: np.nan, 1: np.nan},
 u'DUP_CL_SUB_TYPE': {0: 'M', 1: 'M'},
 u'DUP_COB_TYPE': {0: np.nan, 1: np.nan},
 u'DUP_DX_CD': {0: 'M9901', 1: 'Z0100'},
 u'DUP_FAC_TYPE': {0: np.nan, 1: np.nan},
 u'DUP_FREQUENCY': {0: np.nan, 1: np.nan},
 u'DUP_LOB_ID': {0: 'PBC1', 1: 'PBC1'},
 u'DUP_MOD1': {0: np.nan, 1: np.nan},
 u'DUP_MOD2': {0: np.nan, 1: np.nan},
 u'DUP_MOD3': {0: np.nan, 1: np.nan},
 u'DUP_MOD4': {0: np.nan, 1: np.nan},
 u'DUP_POS_CD': {0: '11', 1: '11'},
 u'DUP_PROC_CD': {0: '98941', 1: 'V2020'},
 u'DUP_REV_CD': {0: np.nan, 1: np.nan},
 u'DX_CD': {0: 'M9901', 1: 'Z0100'},
 u'FAC_TYPE': {0: np.nan, 1: np.nan},
 u'FREQUENCY': {0: np.nan, 1: np.nan},
 u'MBR_AGE': {0: 48, 1: 56},
 u'MOD1': {0: '59', 1: np.nan},
 u'MOD2': {0: np.nan, 1: np.nan},
 u'MOD3': {0: np.nan, 1: np.nan},
 u'MOD4': {0: np.nan, 1: np.nan},
 u'POS_CD': {0: '11', 1: '11'},
 u'PROC_CD': {0: '97140', 1: 'V2781'},
 u'REV_CD': {0: np.nan, 1: np.nan},
 u'RULE_1': {0: 0, 1: 0},
 u'RULE_3': {0: 1, 1: 1},
 u'RULE_4': {0: 1, 1: 1},
 u'RULE_5': {0: 0, 1: 0},
 u'RULE_6': {0: 1, 1: 1},
 'SAME_DX': {0: 1, 1: 1},
 'SAME_POS_CD': {0: 1, 1: 1},
 'SAME_PROC': {0: 0, 1: 0},
 'SAME_PROV': {0: 1, 1: 1},
 'SAME_REV': {0: 0, 1: 0},
 'SAME_TOT': {0: 3, 1: 3},
 u'SYSTEM_GEN_DRG': {0: np.nan, 1: np.nan}}

#read into pandas
df1 = pd.DataFrame(dicpd)

#get object types
categorical_features = list(df1.select_dtypes(include=['object']).columns)

de = DummyEncoder(columns = categorical_features,other_treshold=10,drop_one_level=False)

de.fit(df1)

de.transform(df1)


ValueErrorTraceback (most recent call last)
<ipython-input-5-3a72a3fa8104> in <module>()
    161 de.fit(df1)
    162 
--> 163 de.transform(df1)

<ipython-input-5-3a72a3fa8104> in transform(self, X)
     95                 drops.append(classes[-1])
     96 
---> 97             ohe_trans = pd.DataFrame.from_records(data=ohe.transform(X[cols]),
     98                                                 columns = col_order)
     99 

/data/dataiku-dss-4.2.3/python.packages/sklearn/preprocessing/data.pyc in transform(self, X)
   2073         """
   2074         return _transform_selected(X, self._transform,
-> 2075                                    self.categorical_features, copy=True)
   2076 
   2077 

/data/dataiku-dss-4.2.3/python.packages/sklearn/preprocessing/data.pyc in _transform_selected(X, transform, selected, copy)
   1807     X : array or sparse matrix, shape=(n_samples, n_features_new)
   1808     """
-> 1809     X = check_array(X, accept_sparse='csc', copy=copy, dtype=FLOAT_DTYPES)
   1810 
   1811     if isinstance(selected, six.string_types) and selected == "all":

/data/dataiku-dss-4.2.3/python.packages/sklearn/utils/validation.pyc in check_array(array, accept_sparse, dtype, order, copy, force_all_finite, ensure_2d, allow_nd, ensure_min_samples, ensure_min_features, warn_on_dtype, estimator)
    431                                       force_all_finite)
    432     else:
--> 433         array = np.array(array, dtype=dtype, order=order, copy=copy)
    434 
    435         if ensure_2d:

ValueError: could not convert string to float: V2781

1 ответ

Я разобрался с ошибкой. Весь раздел

ohe_trans = pd.DataFrame.from_records(data=ohe.transform(X[cols]),
                                                columns = col_order)

            ohe_trans.index=X.index

            if drops:
                ohe_trans = ohe_trans.drop(drops, axis=1)

            X = X.drop(cols, axis=1)

был внутри петли столбцов. Необходимо запустить после завершения предыдущего цикла.

Другие вопросы по тегам