pandas – Combinar filas casi duplicadas según el valor de la columna

Tengo un dataframe de pandas con varias filas que están cerca de duplicados entre sí, excepto por un valor. Mi objective es fusionar o “unir” estas filas en una sola fila, sin sumr los valores numéricos.

Aquí hay un ejemplo de lo que estoy trabajando:

 Name Sid Use_Case Revenue A xx01 Voice $10.00 A xx01 SMS $10.00 B xx02 Voice $5.00 C xx03 Voice $15.00 C xx03 SMS $15.00 C xx03 Video $15.00 

Y esto es lo que me gustaría:

 Name Sid Use_Case Revenue A xx01 Voice, SMS $10.00 B xx02 Voice $5.00 C xx03 Voice, SMS, Video $15.00 

La razón por la que no quiero sumr la columna “Ingresos” es porque mi tabla es el resultado de hacer un pivote durante varios períodos de tiempo en los que “Ingresos” simplemente se enumeran varias veces en lugar de tener un valor diferente según “Use_Case” .

¿Cuál sería la mejor manera de abordar este problema? He groupby() función groupby() pero aún no lo entiendo muy bien.

Creo que puedes usar groupby con aggregate first y función personalizada ', '.join :

 df = df.groupby('Name').agg({'Sid':'first', 'Use_Case': ', '.join, 'Revenue':'first' }).reset_index() #change column order print df[['Name','Sid','Use_Case','Revenue']] Name Sid Use_Case Revenue 0 A xx01 Voice, SMS $10.00 1 B xx02 Voice $5.00 2 C xx03 Voice, SMS, Video $15.00 

Buena idea del comentario, gracias Goyo :

 df = df.groupby(['Name','Sid','Revenue'])['Use_Case'].apply(', '.join).reset_index() #change column order print df[['Name','Sid','Use_Case','Revenue']] Name Sid Use_Case Revenue 0 A xx01 Voice, SMS $10.00 1 B xx02 Voice $5.00 2 C xx03 Voice, SMS, Video $15.00 

Estaba usando un código que no creía que fuera óptimo y finalmente encontré la respuesta de Jezrael . Pero después de usarlo y realizar una prueba de tiempo, volví a lo que estaba haciendo, que era:

 cmnts = {} for i, row in df.iterrows(): while True: try: if row['Use_Case']: cmnts[row['Name']].append(row['Use_Case']) else: cmnts[row['Name']].append('n/a') break except KeyError: cmnts[row['Name']] = [] df.drop_duplicates('Name', inplace=True) df['Use_Case'] = ['; '.join(v) for v in cmnts.values()] 

De acuerdo con mi prueba 100 timeit , el método de iteración y reemplazo es un orden de magnitud más rápido que el método groupby .

 import pandas as pd from my_stuff import time_something df = pd.DataFrame({'a': [i / (i % 4 + 1) for i in range(1, 10001)], 'b': [i for i in range(1, 10001)]}) runs = 100 interim_dict = 'txt = {}\n' \ 'for i, row in df.iterrows():\n' \ ' try:\n' \ " txt[row['a']].append(row['b'])\n\n" \ ' except KeyError:\n' \ " txt[row['a']] = []\n" \ "df.drop_duplicates('a', inplace=True)\n" \ "df['b'] = ['; '.join(v) for v in txt.values()]" grouping = "new_df = df.groupby('a')['b'].apply(str).apply('; '.join).reset_index()" print(time_something(interim_dict, runs, beg_string='Interim Dict', glbls=globals())) print(time_something(grouping, runs, beg_string='Group By', glbls=globals())) 

rendimientos

 Interim Dict Total: 59.1164s Avg: 591163748.5887ns Group By Total: 430.6203s Avg: 4306203366.1827ns 

donde time_something es una función que timeit un fragmento de timeit con timeit y devuelve el resultado en el formato anterior.

Puedes groupby y apply la función de list :

 >>> df['Use_Case'].groupby([df.Name, df.Sid, df.Revenue]).apply(list).reset_index() Name Sid Revenue 0 0 A xx01 $10.00 [Voice, SMS] 1 B xx02 $5.00 [Voice] 2 C xx03 $15.00 [Voice, SMS, Video] 

(En caso de que le preocupen los duplicados, use set lugar de list ).