2015-09-18 6 views
11

gleiche wie dieser python pandas: how to find rows in one dataframe but not in another? aber mit mehreren SpaltenPandas: Findet Datensätze, die in einem anderen Datenrahmen nicht existieren nach mehreren Spalten

Dies ist die Setup:

import pandas as pd 

df = pd.DataFrame(dict(
    col1=[0,1,1,2], 
    col2=['a','b','c','b'], 
    extra_col=['this','is','just','something'] 
)) 

other = pd.DataFrame(dict(
    col1=[1,2], 
    col2=['b','c'] 
)) 

Nun, ich möchte, dass die Auswahl Zeilen von df die nicht in anderen existieren. Ich möchte die Auswahl von col1 und col2

In SQL zu tun, würde ich tun:

select * from df 
where not exists (
    select * from other o 
    where df.col1 = o.col1 and 
    df.col2 = o.col2 
) 

Und in Pandas Ich kann so etwas tun, aber es fühlt sich sehr hässlich. Ein Teil der Hässlichkeit könnte vermieden werden, wenn df ID-Spalte hätte, aber es ist nicht immer verfügbar.

key_col = ['col1','col2'] 
df_with_idx = df.reset_index() 
common = pd.merge(df_with_idx,other,on=key_col)['index'] 
mask = df_with_idx['index'].isin(common) 

desired_result = df_with_idx[~mask].drop('index',axis=1) 

Also vielleicht gibt es einige eleganteren Weg?

Antwort

14

Seit 0.17.0 ein neues indicator param ist Sie merge passieren kann denen sagen Sie, ob die Zeilen nur links, rechts oder beides vorhanden sind:

In [5]: 
merged = df.merge(other, how='left', indicator=True) 
merged 

Out[5]: 
    col1 col2 extra_col  _merge 
0  0 a  this left_only 
1  1 b   is  both 
2  1 c  just left_only 
3  2 b something left_only 

In [6]:  
merged[merged['_merge']=='left_only'] 

Out[6]: 
    col1 col2 extra_col  _merge 
0  0 a  this left_only 
2  1 c  just left_only 
3  2 b something left_only 

So können Sie nun das fusionierte df filtern, indem Sie nur 'left_only' Reihen

+1

Vielen Dank für das Zurückkommen. Sie könnten dies in einer Zeile mit 'df.merge (andere, wie = 'links', Indikator = True) .query ('_ merge ==" left_only "') tun, aber ich weiß nicht, ob das besser ist. – Pekka

+0

Persönlich finde ich zu viel Verkettung für die Herstellung eines ein Liner kann den Code schwieriger zu lesen, kann es einige Geschwindigkeit und Speicher Verbesserungen sein, obwohl – EdChum

+1

@Pekka: +, um in einer Zeile zurück zu ursprünglichen links: 'df .merge (andere, wie = 'links', Indikator = True) .query ('_ merge == "left_only"'). drop (['_ merge'], axis = 1) ' – SpeedCoder5

1

Interessante

cols = ['col1','col2'] 
#get copies where the indeces are the columns of interest 
df2 = df.set_index(cols) 
other2 = other.set_index(cols) 
#Look for index overlap, ~ 
df[~df2.index.isin(other2.index)] 

Returns:

col1 col2 extra_col 
0  0 a  this 
2  1 c  just 
3  2 b something 

ein bisschen eleganter scheint ...

+1

Wenn Sie den Index auf diese cols gesetzt können Sie [ 'difference'] (http://pandas.pydata.org/pandas -docs/stable/generated/pandas.Index.difference.html # pandas.Index.difference), um das gleiche Ergebnis zu erreichen – EdChum

Verwandte Themen