Skip to main content
 首页 » 编程设计

python之如何使用集合差异比较 pandas DataFrames

2024年09月03日39think

我有 df1 和 df2:

df1 = pd.DataFrame([[1,1,1,1],[2,2,1,1],[0,0,1,1],[1,1,1,1],[2,2,1,1],[0,0,4,1]],  
                   columns=['col1','col2','col3','col4']) 
df2 = pd.DataFrame([[1,1,1,1],[3,3,1,1],[0,0,1,1],[1,1,5,1],[3,3,1,1],[0,0,1,1]],  
                   columns=['col1','col2','col3','col4']) 

我删除了重复的行:

df1 = df1.drop_duplicates(subset=['col1', 'col2', 'col3']) 
df2 = df2.drop_duplicates(subset=['col1', 'col2', 'col3']) 

所以每个 df 都由唯一的行组成。但是两个 dfs 之间有一些重叠:

   col1  col2  col3  col4 
0     1     1     1     1 
1     2     2     1     1 
2     0     0     1     1 
5     0     0     4     1 
 
   col1  col2  col3  col4 
0     1     1     1     1 
1     3     3     1     1 
2     0     0     1     1 
3     1     1     5     1 

我的实际 df1 和 df2 的形状大约为 (5000000, 23),包括 int、float 和对象字段。


开始编辑: 我想创建 df1_uniq(df1 中有但 df2 中没有)和 df2_uniq(df2 中有但 df1 中没有。

df1_iniq: 
   col1  col2  col3  col4 
1     2     2     1     1 
5     0     0     4     1 
 
df2_uniq: 
   col1  col2  col3  col4 
1     3     3     1     1 
3     1     1     5     1 

结束编辑


在集合表示法中,我认为这将是 df1.difference(df2) 和 df2.difference(df1),但是当我运行该代码时我得到了空集。请注意,比较每个 df 中的单个列确实有效,例如,

set(df_1[field].unique()).difference(set(df_2[field].unique()))

返回 [2]。

另一种方法是遍历每个 df,如果 df1[i] 等于 df2 中的任何行,则删除两个 df 中的行。但这是一种复杂度为 O(n**2) 的方法,需要很长时间。

是否有更 pythonic 和 pandastic 的方法来做到这一点?

请您参考如下方法:

您可以使用 merge 和 indicator=True:

u = df1.merge(df2, how='outer', indicator=True) 
df3 = u.query('_merge == "left_only"').drop('_merge', 1) 
df4 = u.query('_merge == "right_only"').drop('_merge', 1) 
 
df3 
 
   col1  col2  col3  col4 
1     2     2     1     1 
3     0     0     4     1 
 
df4 
 
   col1  col2  col3  col4 
4     3     3     1     1 
5     1     1     5     1 

如果 df1 和 df2 的列名不同,请确保它们都相同:

df1.columns = df2.columns 

如果索引也需要保留,可以在合并前先reset,合并后设置。

u, v = df1.reset_index(), df2.reset_index() 
w = (u.merge(v, how='outer', on=df1.columns.tolist(), indicator=True) 
      .fillna({'index_x': -1, 'index_y': -1}, downcast='infer')) 
w 
 
   index_x  col1  col2  col3  col4  index_y      _merge 
0        0     1     1     1     1        0        both 
1        1     2     2     1     1       -1   left_only 
2        2     0     0     1     1        2        both 
3        5     0     0     4     1       -1   left_only 
4       -1     3     3     1     1        1  right_only 
5       -1     1     1     5     1        3  right_only 

现在,

df3 = (w.query('_merge == "left_only"') 
        .set_index('index_x') 
        .drop(['_merge', 'index_y'], 1) 
        .rename_axis([None], axis=0)) 
df4 = (w.query('_merge == "right_only"') 
        .set_index('index_y') 
        .drop(['_merge', 'index_x'], 1) 
        .rename_axis([None], axis=0)) 
 
df3 
 
   col1  col2  col3  col4 
1     2     2     1     1 
5     0     0     4     1 
 
df4 
 
   col1  col2  col3  col4 
1     3     3     1     1 
3     1     1     5     1