2017-12-03 1 views
5

ich Pandas Datenrahmen df haben:Wie alle Paare von Werten, aus dem Ergebnis eines groupby erzeugen, in einem Pandas Datenrahmen

ID  words 
1  word1 
1  word2 
1  word3 
2  word4 
2  word5 
3  word6 
3  word7 
3  word8 
3  word9 

Ich möchte einen anderen Datenrahmen erzeugen, die alle Paare von Wörtern in jeder erzeugen würde Gruppe. So ergibt sich für das oben wäre:

ID  wordA wordB 
1  word1 word2 
1  word1 word3 
1  word2 word3 
2  word4 word5 
3  word6 word7 
3  word6 word8 
3  word6 word9 
3  word7 word8 
3  word7 word9 
3  word8 word9 

Ich weiß, dass ich df.groupby['words'] verwendet wird, kann in jedem ID die Worte zu bekommen.

Ich weiß auch, dass ich

iterable = ['word1','word2','word3'] 
list(itertools.combinations(iterable, 2)) 

zu bekommen alle möglichen paarweisen Kombinationen verwenden können. Allerdings bin ich ein wenig verloren, um den resultierenden Datenrahmen wie oben gezeigt am besten zu erzeugen.

+0

Ich habe den Titel bearbeitet, um das tatsächliche Problem yo besser widerzuspiegeln Du versuchst zu lösen. –

+1

nein der neue Titel hat nichts damit zu tun, was ich will ... danke für die Mühe aber ... – BKS

+0

Mögliche Duplikat: https://stackoverflow.com/questions/43800390/how-to-create-all-combinations- spaltenweise-für-mehrere-Variablen-in-Pandas –

Antwort

3

Seine einfache Verwendung itertools Kombinationen innerhalb anwenden und stapeln dh

from itertools import combinations 
ndf = df.groupby('ID')['words'].apply(lambda x : list(combinations(x.values,2))) 
          .apply(pd.Series).stack().reset_index(level=0,name='words') 

ID   words 
0 1 (word1, word2) 
1 1 (word1, word3) 
2 1 (word2, word3) 
0 2 (word4, word5) 
0 3 (word6, word7) 
1 3 (word6, word8) 
2 3 (word6, word9) 
3 3 (word7, word8) 
4 3 (word7, word9) 
5 3 (word8, word9) 

Sie genaue Ausgabe Passend weiter wir

sdf = pd.concat([ndf['ID'],ndf['words'].apply(pd.Series)],1).set_axis(['ID','WordsA','WordsB'],1,inplace=False) 

    ID WordsA WordsB 
0 1 word1 word2 
1 1 word1 word3 
2 1 word2 word3 
0 2 word4 word5 
0 3 word6 word7 
1 3 word6 word8 
2 3 word6 word9 
3 3 word7 word8 
4 3 word7 word9 
5 3 word8 word9 

wandeln es in eine eine Linie, die wir tun können, zu tun haben:

combo = df.groupby('ID')['words'].apply(combinations,2)\ 
        .apply(list).apply(pd.Series)\ 
        .stack().apply(pd.Series)\ 
        .set_axis(['WordsA','WordsB'],1,inplace=False)\ 
        .reset_index(level=0) 
+0

Genau genommen sieht es so aus, als ob das Ergebnis im OP in zwei Spalten aufgeteilt werden sollte, was ein weiterer Schritt ist? Ich bin neugierig, ob das alles effizienter ist als nur ein neues df zu bauen? Wird "Apply" nicht als Python-Schleife ausgeführt? – roganjosh

+0

Ah, ich habe langsam meinen ersten Kommentar geschrieben re: weiterer Schritt :) – roganjosh

+0

Hmmm, es scheint, es gibt eine bessere Rückkehr 'DataFrame' von' apply';) – jezrael

2

Sie können eine benutzerdefinierte Funktion definieren, die auf jede Gruppe angewendet wird. Eingang und Ausgang sind ein Datenrahmen:

def combine(group): 
    return pd.DataFrame.from_records(itertools.combinations(group.word, 2)) 

df.groupby('ID').apply(combine) 

Ergebnis:

  0  1 
ID     
1 0 word1 word2 
    1 word1 word3 
    2 word2 word3 
2 0 word4 word5 
3 0 word6 word7 
    1 word6 word8 
    2 word6 word9 
    3 word7 word8 
    4 word7 word9 
    5 word8 word9 
3

Sie groupby mit apply verwenden können und DataFrame zurückkehren, zuletzt reset_index hinzufügen für die zweite Ebene entfernen und dann für die Spalte aus dem Index erstellen :

from itertools import combinations 

f = lambda x : pd.DataFrame(list(combinations(x.values,2)), 
          columns=['wordA','wordB']) 
df = (df.groupby('ID')['words'].apply(f) 
           .reset_index(level=1, drop=True) 
           .reset_index()) 
print (df) 
    ID wordA wordB 
0 1 word1 word2 
1 1 word1 word3 
2 1 word2 word3 
3 2 word4 word5 
4 3 word6 word7 
5 3 word6 word8 
6 3 word6 word9 
7 3 word7 word8 
8 3 word7 word9 
9 3 word8 word9 
Verwandte Themen