Ich habe Pandas-Daten mit einigen Textspalten erhalten. Neben diesen Textspalten gibt es einige NaN-Werte. Was ich versuche zu tun, ist, diese NaNs durch sklearn.preprocessing.Imputer
zu unterstellen (wobei NaN durch den häufigsten Wert ersetzt wird). Das Problem ist in der Implementierung . Angenommen, es gibt einen Pandas-Datenrahmen df mit 30 Spalten, von denen 10 kategorialer Natur sind.
from sklearn.preprocessing import Imputer
imp = Imputer(missing_values='NaN', strategy='most_frequent', axis=0)
imp.fit(df)
Python generiert einen error: 'could not convert string to float: 'run1''
, wobei 'run1' ein gewöhnlicher (nicht fehlender) Wert aus der ersten Spalte mit kategorialen Daten ist.
Jede Hilfe wäre sehr willkommen
Um Mittelwerte für numerische Spalten und den häufigsten Wert für nicht numerische Spalten zu verwenden, können Sie so etwas tun. Sie können weiter zwischen Ganzzahlen und Floats unterscheiden. Ich denke, es könnte sinnvoll sein, stattdessen den Median für ganzzahlige Spalten zu verwenden.
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)
welche druckt,
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
Sie können sklearn_pandas.CategoricalImputer
für die Kategoriespalten verwenden. Einzelheiten:
Erstens können Sie (aus dem Buch Hands-On Machine Learning mit Scikit-Learn und TensorFlow) über Unterpipelines für numerische und string-/kategoriale Funktionen verfügen, wobei der erste Transformator jeder Unterpipeline ein Selektor ist, der eine Liste von Spaltennamen (und die full_pipeline.fit_transform()
nimmt) ein 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
Sie können diese Subpipelines dann mit sklearn.pipeline.FeatureUnion
kombinieren, zum Beispiel:
full_pipeline = FeatureUnion(transformer_list=[
("num_pipeline", num_pipeline),
("cat_pipeline", cat_pipeline)
])
In num_pipeline
können Sie einfach sklearn.preprocessing.Imputer()
verwenden, aber in cat_pipline
können Sie CategoricalImputer()
aus dem sklearn_pandas
-Paket verwenden.
Hinweis: sklearn-pandas
-Paket kann mit pip install sklearn-pandas
installiert werden, es wird jedoch als import sklearn_pandas
importiert.
Inspiriert durch die Antworten hier und für das Fehlen eines Umgangs mit Imputer für alle Anwendungsfälle, schrieb ich das hier. Es unterstützt vier Strategien für die Imputation, wobei mean, mode, median, fill
sowohl für pd.DataFrame
als auch für Pd.Series
funktioniert.
mean
und median
funktionieren nur für numerische Daten, mode
und fill
für numerische und kategoriale Daten.
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)
verwendungszweck
>> 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
Ich kopierte und modifizierte die Antwort von sveitser
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)
Um es zu benutzen, würden Sie folgendes tun:
# 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' kann nur mit quantitativen Merkmalen verwendet werden, nicht mit qualitativen. Dieser kundenspezifische Impuer kann sowohl qualitativ als auch quantitativ verwendet werden. Auch mit scikit learn imputer können wir es entweder für den gesamten Datenrahmen verwenden (wenn alle Features quantitativ sind) oder wir können 'for loop' mit einer Liste ähnlicher Typen von Features/Spalten verwenden (siehe das folgende Beispiel). Custom Imputer kann jedoch mit beliebigen Kombinationen verwendet werden.
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]])
Benutzerdefinierte Betrüger:
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
Datenrahmen:
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) Kann mit einer Liste ähnlicher Art von Funktionen verwendet werden.
cci = CustomImputer(cols=['city', 'boolean']) # here default strategy = mean
cci.fit_transform(X)
kann mit Strategie = Median verwendet werden
sd = CustomImputer(['quantitative_column'], strategy = 'median')
sd.fit_transform(X)
3) Kann mit dem gesamten Datenrahmen verwendet werden, er verwendet den voreingestellten Mittelwert (oder wir können ihn auch mit dem Median ändern. Für qualitative Merkmale wird die Strategie = 'most_frequent' und für den quantitativen Mittelwert/Median verwendet.
call = CustomImputer()
call.fit_transform(X)
Dieser Code füllt eine Reihe mit der häufigsten Kategorie aus:
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)
Ausgänge:
m =
0 a
1 NaN
2 c
3 a
dtype: object
new_m =
0 a
1 a
2 c
3 a
dtype: object
Es gibt ein Paket sklearn-pandas
, das eine Option zur Imputation für die kategoriale Variable enthält 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)
Ähnlich. Ändern Sie Imputer
für 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)
dabei findet pandas.DataFrame.mode()
den häufigsten Wert für jede Spalte und füllt dann mit pandas.DataFrame.fillna()
fehlende Werte auf. Andere strategy
-Werte werden von Imputer
immer noch genauso behandelt.