sklearn onehotencoder labelencoder example python pandas scikit-learn imputation

python - onehotencoder - sklearn



Imputar valores categóricos faltantes en scikit-learn (6)

Tengo datos de pandas con algunas columnas de tipo de texto. Hay algunos valores de NaN junto con estas columnas de texto. Lo que trato de hacer es imputar esos NaN por sklearn.preprocessing.Imputer (reemplazando NaN por el valor más frecuente). El problema está en la implementación. Supongamos que hay un marco de datos de Pandas df con 30 columnas, 10 de las cuales son de naturaleza categórica. Una vez que corro:

from sklearn.preprocessing import Imputer imp = Imputer(missing_values=''NaN'', strategy=''most_frequent'', axis=0) imp.fit(df)

Python genera un error: ''could not convert string to float: ''run1'''' , donde ''run1'' es un valor ordinario (no perdido) de la primera columna con datos categóricos.

Cualquier ayuda sería muy bienvenida


Copiando y modificando la respuesta de sveitser, hice una imputer para un objeto pandas.Series

class CustomImputer(BaseEstimator, TransformerMixin): def __init__(self, strategy=''mean'',filler=''NA''): self.strategy = strategy self.fill = filler def fit(self, X, y=None): if self.strategy in [''mean'',''median'']: if not all(X.dtypes == np.number): raise ValueError(''dtypes mismatch np.number dtype is / required for ''+ self.strategy) if self.strategy == ''mean'': self.fill = X.mean() elif self.strategy == ''median'': self.fill = X.median() elif self.strategy == ''mode'': self.fill = X.mode().iloc[0] elif self.strategy == ''fill'': if type(self.fill) is list and type(X) is pd.DataFrame: self.fill = dict([(cname, v) for cname,v in zip(X.columns, self.fill)]) return self def transform(self, X, y=None): return X.fillna(self.fill)

Para usarlo harías:

>> df MasVnrArea FireplaceQu Id 1 196.0 NaN 974 196.0 NaN 21 380.0 Gd 5 350.0 TA 651 NaN Gd >> CustomImputer(strategy=''mode'').fit_transform(df) MasVnrArea FireplaceQu Id 1 196.0 Gd 974 196.0 Gd 21 380.0 Gd 5 350.0 TA 651 196.0 Gd >> CustomImputer(strategy=''fill'', filler=[0, ''NA'']).fit_transform(df) MasVnrArea FireplaceQu Id 1 196.0 NA 974 196.0 NA 21 380.0 Gd 5 350.0 TA 651 0.0 Gd


Este código completa una serie con la categoría más frecuente:

import pandas as pd import numpy as np # create fake data m = pd.Series(list(''abca'')) m.iloc[1] = np.nan #artificially introduce nan print(''m = '') print(m) #make dummy variables, count and sort descending: most_common = pd.get_dummies(m).sum().sort_values(ascending=False).index[0] def replace_most_common(x): if pd.isnull(x): return most_common else: return x new_m = m.map(replace_most_common) #apply function to original data print(''new_m = '') print(new_m)

Productos:

m = 0 a 1 NaN 2 c 3 a dtype: object new_m = 0 a 1 a 2 c 3 a dtype: object


Inspirado por las respuestas aquí y por la falta de un Impost para todos los casos de uso, terminé escribiendo esto. Es compatible con cuatro estrategias para la imputación mean, mode, median, fill funciona tanto en pd.DataFrame como en Pd.Series .

mean y median funciona solo para datos numéricos, mode y trabajos de fill para datos numéricos y categóricos.

import numpy import pandas from sklearn.base import TransformerMixin class SeriesImputer(TransformerMixin): def __init__(self): """Impute missing values. If the Series is of dtype Object, then impute with the most frequent object. If the Series is not of dtype Object, then impute with the mean. """ def fit(self, X, y=None): if X.dtype == numpy.dtype(''O''): self.fill = X.value_counts().index[0] else : self.fill = X.mean() return self def transform(self, X, y=None): return X.fillna(self.fill)

uso

# Make a series s1 = pandas.Series([''k'', ''i'', ''t'', ''t'', ''e'', numpy.NaN]) a = SeriesImputer() # Initialize the imputer a.fit(s1) # Fit the imputer s2 = a.transform(s1) # Get a new series


Para usar valores medios para columnas numéricas y el valor más frecuente para columnas no numéricas, puede hacer algo como esto. Puede distinguir aún más entre enteros y flotantes. Supongo que podría tener sentido usar la mediana para las columnas enteras.

import pandas as pd import numpy as np from sklearn.base import TransformerMixin class DataFrameImputer(TransformerMixin): def __init__(self): """Impute missing values. Columns of dtype object are imputed with the most frequent value in column. Columns of other types are imputed with mean of column. """ def fit(self, X, y=None): self.fill = pd.Series([X[c].value_counts().index[0] if X[c].dtype == np.dtype(''O'') else X[c].mean() for c in X], index=X.columns) return self def transform(self, X, y=None): return X.fillna(self.fill) data = [ [''a'', 1, 2], [''b'', 1, 1], [''b'', 2, 2], [np.nan, np.nan, np.nan] ] X = pd.DataFrame(data) xt = DataFrameImputer().fit_transform(X) print(''before...'') print(X) print(''after...'') print(xt)

que imprime,

before... 0 1 2 0 a 1 2 1 b 1 1 2 b 2 2 3 NaN NaN NaN after... 0 1 2 0 a 1.000000 2.000000 1 b 1.000000 1.000000 2 b 2.000000 2.000000 3 b 1.333333 1.666667


Puede usar sklearn_pandas.CategoricalImputer para las columnas categóricas. Detalles:

Primero, (del libro Hands-On Machine Learning con Scikit-Learn y TensorFlow) puede tener subcapas para características numéricas y de cadena / categóricas, donde el primer transformador de cada subpipeline es un selector que toma una lista de nombres de columna (y la línea full_pipeline.fit_transform() toma un Dataframe de pandas):

class DataFrameSelector(BaseEstimator, TransformerMixin): def __init__(self, attribute_names): self.attribute_names = attribute_names def fit(self, X, y=None): return self def transform(self, X): return X[self.attribute_names].values

A continuación, puede combinar estas subcategorías con sklearn.pipeline.FeatureUnion , por ejemplo:

full_pipeline = FeatureUnion(transformer_list=[ ("num_pipeline", num_pipeline), ("cat_pipeline", cat_pipeline) ])

Ahora, en num_pipeline puede simplemente usar sklearn.preprocessing.Imputer() , pero en cat_pipline , puede usar CategoricalImputer() desde el paquete sklearn_pandas .

nota: el paquete sklearn-pandas se puede instalar con la pip install sklearn-pandas , pero se importa como import sklearn_pandas


Similar. Modificar Imputer para strategy=''most_frequent'' :

class GeneralImputer(Imputer): def __init__(self, **kwargs): Imputer.__init__(self, **kwargs) def fit(self, X, y=None): if self.strategy == ''most_frequent'': self.fills = pd.DataFrame(X).mode(axis=0).squeeze() self.statistics_ = self.fills.values return self else: return Imputer.fit(self, X, y=y) def transform(self, X): if hasattr(self, ''fills''): return pd.DataFrame(X).fillna(self.fills).values.astype(str) else: return Imputer.transform(self, X)

donde pandas.DataFrame.mode() encuentra el valor más frecuente para cada columna y luego pandas.DataFrame.fillna() rellena los valores faltantes con estos. Otros valores strategy todavía se manejan de la misma manera por Imputer .