Attribuer des valeurs manquantes catégoriques à scikit-learn
j'ai des données pandas avec des colonnes de type texte. Il y a quelques valeurs de NaN avec ces colonnes de texte. Ce que j'essaie de faire, c'est d'imputer ces NaN à sklearn.preprocessing.Imputer
(remplaçant NaN par la valeur la plus fréquente). Le problème est dans la mise en œuvre.
Supposons Qu'il existe une base de données Pandas avec 30 colonnes, dont 10 sont de nature catégorique.
Une fois que j'ai lancer:
from sklearn.preprocessing import Imputer
imp = Imputer(missing_values='NaN', strategy='most_frequent', axis=0)
imp.fit(df)
Python génère un error: 'could not convert string to float: 'run1''
, où 'run1' est une valeur ordinaire (non manquante) de la première colonne avec données catégoriques.
Toute aide serait la bienvenue
6 réponses
pour utiliser les valeurs moyennes pour les colonnes numériques et la valeur la plus fréquente pour les colonnes non numériques, vous pourriez faire quelque chose comme ça. Vous pouvez encore distinguer entre les entiers et les flotteurs. Je suppose qu'il pourrait être logique d'utiliser la médiane pour les colonnes entières à la place.
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)
qui 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
Vous pouvez utiliser sklearn_pandas.CategoricalImputer
pour les colonnes catégoriques. Détails:
tout D'abord, (du livre Hands-On Machine Learning with Scikit-Learn and TensorFlow) vous pouvez avoir des sous-lignes pour les caractéristiques numériques et string/categorical, où le premier transformateur de chaque sous-ligne est un sélecteur qui prend une liste de noms de colonne (et le full_pipeline.fit_transform()
prend une pandas DataFrame):
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
Vous pouvez ensuite combiner ces sous pipelines sklearn.pipeline.FeatureUnion
, pour exemple:
full_pipeline = FeatureUnion(transformer_list=[
("num_pipeline", num_pipeline),
("cat_pipeline", cat_pipeline)
])
Maintenant, dans le num_pipeline
vous pouvez simplement utiliser sklearn.preprocessing.Imputer()
, mais dans l' cat_pipline
, vous pouvez utiliser CategoricalImputer()
sklearn_pandas
paquet.
remarque:sklearn-pandas
le paquet peut être installé avec pip install sklearn-pandas
, mais il est importé comme import sklearn_pandas
copier et modifier la réponse de sveitser, j'ai fait un emputer pour un pandas.La série de l'objet
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)
Pour l'utiliser, il ferait:
# 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
ce code remplit une série avec la catégorie la plus fréquente:
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)
Sorties:
m =
0 a
1 NaN
2 c
3 a
dtype: object
new_m =
0 a
1 a
2 c
3 a
dtype: object
Inspiré par les réponses ici et un goto Imputer pour tous les cas d'utilisation j'ai fini par écrire. Il soutient quatre stratégies pour l'imputation mean, mode, median, fill
fonctionne sur les deux pd.DataFrame
et Pd.Series
.
mean
et median
fonctionne uniquement pour les données numériques,mode
et fill
fonctionne à la fois pour les données numériques et catégoriques.
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)
utilisation
>> 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
Similaire. Modifier Imputer
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)
où pandas.DataFrame.mode()
trouve la valeur la plus fréquente pour chaque colonne et ensuite pandas.DataFrame.fillna()
remplit des valeurs manquantes. D'autres strategy
les valeurs sont toujours traités de la même façon par Imputer
.