J'essaie de créer un pipeline Sklearn en 2 étapes:
Cependant, mes données ont à la fois des variables numériques et catégoriques, que j'ai converties en variables nominales à l'aide de pd.get_dummies
. Je veux normaliser les variables numériques mais laisser les nuls tels qu’ils sont. J'ai fait ça comme ça:
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)
Cependant, si je devais créer un pipeline comme:
pipe = sklearn.pipeline.make_pipeline(StandardScaler(), KNeighborsClassifier())
Cela uniformiserait toutes les colonnes de mon DataFrame. Y at-il un moyen de faire cela en normalisant uniquement les colonnes numériques?
En supposant que vous ayez le DF suivant:
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
vous pouvez trouver toutes les colonnes numériques:
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
et n'appliquez StandardScaler
qu'à ces colonnes numériques:
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
maintenant, vous pouvez "un encodage à chaud" des colonnes catégoriques (non numériques) ...
Je voudrais utiliser FeatureUnion . Ensuite, je fais habituellement quelque chose comme ça, en supposant que vous encodiez vos variables catégoriques de manière factuelle également dans le pipeline au lieu d’avant avec les 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())
])
Vous pouvez également consulter Sklearn Pandas , qui est également intéressant.
Puisque vous avez converti vos entités catégoriques en variables nominales à l'aide de pd.get_dummies
, vous n'avez donc pas besoin d'utiliser OneHotEncoder
. En conséquence, votre pipeline devrait être:
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)
]
)