Supposons que j'ai un DataFrame comme ceci:

import pandas as pd
import numpy as np

df = pd.DataFrame(
    {
        'x0': [1, 2, np.nan, 5],
        'x1': [4, 5, 6, 10],
        'group': [2, 10, 10, 2],
        'id': [1, 2, 3, 4],
    }
)

Je veux appliquer une union d'estimateur / estimateur arbitraire à chaque colonne préfixée par x, donc je propose un estimateur de composition comme celui-ci:

from sklearn.preprocessing import StandardScaler
pd.DataFrame(df.groupby('group').apply(lambda x: StandardScaler().fit_transform(x.drop(['group', 'id'], axis=1))).explode().values.tolist())
#      0    1
# 0 -1.0 -1.0
# 1  1.0  1.0
# 2  0.0 -1.0
# 3  NaN  1.0

Comme nous le voyons, il n'y a vraiment pas un excellent moyen de suivre quel groupe ou index (colonne id) auquel ces lignes appartiennent. Je ne suis pas intéressé par la transformation inverse de ces caractéristiques mises à l'échelle. Comment puis-je suivre les colonnes group et id dans un tel pipeline?

J'ai regardé ici mais je n'ai pas pu obtenir la clé primaire et les autres fonctionnalités souhaitées à emporter.

0
blacksite 3 nov. 2020 à 16:21

2 réponses

Meilleure réponse

Vous êtes sur la bonne idée, mais vous pouvez simplifier et nettoyer votre code en plusieurs parties en utilisant les méthodes pandas de la bonne manière:

from sklearn.preprocessing import StandardScaler
from sklearn.compose import make_column_transformer

ct = make_column_transformer(
    (StandardScaler(), df.head(1).filter(like='x').columns),
    remainder='passthrough'
)

data = df.groupby('group').apply(ct.fit_transform).explode()
pd.DataFrame(data.tolist(), columns=df.columns)
    x0   x1  group   id
0 -1.0 -1.0    2.0  1.0
1  1.0  1.0    2.0  4.0
2  0.0 -1.0   10.0  2.0
3  NaN  1.0   10.0  3.0
1
Erfan 3 nov. 2020 à 13:38

Vous pouvez faire quelque chose comme ça, en utilisant sklearn.compose.make_column_transformer:

from sklearn.compose import make_column_transformer
columns_to_transform = [c for c in df if c not in ['group', 'id']]
columns_not_to_transform = ['group', 'id']
all_columns = columns_to_transform + columns_not_to_transform
obj = make_column_transformer(
    (StandardScaler(), columns_to_transform),
    ('passthrough', columns_not_to_transform),
)
pd.DataFrame(df.groupby('group').apply(lambda x: obj.fit_transform(x)).explode().values.tolist()).rename(columns = dict(zip(range(len(all_columns)), all_columns)))
    x0   x1  group   id
0 -1.0 -1.0    2.0  1.0
1  1.0  1.0    2.0  4.0
2  0.0 -1.0   10.0  2.0
3  NaN  1.0   10.0  3.0
0
blacksite 3 nov. 2020 à 13:33