J'ai des données sur les pandas avec des colonnes de type texte. Il y a quelques valeurs NaN avec ces colonnes de texte. Ce que j'essaie de faire est d'imputer ces NaN avec sklearn.preprocessing.Imputer
(en remplaçant NaN par la valeur la plus fréquente). Le problème est en cours d’application . Supposons qu’il existe une base de données Pandas contenant 30 colonnes, dont 10 de nature catégorique ...
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 des données catégorielles.
Toute aide est la bienvenue
Pour utiliser les valeurs moyennes pour les colonnes numériques et la valeur la plus fréquente pour les colonnes non numériques, vous pouvez procéder de la sorte. Vous pouvez encore distinguer entre les entiers et les flottants. J'imagine qu'il pourrait être judicieux 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, (tiré du livre Hands-On Machine Learning avec Scikit-Learn et TensorFlow), vous pouvez avoir des sous-lignes pour les fonctions numériques et chaînes/catégories, le premier transformateur de chaque sous-ligne étant un sélecteur prenant une liste de noms de colonnes (et la fonction full_pipeline.fit_transform()
un 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 avec sklearn.pipeline.FeatureUnion
, par 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 le cat_pipline
, vous pouvez utiliser CategoricalImputer()
à partir du paquetage sklearn_pandas
.
note: le paquetsklearn-pandas
peut être installé avec pip install sklearn-pandas
, mais il est importé en tant que import sklearn_pandas
Inspiré par les réponses fournies ici et par le manque d'un goto Imputer pour tous les cas d'utilisation, j'ai fini par écrire ceci. Il prend en charge quatre stratégies d'imputation mean, mode, median, fill
qui fonctionne à la fois sur pd.DataFrame
et Pd.Series
.
mean
et median
ne fonctionne que pour les données numériques, mode
et fill
fonctionne pour les données numériques et catégorielles.
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)
usage
>> 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
Copiant et modifiant la réponse du serveur, j'ai créé un imputer pour un objet pandas.Series
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, vous feriez:
# 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
strategy = 'most_frequent' ne peut être utilisé qu'avec des fonctionnalités quantitatives, pas qualitatives. Cet importateur personnalisé peut être utilisé à la fois qualitatif et quantitatif. Également avec scikit learn imputer, nous pouvons l’utiliser pour l’ensemble du bloc de données (si toutes les entités sont quantitatives) ou nous pouvons utiliser «for loop» avec une liste de types d’entités/colonnes similaires (voir l’exemple ci-dessous). Mais imputer personnalisé peut être utilisé avec toutes les combinaisons.
from sklearn.preprocessing import Imputer
impute = Imputer(strategy='mean')
for cols in ['quantitative_column', 'quant']: # here both are quantitative features.
xx[cols] = impute.fit_transform(xx[[cols]])
Imputer personnalisé:
from sklearn.preprocessing import Imputer
from sklearn.base import TransformerMixin
class CustomImputer(TransformerMixin):
def __init__(self, cols=None, strategy='mean'):
self.cols = cols
self.strategy = strategy
def transform(self, df):
X = df.copy()
impute = Imputer(strategy=self.strategy)
if self.cols == None:
self.cols = list(X.columns)
for col in self.cols:
if X[col].dtype == np.dtype('O') :
X[col].fillna(X[col].value_counts().index[0], inplace=True)
else : X[col] = impute.fit_transform(X[[col]])
return X
def fit(self, *_):
return self
Trame de données:
X = pd.DataFrame({'city':['tokyo', np.NaN, 'london', 'seattle', 'san
francisco', 'tokyo'],
'boolean':['yes', 'no', np.NaN, 'no', 'no', 'yes'],
'ordinal_column':['somewhat like', 'like', 'somewhat like', 'like',
'somewhat like', 'dislike'],
'quantitative_column':[1, 11, -.5, 10, np.NaN, 20]})
city boolean ordinal_column quantitative_column
0 tokyo yes somewhat like 1.0
1 NaN no like 11.0
2 london NaN somewhat like -0.5
3 seattle no like 10.0
4 san francisco no somewhat like NaN
5 tokyo yes dislike 20.0
1) Peut être utilisé avec une liste de types similaires de fonctionnalités.
cci = CustomImputer(cols=['city', 'boolean']) # here default strategy = mean
cci.fit_transform(X)
peut être utilisé avec la stratégie = médiane
sd = CustomImputer(['quantitative_column'], strategy = 'median')
sd.fit_transform(X)
3) Peut être utilisé avec un cadre de données complet, il utilisera la moyenne par défaut (ou nous pouvons également le changer avec la médiane. Pour les caractéristiques qualitatives, il utilise la stratégie = 'le plus fréquemment' et pour la moyenne/médiane quantitative.
call = CustomImputer()
call.fit_transform(X)
Ce code complète 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)
Les sorties:
m =
0 a
1 NaN
2 c
3 a
dtype: object
new_m =
0 a
1 a
2 c
3 a
dtype: object
Il existe un package sklearn-pandas
qui permet d'imputer une variable catégorique https://github.com/scikit-learn-contrib/sklearn-pandas#categoricalimputer
>>> from sklearn_pandas import CategoricalImputer
>>> data = np.array(['a', 'b', 'b', np.nan], dtype=object)
>>> imputer = CategoricalImputer()
>>> imputer.fit_transform(data)
array(['a', 'b', 'b', 'b'], dtype=object)
Similaire. Modifiez Imputer
pour 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, puis pandas.DataFrame.fillna()
remplit les valeurs manquantes avec celles-ci. Les autres valeurs strategy
sont toujours traitées de la même manière par Imputer
.