报告 difference/change 两个相同形状的数据帧之间的值

Report difference/change in values between two dataFrames of identical shape

上下文是我想比较两个 df 并找出差异。

这里的 df 和 df2 有一点不同:

df = pd.DataFrame({'a': range(3),
                   'b': range(3)})

df2 = df.copy()
df2.iloc[1,1] = 100

比较它们会产生相同形状的二维布尔 df:

df != df2
Out[28]: 
       a      b
0  False  False
1  False   True
2  False  False

我尝试提取对应于 True 的元素,但其他元素(我不想要的)仍然以 NaN 出现

df[df != df2]
Out[29]: 
    a    b
0 NaN  NaN
1 NaN  1.0
2 NaN  NaN

如何只提取对应于 True 和索引的元素(所以我知道 df 中的位置):

df[df != df2] # somehow?
Out[30]: 
    b
1 1.0

更新:上面的例子只有一个True。在有多个True的一般情况下,我认为有两种情况:

  1. df很小,大家可以看看:

    df = pd.DataFrame({'a': range(3),
                       'b': range(3)})
    
    df2 = df.copy()
    df2.iloc[0,0] = 100
    df2.iloc[1,1] = 100
    
    df[df!=df2].dropna(how='all',axis=(0,1)) # U9-Forward's answer
    Out[39]: 
         a    b
    0  0.0  NaN
    1  NaN  1.0
    
  2. df很大,大家可以看看:

    index    column   df_value     df2_value
        0         a        0.0           100
        1         b        1.0           100
    

@U9-Forward 的回答非常适用于情况 1,并且只有一个为真。

@coldspeed 提供了一个全面的解决方案。谢谢!

使用条件然后dropna:

print(df[df!=df2].dropna(how='all',axis=(0,1)))

掩码值:

df.values[df != df2]
# array([1])

这个案子应该怎么处理?

df2.at[0, 'a'] = 100

df
   a  b
0  0  0
1  1  1
2  2  2

df2
     a    b
0  100    0
1    1  100
2    2    2

df != df2 
       a      b
0   True  False
1  False   True
2  False  False

df.values[df != df2]
# array([0, 1])

# in the other answer
df[df!=df2].dropna(how='all',axis=(0,1))
     a    b
0  0.0  NaN
1  NaN  1.0

所需的输出是什么?


如果您只是 df 的每一列中的值不同,那么像 aggdropna 这样简单的值就可以了。

df[df != df2].agg(lambda x: x.dropna().tolist())

a    [0.0]
b    [1.0]
dtype: object

如果需要索引和列,请使用 melt:

u = df2.reset_index().melt('index')
v = df.reset_index().melt('index')

u[u['value'] != v['value']]
   index variable  value
0      0        a    100
4      1        b    100

或者,使用 np.nonzero,用 numpy 来做到这一点 - 真值是非零的,它们的索引被返回。

m = (df != df2).values
idx, cols = np.nonzero(m)

pd.DataFrame({
    'index': df.index.values[idx],
    'column': df.columns.values[cols],
    'value_1': df.values[m],
    'value_2': df2.values[m]
})

   index column  value_1  value_2
0      0      a        0      100
1      1      b        1      100

如果需要有关索引和列的信息,请为 MultiIndex Series 添加 stack:

df = pd.DataFrame({'a': range(3),
                   'b': range(3)})

df2 = df.copy()
df2.iloc[1,1] = 100
df2.iloc[0,0] = 100

s = df.stack()
s2 = df2.stack()
out = s[s != s2].rename_axis(['idx','col']).reset_index(name='val')
print (out)
   idx col  val
0    0   a    0
1    1   b    1

out2 = s2[s != s2].rename_axis(['idx','col']).reset_index(name='val')
print (out2)
   idx col  val
0    0   a  100
1    1   b  100

或将 numpy indexingnumpy.where 一起用于 True 值的索引:

mask = df != df2
a = np.where(mask)

out = pd.DataFrame({'idx': df.index.values[a[0]],
                    'cols': df.columns.values[a[1]],
                    'vals_df': df.values[mask],
                    'vals_df2': df2.values[mask]})
print (out)
   idx cols  vals_df  vals_df2
0    0    a        0       100
1    1    b        1       100

一个 numpy 解决方案:

mask = df2[df!=df2]
a = mask.values

这returns一个数组。

x = a[~np.isnan(a)].astype(int)
>>x
array([100])

您可以使用 melt,然后筛选出不同的值:

diffs = df.ne(df2).reset_index().melt(id_vars=['index'])
>>> diffs[diffs['value'].eq(True)].iloc[:, :-1].reset_index(drop=True)
   index variable
0      1        b