1
votes

group by + case quand dans une autre colonne avec des pandas

J'ai un modèle de données avec trois colonnes (CUST_ID, TOPIC, VALUE)

result = pd.DataFrame({"CUST_ID":["C1", "C2", "C3"],
                       "TOPIC_a_VALUE":[10, np.nan, 5],
                       "TOPIC_b_VALUE":[15, 8, 20]})

Je souhaite regrouper par CUST_ID, transformer la colonne "TOPIC" en deux colonnes "TOPIC_a_VALUE" et "TOPIC_b_VALUE "

Je sais comment le faire par SQL, mais comment le faire par des pandas?

SELECT CUST_ID,
       MAX(CASE WHEN TOPIC = "TOPIC1" THEN VALUE ELSE 0 END) AS TOPIC_a_VALUE
       MAX(CASE WHEN TOPIC = "TOPIC2" THEN VALUE ELSE 0 END) AS TOPIC_b_VALUE
FROM TABLE
GROUP BY CUST_ID

Le résultat que je veux est ci-dessous, p >

data = pd.DataFrame({"CUST_ID":["C1", "C1", "C2", "C3", "C3"],
                       "TOPIC":["TOPIC1", "TOPIC2", "TOPIC2", "TOPIC1", "TOPIC2"],
                       "VALUE":[10, 15, 8, 5, 20]})


4 commentaires

Pourriez-vous s'il vous plaît poster à quoi ressemble votre sortie finale en utilisant des données aléatoires


@Sumanth j'ajoute les données originales et le résultat par trame de données pandas


il n'y a pas de TOPIC = "a" dans les données d'origine, veuillez l'ajouter afin que nous puissions répliquer


@ anky_91 Je modifie la faute de frappe, merci


4 Réponses :


0
votes

Votre requête n'a pas de sens en SQL. Je suppose que vous avez l'intention de quelque chose comme ceci:

SELECT CUST_ID,
       MAX(CASE WHEN TOPIC = 'a' THEN VALUE ELSE 0 END) AS TOPIC_a_VALUE
       MAX(CASE WHEN TOPIC = 'b' THEN VALUE ELSE 0 END) AS TOPIC_b_VALUE
FROM TABLE
GROUP BY CUST_ID;

Cela n'aide pas directement avec la solution Pandas, mais au moins la requête aura du sens.


1 commentaires

Pense à @Gordon Linoff, j'oublie la fonction d'aggération.



1
votes

IIUC vous avez besoin de quelque chose comme:

df=data.pivot_table(index=['CUST_ID','TOPIC'],columns=['TOPIC']).reset_index()
df.columns=[''.join(col) for col in df.columns.values]
df.loc[df.CUST_ID.duplicated(keep=False)]=df.loc[df.CUST_ID.duplicated(keep=False)].bfill()
df=df.drop_duplicates('CUST_ID')
df=df.drop([col for col in df.columns if 'Key' in col],axis=1).reset_index(drop=True)

print(df)

  CUST_ID   TOPIC  VALUETOPIC1  VALUETOPIC2
0      C1  TOPIC1         10.0         15.0
1      C2  TOPIC2          NaN          8.0
2      C3  TOPIC1          5.0         20.0


0 commentaires

3
votes

Peut-être plus lisible que les autres réponses suggérées, j'irais avec:

.rename(columns={'TOPIC1': 'TOPIC_a_VALUE', 'TOPIC2': 'TOPIC_b_VALUE'})

Si vous préférez, vous pouvez bien sûr renommer les colonnes:

data.groupby(['CUST_ID', 'TOPIC'])['VALUE'].max().unstack()
# Output
#TOPIC   TOPIC1 TOPIC2
#CUST_ID              
#C1        10.0   15.0
#C2         NaN    8.0
#C3         5.0   20.0


1 commentaires

Oui, c'est mieux. Je ne pouvais pas penser à ça hier soir. +1



0
votes

Vous pouvez utiliser groupby de la manière suivante:

df1 = df1.drop(columns = ['TOPIC']).
rename(columns{'VALUETOPIC1':'TOPIC_a_VALUE','VALUETOPIC2':'TOPIC_b_VALUE'})

Pour nettoyer le dataframe

df=data.pivot_table(index=['CUST_ID','TOPIC'],columns=['TOPIC']).reset_index()
df.columns=[''.join(col) for col in df.columns.values]

df1 = df.groupby('CUST_ID').ffill()\
        .groupby('CUST_ID').last()\
        .reset_index()


0 commentaires