web-dev-qa-db-fra.com

Comment standardiser uniquement les variables numériques dans un pipeline sklearn?

J'essaie de créer un pipeline Sklearn en 2 étapes:

  1. Normaliser les données
  2. Ajuster les données à l'aide de KNN

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?

7
Nate Hutchinson

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) ...

10
MaxU

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. 

5
Marcus V.

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)
    ]
)
1
ebrahimi