Python 比较两个数据帧的差异
我有一个脚本更新了5-10列的数据,但有时开始csv将与结束csv相同,所以我不想写相同的csv文件,我希望它什么都不做 如何比较两个数据帧以检查它们是否相同Python 比较两个数据帧的差异,python,python-2.7,pandas,Python,Python 2.7,Pandas,我有一个脚本更新了5-10列的数据,但有时开始csv将与结束csv相同,所以我不想写相同的csv文件,我希望它什么都不做 如何比较两个数据帧以检查它们是否相同 csvdata = pandas.read_csv('csvfile.csv') csvdata_old = csvdata # ... do stuff with csvdata dataframe if csvdata_old != csvdata: csvdata.to_csv('csvfile.csv', index=
csvdata = pandas.read_csv('csvfile.csv')
csvdata_old = csvdata
# ... do stuff with csvdata dataframe
if csvdata_old != csvdata:
csvdata.to_csv('csvfile.csv', index=False)
有什么想法吗?您还需要小心创建数据帧的副本,否则csvdata_old将用csvdata更新(因为它指向同一对象): 要检查它们是否相等,您可以: 您可以使用以下内容将其包装到函数中:
try:
assert_frame_equal(csvdata, csvdata_old)
return True
except: # appeantly AssertionError doesn't catch all
return False
讨论了一种更好的方法…这比较了两个数据帧的值。注意,表之间的行/列数需要相同
comparison_array = table.values == expected_table.values
print (comparison_array)
>>>[[True, True, True]
[True, False, True]]
if False in comparison_array:
print ("Not the same")
#Return the position of the False values
np.where(comparison_array==False)
>>>(array([1]), array([1]))
然后可以使用此索引信息返回表之间不匹配的值。因为它是零索引的,所以它指的是第二个位置的第二个数组,这是正确的。不确定问题发布时是否存在这种情况,但熊猫现在有一个内置函数来测试两个数据帧之间的相等性:。使用:dfu 1.equals(dfu 2)返回True或False,详情如下
更准确的比较应该单独检查索引名,因为
DataFrame.equals
不测试索引名。所有其他属性(索引值(单/多索引)、值、列、数据类型)都由它正确检查
df1 = pd.DataFrame([[1, 'a'], [2, 'b'], [3, 'c']], columns=['num', 'name'])
df1 = df1.set_index('name')
df2 = pd.DataFrame([[1, 'a'], [2, 'b'], [3, 'c']], columns=['num', 'another_name'])
df2 = df2.set_index('another_name')
df1.equals(df2)
True
df1.index.names == df2.index.names
False
注意:使用
index.names
而不是index.name
使它也适用于多索引数据帧。不确定这是否有用,但我快速组合了这个python方法,只返回两个具有相同列和形状的数据帧之间的差异
def get_different_rows(source_df, new_df):
"""Returns just the rows from the new dataframe that differ from the source dataframe"""
merged_df = source_df.merge(new_df, indicator=True, how='outer')
changed_rows_df = merged_df[merged_df['_merge'] == 'right_only']
return changed_rows_df.drop('_merge', axis=1)
在我的例子中,我有一个奇怪的错误,即使索引、列名 值相同,
数据帧
不匹配。我一直追查到
数据类型,而且似乎熊猫
有时可以使用不同的数据类型,
导致这样的问题
例如:
df1 = pd.DataFrame({
'num': [1, 4, 3],
'name': ['a', 'b', 'c'],
})
df2 = pd.DataFrame({
'num': [1, 2, 3],
'name': ['a', 'b', 'd'],
})
param2=pd.DataFrame({'a':[1]})
param1=pd.DataFrame({'a':[1],'b':[2],'c':[2],'step':['alpha']})
如果您检查param1.dtypes
和param2.dtypes
,您会发现'a'是
为param1
键入object
,为param2
键入int64
。现在,如果你这样做了
某些操作使用param1
和param2
的组合,其他
数据帧的参数将偏离默认值
因此,在生成最终数据帧之后,即使
如果打印出来的是相同的,final\u df1.equals(final\u df2)
,则可能是
不相等,因为那些samll参数,如轴1,ObjectBlock
,
IntBlock
可能不同
解决这个问题并比较值的一个简单方法是使用
final\u df1==final\u df2
但是,这将进行逐个元素的比较,因此如果
正在使用它断言语句,例如在pytest
中
TL;博士
有效的方法是
all(final\u df1==final\u df2)
这将进行元素对元素的比较,同时忽略参数
比较起来很重要
TL;DR2
如果值和索引相同,但
final\u df1.equals(final\u df2)
显示False
,则可以使用final\u df1.\u data
和final\u df2.\u data
检查数据帧的其余元素。提取对称差异:
df_diff = pd.concat([df1,df2]).drop_duplicates(keep=False)
例如:
df1 = pd.DataFrame({
'num': [1, 4, 3],
'name': ['a', 'b', 'c'],
})
df2 = pd.DataFrame({
'num': [1, 2, 3],
'name': ['a', 'b', 'd'],
})
将产生:
注意:在pandas的下一个版本之前,为了避免关于将来如何设置sort参数的警告,只需添加sort=False
参数。详情如下:
df_diff = pd.concat([df1,df2], sort=False).drop_duplicates(keep=False)
不是熊猫方面的专家,但正常的平等性比较不应该起作用吗?我已经看过平等性,但我不确定如何使用该功能,我也无法在搜索中找到任何东西:(出于某种原因,我得到了一个异常:
exception:只能比较相同标签的DataFrame对象
,这就给出了答案,对吗?这意味着标签(行和列名/值)在Andy的包装中添加另一行:Exception:return False
@Hyflex是的,正如Tom指出的,只需删除AssertionError(在它仅停止AssertionError并引发其他事件之前)…好的,我修复了标签(我没有意识到我必须对csvdat_old的标签顺序进行重新排序,我尝试将其纳入我的实际数据中,但即使数据在输出时是相同的,它也会更新,是否有办法找到/查看到底是什么“不同”?如何在这些帧中获得不同的值?这里的主要好处是您可以确定np返回的索引位置。在哪里确定表不匹配的确切位置,并提醒用户该位置。不,这是不存在的,它同样有效。(更好,因为这是一个单行vs 5行显示,它在浮点上工作吗?我希望有一个精度参数。必须有比这更好的参数。仅仅一个false不是一个令人满意的答案不确定这是否是大多数人想要的。DataFrame.equals进行了非常深入的比较。例如..我有两个数据帧值是相等的。但是,DataFrames
也有一些参数称为Axis 1
、IntBlock
和ObjectBlock
。这些参数是在pd.\u data
下定义的。如果这两个对象之间的参数不同,则会导致False@NickpickDataFrame.eq
可能很适合f或者定位不相等的元素?有一个问题:索引。名称不进行比较。有关详细信息,请参阅我的答案:是否有人
df1 = pd.DataFrame({
'num': [1, 4, 3],
'name': ['a', 'b', 'c'],
})
df2 = pd.DataFrame({
'num': [1, 2, 3],
'name': ['a', 'b', 'd'],
})
df_diff = pd.concat([df1,df2], sort=False).drop_duplicates(keep=False)