2016-07-23 15 views
3

Dies ist ein Follow-up von this questionMerge Datenrahmen auf zwei Säulen

ich zwei Pandas haben Datenrahmen, wie folgt:

print(a) 

    foo bar let letval 
9 foo1 bar1 let1  a 
8 foo2 bar2 let1  b 
7 foo3 bar3 let1  c 
6 foo1 bar1 let2  z 
5 foo2 bar2 let2  y 
4 foo3 bar3 let2  x 

print(b) 

    foo bar num numval 
0 foo1 bar1 num1  1 
1 foo2 bar2 num1  2 
2 foo3 bar3 num1  3 
3 foo1 bar1 num2  4 
4 foo2 bar2 num2  5 
5 foo3 bar3 num2  6 

Ich möchte [ 'foo', 'bar' ] die zwei von ihnen auf den Säulen merge.

Wenn ich einfach c = pd.merge(a, b, on=['foo', 'bar']) tun, erhalte ich:

prnint(c) 

    foo bar let letval num numval 
0 foo1 bar1 let1  a num1  1 
1 foo1 bar1 let1  a num2  4 
2 foo1 bar1 let2  z num1  1 
3 foo1 bar1 let2  z num2  4 
4 foo2 bar2 let1  b num1  2 
5 foo2 bar2 let1  b num2  5 
6 foo2 bar2 let2  y num1  2 
7 foo2 bar2 let2  y num2  5 
8 foo3 bar3 let1  c num1  3 
9 foo3 bar3 let1  c num2  6 
10 foo3 bar3 let2  x num1  3 
11 foo3 bar3 let2  x num2  6 

Ich möchte:

print(c) 

    foo bar let letval num numval 
0 foo1 bar1 let1  a num1  1 
1 foo2 bar2 let1  b num1  2 
2 foo3 bar3 let1  c num1  3 
3 foo1 bar1 let2  z num2  4 
4 foo2 bar2 let2  y num2  5 
5 foo3 bar3 let2  x num2  6 

Der nächstgelegene ich habe ist:

c = pd.merge(a, b, left_index=['foo', 'bar'], right_index=['foo', 'bar']) 

Was bin ich fehlt ?

Und warum bekomme ich c.shape = (12,6) im ersten Beispiel?


bearbeiten

Dank @piRSquared's answer erkannte ich, dass das zugrunde liegende Problem besteht darin, dass es nicht eine einzige Kombination von Spalten ist, das zu tun. Somit kann das Zusammenführungsproblem, wie es zuvor gestellt wurde, nicht eindeutig gelöst werden. Das heißt, die Frage wird in eine einfachere umgewandelt:

Wie eine eindeutige Beziehung zwischen den Tabellen zu machen?

ich gelöst, dass mit einem Wörterbuch, das bildet die gewünschten Ausgänge, die ausgerichtet werden müssen:

map_ab = { 'num1':'let1', 'num2':'let2' } 
b['let'] = b.apply(lambda x: map_ab[x['num']], axis=1) 
c = pd.merge(a, b, on=['foo', 'bar', 'let']) 
print(c) 

Antwort

2

Der Grund, warum Sie das bekommen, ist, weil die Spalten, auf denen Sie zusammenführen, keine eindeutigen Kombinationen darstellen. Zum Beispiel hat die erste Zeile (Index 0) von afoo1 und bar1, aber auch die vierte Zeile (Index 3). Ok, das ist in Ordnung, aber b hat das gleiche Problem. Also, wenn Sie b 's foo1 & bar1 für Zeile indexiert mit 0 übereinstimmen, stimmt es zweimal überein. Das gleiche gilt, wenn Sie foo1 & bar1 in Zeile mit 3 indexiert übereinstimmen, es entspricht zweimal. Sie haben also vier Matches für diese zwei Reihen.

So erhalten Sie

  • a Zeile 0 Matches mit b Zeile 0
  • a Zeile 0 Matches mit b Reihe 3
  • a Zeile 3 Begegnungen mit b Zeile 0
  • a Reihe 3 Ursachen mit b Reihe 3

Und dann, Ihr Beispiel macht das noch 2 mal. 3 * 4 == 12

Die einzige Möglichkeit, dies zu tun und unzweideutig zu sein, besteht darin, sich für eine Regel zu entscheiden, welche Übereinstimmung zu treffen ist, wenn es mehr als eine Übereinstimmung gibt. Ich entschied mich, eine Ihrer anderen Spalten zu gruppieren und dann die erste zu nehmen. Es entspricht immer noch nicht Ihrer erwarteten Ausgabe, aber ich schlage vor, dass Sie ein schlechtes Beispiel gegeben haben.

pd.merge(a, b, on=['foo', 'bar']).groupby(['foo', 'bar', 'let'], as_index=False).first() 

enter image description here

+0

Großartige Erklärung, was passiert, besonders * wenn Sie b's foo1 & bar1 für Zeile indexieren, die mit 0 indiziert ist passt zweimal. *! – Luis

+0

Das Beispiel ist genauso gut/schlecht wie das Problem, das ich zur Hand habe. Zugegeben, ich habe etwas anderes gemacht (die DataFrames wurden anders als Dateien importiert), aber es ist eine Situation, die hin und wieder passiert. – Luis

+0

@Luis stimmte zu. Aber das ist das Problem. Angesichts der von Ihnen angegebenen Informationen gibt es keine eindeutige Antwortmöglichkeit. Ich hätte Duplikate fallen lassen können, aber das würde nicht die Antwort geben, nach der Sie gefragt haben. Irgendetwas stimmt nicht mit den Daten oder der Anfrage. Sie müssen sich versöhnen und erneut fragen. – piRSquared

1

können Sie verwenden combine_first:

In[21]:a.combine_first(b) 
Out[21]: 
    bar foo let letval num numval 
0 bar1 foo1 let1  a num1  1 
1 bar2 foo2 let1  b num1  2 
2 bar3 foo3 let1  c num1  3 
3 bar1 foo1 let2  z num2  4 
4 bar2 foo2 let2  y num2  5 
5 bar3 foo3 let2  x num2  6 

Im ersten Beispiel, das Sie tun werden inner join, die alle Zeilen zurückgibt, wenn bar & foo in a,b gleich sind.

+2

'combine_first' ist passend auf' index' und 'columns'. Es wird ein Datenframe erzeugt, das einen Index hat, der 'a.index.union (b.index)' ist und wie für die Spalten. Wenn Sie 'a = pd.DataFrame ([], list ('ab'), list ('AB'))' und 'b = pd.DataFrame ([], Liste ('cd'), list (' CD ')) 'dann' a.combine_first (b) 'wird ein 4x4 Datenrahmen sein. Der Punkt ist, Ihre Antwort ignoriert die Tatsache, dass das OP bei '['bar', 'foo']' 'mitmachen will und tatsächlich auf den gegebenen Integer-Index passt. – piRSquared

+0

@piRSquared Danke für das Zeigen Ich habe viel zu lernen. – shivsn

+0

Ja, combine_first funktioniert nur, weil die Indizes übereinstimmen. Wenn Sie 'a.index = [9,8,7,6,5,4] a.combine_first (b)' tun, wird es nicht mehr funktionieren. Außerdem tritt das Verhalten bei 'merge' mit jeder Option auf, um zu verbinden (' inner', 'outer' usw.). – Luis