2017-11-07 2 views
2

Ich habe zwei DataFrames, die die gleichen Spaltennamen mit einigen übereinstimmenden Daten und einigen eindeutigen Daten haben.nur Outer Join Python Pandas

Ich möchte die Mitte ausschließen und nur speichern, was für beide DataFrames einzigartig ist.

Wie würde ich diese zwei Datenrahmen concat oder zusammenführen oder verbinden, um dies zu tun?

Zum Beispiel in diesem Bild, das ich nicht über die Mitte in diesem Bild, ich will beiden Seiten aber nicht in der Mitte:

enter image description here

Hier mein Code ist jetzt:

def query_to_df(query): 
    ... 
    df_a = pd.DataFrame(data_a) 
    df_b = pd.DataFrame(data_b) 
    outer_results = pd.concat([df_a, df_b], axis=1, join='outer') 
    return df 

Lassen Sie mich Ihnen ein Beispiel dafür geben, was ich brauche:

df_a = 
col_a col_b col_c 
    a1  b1  c1 
    a2  b2  c2 

df_b = 
col_a col_b col_c 
    a2  b2  c2 
    a3  b3  c3 

# they only share the 2nd row: a2  b2  c2 
# so the outer result should be: 
col_a col_b col_c col_a col_b col_c 
    a1  b1  c1  NA  NA  NA 
    NA  NA  NA  a3  b3  c3 

oder Ich würde mit 2 Datenrahmen

result_1 = 
col_a col_b col_c 
    a1  b1  c1 

result_2 = 
col_a col_b col_c 
    a3  b3  c3 

schließlich genauso glücklich sein, werden Sie feststellen, dass a2 b2 c2 ausgeschlossen wurden, weil alle Spalten übereinstimmen - wie ich fest, dass ich auf Basis anschließen möchten, auf alle Spalten, nicht nur 1? Wenn df_a gehabt hätte, würde ich diese Reihe auch in result_1 haben wollen.

+1

Ich denke, Sie suchen nach 'pd.merge' nicht' pd.concat'. Eigentlich, nicht ganz sicher, wie du verschmelzest ... Ich denke, eine genauere Beschreibung ist, dass du Zeilen bekommst, die nur in einer Tabelle vorhanden sind. Selbst dann bin ich nicht sicher, warum du sie nebeneinander hast, denn jetzt hast du 2 'col_a' und' col_b' und 'col_c' – AsheKetchum

Antwort

3

Verwenden merge mit indicator Parameter und outer join erste und dann durch query oder boolean indexing filtern:

df = df_a.merge(df_b, how='outer', indicator=True) 
print (df) 
    col_a col_b col_c  _merge 
0 a1 b1 c1 left_only 
1 a2 b2 c2  both 
2 a3 b3 c3 right_only 

a = df.query('_merge == "left_only"').drop('_merge', 1) 
print (a) 
    col_a col_b col_c 
0 a1 b1 c1 

b = df.query('_merge == "right_only"').drop('_merge', 1) 
print (b) 
    col_a col_b col_c 
2 a3 b3 c3 

Oder:

a = df[df['_merge'] == "left_only"].drop('_merge', 1) 
print (a) 
    col_a col_b col_c 
0 a1 b1 c1 

b = df[df['_merge'] == "right_only"].drop('_merge', 1) 
print (b) 
    col_a col_b col_c 
2 a3 b3 c3 
2

Verwenden pd.DataFrame.drop_duplicates
Dies setzt die Zeilen in ihre jeweiligen eindeutigen waren Datenrahmen.

df_a.append(df_b).drop_duplicates(keep=False) 

    col_a col_b col_c 
0 a1 b1 c1 
1 a3 b3 c3 

Sie können sogar pd.concat mit dem keys Parameter verwenden, um den Kontext zu geben, in dem die Reihe kam.

pd.concat([df_a, df_b], keys=['a', 'b']).drop_duplicates(keep=False) 

    col_a col_b col_c 
a 0 a1 b1 c1 
b 1 a3 b3 c3 
+1

das habe ich gesehen. Das ist Schlau! – piRSquared

1

concat und drop_duplicates mit keep = False

new_df = pd.concat([df_a, df_b]).drop_duplicates(keep=False) 

    col_a col_b col_c 
0 a1  b1  c1 
1 a3  b3  c3 

Mit numpy setdiff1

df_a = pd.DataFrame(np.setdiff1d(np.array(df_a.values), np.array(df_b.values))\ 
.reshape(-1, df_a.shape[1]), columns = df_a.columns) 

df_b = pd.DataFrame(np.setdiff1d(np.array(df_b.values), np.array(df_a.values))\ 
.reshape(-1, df_b.shape[1]), columns = df_b.columns) 

df_a

col_a col_b col_c 
0 a1  b1  c1 

df_b

col_a col_b col_c 
0 a3  b3  c3