2017-02-01 5 views
1

Ich habe mit einer zusammenführenden Abfrage nach Hilfe gesucht, bin mir aber nicht sicher, wie meine Frage am präzisesten formuliert werden kann, sodass ich nichts gefunden habe das hilft direkt.Python-Datenrahmen in mehreren Spalten mit verschiedenen Join-Typen zusammenführen

Ich bin auf der Suche nach zwei Tabellen in drei Spalten mit einem linken Join zusammenführen, jedoch gibt es einige Null-Einträge im dritten Feld und in diesem Fall, ich glaube, ich möchte einen äußeren Join - also wenn es eine Übereinstimmung gibt In den ersten beiden Spalten werden die Daten verknüpft, unabhängig davon, ob in der dritten Spalte eine Übereinstimmung vorhanden ist.

df_A: 
Competitor Product Type  
A    P1   X 
A    P2   X 
A    P2   Y 
B    P1   X 
B    P1   Y 

df_B: 
Competitor Product Type Value  
A    P1   X  £5 
A    P2   X  £10 
A    P2   Y  £12 
B    P1     £15 

Ich möchte eine Zusammenführung auf diesen beiden Tabellen mit den Konkurrenten, Produkt und Typ Felder machen. Allerdings wird nicht immer ‚Type‘ Feld in der zweiten Tabelle gefüllt werden und in diesem Fall möchte ich den Wert für alle Typen in Tabelle A angewendet werden, das heißt:

Competitor Product Type Value 
A    P1   X  £5 
A    P2   X  £10 
A    P2   Y  £12 
B    P1   X  £15 
B    P1   Y  £15 

ich erfolgreich auf dem ersten zusammenführen können zwei Spalten mit dem Code:

df_merge=pd.merge(df_A,df_B,how='left',on=['Competitor','Product']) 

aber wenn ich die dritte Spalte ‚Typ‘ hinzufügen, diese auffüllt nur den Wert für die mit Streichhölzern in allen Spalten, das heißt:

Competitor Product Type Value 
A    P1   X  £5 
A    P2   X  £10 
A    P2   Y  £12 
B    P1   
B    P1   

gibt es eine Möglichkeit von Kombinationen die Join-Typen oder andere Wege, um zu dieser Lösung zu gelangen?

Antwort

2

Sie auf ['Competitor','Product'] fusionieren könnten:

df_merged = pd.merge(df_A, df_B, how='left', on=['Competitor','Product']) 

und dann die Zeilen auswählen, in dem entweder die Art ist die gleiche oder die Type_y ist der Platzhalter-Wert:

mask = (df_merged['Type'] == df_merged['Type_y']) | (df_merged['Type_y'] == '') 
result = df_merged.loc[mask, ['Competitor','Product','Type','Value']] 

Zum Beispiel ,

import pandas as pd 

df_A = pd.DataFrame({'Competitor': ['A', 'A', 'A', 'B', 'B'], 
'Product': ['P1', 'P2', 'P2', 'P1', 'P1'], 
'Type': ['X', 'X', 'Y', 'X', 'Y']}) 

df_B = pd.DataFrame({'Competitor': ['A', 'A', 'A', 'B'], 
'Product': ['P1', 'P2', 'P2', 'P1'], 
'Type': ['X', 'X', 'Y', ''], 
'Value': ['£5', '£10', '£12', '£15']},) 

df_merged = pd.merge(df_A, df_B, how='left', on=['Competitor','Product'], 
        suffixes=('','_y')) 
mask = (df_merged['Type'] == df_merged['Type_y']) | (df_merged['Type_y'] == '') 
result = df_merged.loc[mask, ['Competitor','Product','Type','Value']] 

print(result) 

Ausbeuten

Competitor Product Type Value 
0   A  P1 X £5 
1   A  P2 X £10 
4   A  P2 Y £12 
5   B  P1 X £15 
6   B  P1 Y £15 

Eine Kritik, die bei Verwendung von

pd.merge(df_A, df_B, how='left', on=['Competitor','Product']) 

geebnet werden könnte, ist, dass es eine Menge unnötiger Zeilen erzeugen könnten - all jene Zeilen, in denen Type_x nicht gleich Type_y tut . Wenn und df_B groß sind, kann dies zu übermäßiger Speicherauslastung führen.

dieses Problem zu lösen, könnten wir durch die Trennung df_B in zwei Teile sparsamer mit dem Speicher sein: Die Zeilen mit den Wildcard-Werte und jene ohne:

is_wild = pd.isnull(df_B['Type']) 
df_notwild, df_wild = df_B.loc[~is_wild], df_B.loc[is_wild] 

dann separat die beiden Teile zusammenführen. Wenn keine Platzhalterwerte vorhanden sind, können wir in allen Spalten zusammenführen.Wenn Platzhalter sind, wollen wir nur auf der rechten merge auf ['Competitor','Product']:

df_merged1 = pd.merge(df_A, df_notwild, how='inner') 
df_merged2 = pd.merge(df_A, df_wild, how='right', on=['Competitor','Product'], 
         suffixes=('','_y')).drop('Type_y', axis=1) 

Dann können die beiden Datenrahmen verkettet werden, um das gewünschte Ergebnis zu bilden:

result = pd.concat([df_merged1, df_merged2], ignore_index=True) 

So zu sparen Speicher,

import numpy as np 
import pandas as pd 

df_A = pd.DataFrame({'Competitor': ['A', 'A', 'A', 'B', 'B'], 
'Product': ['P1', 'P2', 'P2', 'P1', 'P1'], 
'Type': ['X', 'X', 'Y', 'X', 'Y']}) 

df_B = pd.DataFrame({'Competitor': ['A', 'A', 'A', 'B'], 
'Product': ['P1', 'P2', 'P2', 'P1'], 
'Type': ['X', 'X', 'Y', np.nan], 
'Value': ['£5', '£10', '£12', '£15']},) 

is_wild = pd.isnull(df_B['Type']) 
df_notwild, df_wild = df_B.loc[~is_wild], df_B.loc[is_wild] 

df_merged1 = pd.merge(df_A, df_notwild, how='inner') 
df_merged2 = pd.merge(df_A, df_wild, how='right', on=['Competitor','Product'], 
         suffixes=('','_y')).drop('Type_y', axis=1) 

result = pd.concat([df_merged1, df_merged2], ignore_index=True) 
print(result) 

erzeugt das gleiche Ergebnis wie die erste Methode, abov e.

+0

Wie würde dies für Felder, die NaN sind, angepasst werden? Anpassen des Codes an is_wild = df_B ['Typ'] == 'NaN' führt dazu, dass alle Einträge der Tabelle 'is wild' falsch sind – Sarah

+1

Wenn der Platzhalterwert 'NaN' ist, verwenden Sie' is_wild = pd.isnull (df_B ['Typ']) '. Ich habe das zweite Beispiel aktualisiert, um es zu demonstrieren. – unutbu

Verwandte Themen