Verketten Sie Zeichenfolgen aus mehreren Zeilen mit Pandas groupby


92

Ich möchte mehrere Zeichenfolgen in einem Datenrahmen zusammenführen, der auf einer Gruppierung in Pandas basiert.

Dies ist mein bisheriger Code:

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)

Ich möchte, dass das Endergebnis so aussieht:

Geben Sie hier die Bildbeschreibung ein

Ich verstehe nicht, wie ich groupby verwenden und eine Art Verkettung der Zeichenfolgen in der Spalte "Text" anwenden kann. Jede Hilfe geschätzt!

Antworten:


160

Sie können nach den Spalten 'name'und gruppieren 'month', dann aufrufen transform, um Daten zurückzugeben, die an der ursprünglichen df ausgerichtet sind, und ein Lambda anwenden, in dem wir joindie Texteingaben vornehmen:

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

Ich reiche den ursprünglichen df ein, indem ich hier eine Liste der interessierenden Spalten übergebe df[['name','text','month']]und dann anrufedrop_duplicates

EDIT eigentlich kann ich einfach anrufen applyund dann 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

aktualisieren

das lambdaist hier unnötig:

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

1
In pandas < 1.0, .drop_duplicates()ignoriert den Index, die zu unerwarteten Ergebnissen führen kann. Sie können dies vermeiden, indem Sie .agg(lambda x: ','.join(x))anstelle von verwenden .transform().drop_duplicates().
Matthias Fripp

Ordentlich und unkompliziert. Hervorragend fleixibel auch
Raghavan vmvs

drop_duplicates()funktioniert möglicherweise nicht, wenn Sie keinen Parameter einschließen drop_duplicates(inplace=True)oder die Codezeile einfach neu schreiben als df = df[['name','text','month']].drop_duplicates()
IAmBotmaker

44

Wir können nach den Spalten 'name' und 'month' gruppieren und dann agg () -Funktionen der DataFrame-Objekte von Panda aufrufen.

Die von der Funktion agg () bereitgestellte Aggregationsfunktion ermöglicht die Berechnung mehrerer Statistiken pro Gruppe in einer Berechnung.

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

Geben Sie hier die Bildbeschreibung ein


27

Die Antwort von EdChum bietet Ihnen viel Flexibilität. Wenn Sie jedoch nur Zeichenfolgen in eine Spalte mit Listenobjekten einbinden möchten, können Sie auch:

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


Mann, du hast mir gerade viel Zeit gespart. Vielen Dank. Dies ist der beste Weg, um die chronologischen Listen der Registrierungen / Benutzer-IDs zu mir bekannten Kohorten zusammenzustellen. Vielen Dank noch mal.
Alex Fedotov

5

Für mich waren die oben genannten Lösungen nahe beieinander, fügten jedoch einige unerwünschte / n und dtype: object hinzu. Hier ist also eine modifizierte Version:

df.groupby(['name', 'month'])['text'].apply(lambda text: ''.join(text.to_string(index=False))).str.replace('(\\n)', '').reset_index()
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.