Ich versuche, eine Sklearn-Pipeline mit 2 Schritten zu erstellen:
Meine Daten haben jedoch sowohl numerische als auch kategoriale Variablen, die ich mit pd.get_dummies
in Dummies konvertiert habe. Ich möchte die numerischen Variablen standardisieren, aber die Dummys so lassen, wie sie sind. Ich habe das so gemacht:
X = dataframe containing both numeric and categorical columns
numeric = [list of numeric column names]
categorical = [list of categorical column names]
scaler = StandardScaler()
X_numeric_std = pd.DataFrame(data=scaler.fit_transform(X[numeric]), columns=numeric)
X_std = pd.merge(X_numeric_std, X[categorical], left_index=True, right_index=True)
Wenn ich jedoch eine Pipeline erstellen würde:
pipe = sklearn.pipeline.make_pipeline(StandardScaler(), KNeighborsClassifier())
Dies würde alle Spalten in meinem DataFrame standardisieren. Gibt es eine Möglichkeit, dies zu tun, während nur die numerischen Spalten standardisiert werden?
Angenommen, Sie haben das folgende DF:
In [163]: df
Out[163]:
a b c d
0 aaa 1.01 xxx 111
1 bbb 2.02 yyy 222
2 ccc 3.03 zzz 333
In [164]: df.dtypes
Out[164]:
a object
b float64
c object
d int64
dtype: object
sie können alle numerischen Spalten finden:
In [165]: num_cols = df.columns[df.dtypes.apply(lambda c: np.issubdtype(c, np.number))]
In [166]: num_cols
Out[166]: Index(['b', 'd'], dtype='object')
In [167]: df[num_cols]
Out[167]:
b d
0 1.01 111
1 2.02 222
2 3.03 333
und wende StandardScaler
nur auf diese numerischen Spalten an:
In [168]: scaler = StandardScaler()
In [169]: df[num_cols] = scaler.fit_transform(df[num_cols])
In [170]: df
Out[170]:
a b c d
0 aaa -1.224745 xxx -1.224745
1 bbb 0.000000 yyy 0.000000
2 ccc 1.224745 zzz 1.224745
jetzt können Sie "eine heiße Kodierung" kategoriale (nicht numerische) Spalten erstellen ...
Ich würde FeatureUnion verwenden. Ich mache dann normalerweise so etwas, vorausgesetzt, Sie verschlüsseln Ihre kategorialen Variablen auch innerhalb der Pipeline anstatt zuvor mit Pandas:
from sklearn.pipeline import Pipeline, FeatureUnion, make_pipeline
from sklearn.preprocessing import OneHotEncoder
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.neighbors import KNeighborsClassifier
class Columns(BaseEstimator, TransformerMixin):
def __init__(self, names=None):
self.names = names
def fit(self, X, y=None, **fit_params):
return self
def transform(self, X):
return X[self.names]
numeric = [list of numeric column names]
categorical = [list of categorical column names]
pipe = Pipeline([
("features", FeatureUnion([
('numeric', make_pipeline(Columns(names=numeric),StandardScaler())),
('categorical', make_pipeline(Columns(names=categorical),OneHotEncoder(sparse=False)))
])),
('model', KNeighborsClassifier())
])
Sie können auch weiter nach Sklearn Pandas suchen, was auch interessant ist.
Da Sie Ihre kategorialen Funktionen mit pd.get_dummies
in Dummies konvertiert haben, müssen Sie OneHotEncoder
nicht verwenden. Als Ergebnis sollte Ihre Pipeline sein:
from sklearn.preprocessing import StandardScaler,FunctionTransformer
from sklearn.pipeline import Pipeline,FeatureUnion
knn=KNeighborsClassifier()
pipeline=Pipeline(steps= [
('feature_processing', FeatureUnion(transformer_list = [
('categorical', FunctionTransformer(lambda data: data[:, cat_indices])),
#numeric
('numeric', Pipeline(steps = [
('select', FunctionTransformer(lambda data: data[:, num_indices])),
('scale', StandardScaler())
]))
])),
('clf', knn)
]
)