Concaténer les chaînes de plusieurs lignes à l'aide de Pandas groupby

92

Je souhaite fusionner plusieurs chaînes dans un dataframe basé sur un groupedby dans Pandas.

C'est mon code pour l'instant:

import pandas as pd
from io import StringIO

data = StringIO("""
"name1","hej","2014-11-01"
"name1","du","2014-11-02"
"name1","aj","2014-12-01"
"name1","oj","2014-12-02"
"name2","fin","2014-11-01"
"name2","katt","2014-11-02"
"name2","mycket","2014-12-01"
"name2","lite","2014-12-01"
""")

# load string as stream into dataframe
df = pd.read_csv(data,header=0, names=["name","text","date"],parse_dates=[2])

# add column with month
df["month"] = df["date"].apply(lambda x: x.month)

Je veux que le résultat final ressemble à ceci:

entrez la description de l'image ici

Je ne comprends pas comment je peux utiliser groupby et appliquer une sorte de concaténation des chaînes dans la colonne "texte". Toute aide appréciée!

mattiasostmar
la source

Réponses:

159

Vous pouvez grouper les colonnes 'name'et 'month', puis appeler transformqui renverra des données alignées sur le df d'origine et appliquer un lambda où nous joinles entrées de texte:

In [119]:

df['text'] = df[['name','text','month']].groupby(['name','month'])['text'].transform(lambda x: ','.join(x))
df[['name','text','month']].drop_duplicates()
Out[119]:
    name         text  month
0  name1       hej,du     11
2  name1        aj,oj     12
4  name2     fin,katt     11
6  name2  mycket,lite     12

Je sous le df original en passant une liste des colonnes d'intérêt df[['name','text','month']]ici, puis j'appelledrop_duplicates

EDIT en fait, je peux simplement appeler applyet ensuite reset_index:

In [124]:

df.groupby(['name','month'])['text'].apply(lambda x: ','.join(x)).reset_index()

Out[124]:
    name  month         text
0  name1     11       hej,du
1  name1     12        aj,oj
2  name2     11     fin,katt
3  name2     12  mycket,lite

mise à jour

le lambdan'est pas nécessaire ici:

In[38]:
df.groupby(['name','month'])['text'].apply(','.join).reset_index()

Out[38]: 
    name  month         text
0  name1     11           du
1  name1     12        aj,oj
2  name2     11     fin,katt
3  name2     12  mycket,lite
EdChum
la source
1
Dans pandas < 1.0, .drop_duplicates()ignore l'index, ce qui peut donner des résultats inattendus. Vous pouvez éviter cela en utilisant à la .agg(lambda x: ','.join(x))place de .transform().drop_duplicates().
Matthias Fripp
Propre et simple. Éminemment fleixible aussi
Raghavan vmvs
drop_duplicates()peut ne pas fonctionner si vous n'incluez pas de paramètre drop_duplicates(inplace=True)ou réécrivez simplement la ligne de code comme df = df[['name','text','month']].drop_duplicates()
IAmBotmaker
44

nous pouvons regrouper par les colonnes 'nom' et 'mois', puis appeler les fonctions agg () des objets DataFrame de Panda.

La fonctionnalité d'agrégation fournie par la fonction agg () permet de calculer plusieurs statistiques par groupe en un seul calcul.

df.groupby(['name', 'month'], as_index = False).agg({'text': ' '.join})

entrez la description de l'image ici

Ram Prajapati
la source
27

La réponse d'EdChum vous offre beaucoup de flexibilité, mais si vous souhaitez simplement concatérer des chaînes dans une colonne d'objets de liste, vous pouvez également:

output_series = df.groupby(['name','month'])['text'].apply(list)

Rutger Hofste
la source
Mec, tu viens de me faire gagner beaucoup de temps. Merci. C'est la meilleure façon d'assembler les listes chronologiques des enregistrements / identifiants d'utilisateurs en «cohortes» que je connaisse. Merci une fois de plus.
Alex Fedotov
5

Pour moi, les solutions ci-dessus étaient proches mais ont ajouté des / n et dtype: object indésirables, voici donc une version modifiée:

df.groupby(['name', 'month'])['text'].apply(lambda text: ''.join(text.to_string(index=False))).str.replace('(\\n)', '').reset_index()
Nic Scozzaro
la source