3
votes

Groupe Pandas En utilisant un autre DataFrame d'encodages one-hot / masques superposés

J'ai deux dataframes avec des observations sur les lignes et des fonctionnalités (ou l'appartenance à un groupe) sur des colonnes, par exemple:

> aggr_df

     a    b    c
g1   2    2    5
g2   2    3    2

Je souhaite regrouper et agréger (par somme) les valeurs dans le premier dataframe ( data_df ) conditionnel aux valeurs binaires (masques) dans le deuxième dataframe ( mask_df ). Le résultat devrait être le suivant (groupes x fonctionnalités):

> data_df

     a    b    c
A    1    2    1
B    0    1    3
C    0    0    1
D    2    1    1
E    1    1    1

> mask_df

    g1   g2
A    0    1
B    1    0
C    1    0
D    1    0
E    0    1

Y a-t-il un moyen dans les pandas de regrouper le premier dataframe ( data_df ) en utilisant masques contenus dans un second dataframe ( mask_df ) en une seule commande?


0 commentaires

5 Réponses :


2
votes

La meilleure façon de procéder est de combiner les dataframes. Vous pouvez combiner sur l'index en utilisant d'abord une instruction de jointure. df_merge = data_df.merge (aggr_df, left_on = True, right_on = True) . Ensuite, vous pouvez simplement utiliser df_merge pour vos opérations de regroupement.


0 commentaires

1
votes

Voici une manière d'utiliser une compréhension de liste:

pd.DataFrame([(data_df.T * mask_df[i]).sum(axis=1) for i in mask_df.columns], 
             index = mask.columns)

    a  b  c
g1  2  2  5
g2  2  3  2


0 commentaires

3
votes

Vous pouvez le faire à moindre coût avec dot et groupby:

mask_df.dot(mask_df.columns)

A    g2
B    g1
C    g1
D    g1
E    g2
dtype: object

Où ,

data_df.groupby(mask_df.dot(mask_df.columns)).sum()

    a  b  c
g1  2  2  5
g2  2  3  2


5 commentaires

Je pensais que le point était destiné à la multiplication matricielle, j'ai du mal à comprendre comment cela produirait le résultat souhaité. (Cela pourrait être la façon dont un manque de compréhension sur la façon dont cela fonctionne sous le capot.)


La fonctionnalité de @ Polkaguy6000 pandas dot a été étendue pour fonctionner avec des chaînes pour faire des trucs sympas comme ça.


Cela semble aussi fonctionner lorsque mask_df est une dataframe de booléens


Malheureusement, cette solution (bien que rapide) ne fonctionne qu'avec des masques qui ne se chevauchent pas, voir W-B's ou ma réponse pour une solution plus générale (dans le cas de l'agrégation somme / moyenne).


@ gc5 Nice, merci d'avoir souligné la distinction. J'ai voté pour votre réponse.



3
votes

Notez que cela fonctionnera même dans le cas où les observations de la première trame de données ( data_df ) appartiennent à plusieurs masques dans la deuxième trame de données ( mask_df ).

> pd.concat({x:data_df.mul(mask_df[x],0).sum() for x in mask_df}).unstack()

    a  b  c
g1  2  2  5
g2  2  3  2


2 commentaires

C'est plus général


Cependant, cela est très lent. Voir ma réponse pour une solution plus rapide dans le cas de l'agrégation somme / moyenne.



2
votes

J'ai décidé d'écrire une autre réponse depuis:

    La réponse de
  • coldspeed fonctionne uniquement avec des encodages à chaud
  • La réponse de
  • W-B ne peut pas être facilement parallélisée car elle fonctionne sur la compréhension de dictée

Dans mon cas, j'ai remarqué que je pouvais obtenir le même résultat simplement en utilisant un produit scalaire de mask_df avec data_df :

> mask_df.T.dot(data_df).div(mask_df.sum(), axis=0)

Dans le cas particulier de l'obtention de la moyenne au lieu de la somme, il est possible de mettre à l'échelle le mask_df par le nombre d'unités pour chaque groupe:

> mask_df.T.dot(data_df)


0 commentaires