我试图强调两个数据帧之间到底发生了什么变化。
假设我有两个Python Pandas数据帧:
"StudentRoster Jan-1":
id Name score isEnrolled Comment
111 Jack 2.17 True He was late to class
112 Nick 1.11 False Graduated
113 Zoe 4.12 True
"StudentRoster Jan-2":
id Name score isEnrolled Comment
111 Jack 2.17 True He was late to class
112 Nick 1.21 False Graduated
113 Zoe 4.12 False On vacation
我的目标是输出一个HTML表,该表:
HTML表识别已经改变的行(可以是int、float、布尔、具有相同、旧和新值的string)
"StudentRoster Difference Jan-1 - Jan-2":id Name score isEnrolled Comment 112尼克是1.11|现在是1.21假毕业113佐伊4.12是真|现在假是"“|现在在度假”“
我想我可以逐行和逐列进行比较,但是有没有更简单的方法呢?
发布于 2013-06-14 03:39:45
第一部分类似于Constantine,您可以获得哪些行为空的布尔值*
In [21]: ne = (df1 != df2).any(1)
In [22]: ne
Out[22]:
0 False
1 True
2 True
dtype: bool
然后,我们可以看到哪些条目发生了更改:
In [23]: ne_stacked = (df1 != df2).stack()
In [24]: changed = ne_stacked[ne_stacked]
In [25]: changed.index.names = ['id', 'col']
In [26]: changed
Out[26]:
id col
1 score True
2 isEnrolled True
Comment True
dtype: bool
在这里,第一个条目是索引,第二个条目是已更改的列。
In [27]: difference_locations = np.where(df1 != df2)
In [28]: changed_from = df1.values[difference_locations]
In [29]: changed_to = df2.values[difference_locations]
In [30]: pd.DataFrame({'from': changed_from, 'to': changed_to}, index=changed.index)
Out[30]:
from to
id col
1 score 1.11 1.21
2 isEnrolled True False
Comment None On vacation
*注意:重要的是df1
和df2
在这里共享相同的索引。为了克服这种模糊性,您可以确保只使用df1.index & df2.index
查看共享标签,但我认为这将作为练习。
发布于 2017-11-04 22:58:06
突出显示两个DataFrames之间的差异
可以使用DataFrame style属性突出显示存在差异的单元格的背景色。
使用原始问题中的示例数据的
第一步是使用concat
函数水平连接DataFrames,并使用keys
参数区分每个帧:
df_all = pd.concat([df.set_index('id'), df2.set_index('id')],
axis='columns', keys=['First', 'Second'])
df_all
交换列级别并将相同的列名放在彼此的旁边可能更容易:
df_final = df_all.swaplevel(axis='columns')[df.columns[1:]]
df_final
现在,更容易发现帧之间的差异。但是,我们可以更进一步,使用style
属性来突出显示不同的单元格。我们定义了一个自定义函数来做这件事,你可以在this part of the documentation中看到。
def highlight_diff(data, color='yellow'):
attr = 'background-color: {}'.format(color)
other = data.xs('First', axis='columns', level=-1)
return pd.DataFrame(np.where(data.ne(other, level=0), attr, ''),
index=data.index, columns=data.columns)
df_final.style.apply(highlight_diff, axis=None)
这将突出显示两个都缺少值的单元格。您可以填充它们,也可以提供额外的逻辑,这样它们就不会突出显示。
发布于 2016-07-17 21:12:43
这个答案只是简单地扩展了@Andy Hayden的答案,使其在数值字段为nan
时具有弹性,并将其包装到一个函数中。
import pandas as pd
import numpy as np
def diff_pd(df1, df2):
"""Identify differences between two pandas DataFrames"""
assert (df1.columns == df2.columns).all(), \
"DataFrame column names are different"
if any(df1.dtypes != df2.dtypes):
"Data Types are different, trying to convert"
df2 = df2.astype(df1.dtypes)
if df1.equals(df2):
return None
else:
# need to account for np.nan != np.nan returning True
diff_mask = (df1 != df2) & ~(df1.isnull() & df2.isnull())
ne_stacked = diff_mask.stack()
changed = ne_stacked[ne_stacked]
changed.index.names = ['id', 'col']
difference_locations = np.where(diff_mask)
changed_from = df1.values[difference_locations]
changed_to = df2.values[difference_locations]
return pd.DataFrame({'from': changed_from, 'to': changed_to},
index=changed.index)
因此,对于您的数据(稍微编辑一下,在score列中有一个NaN ):
import sys
if sys.version_info[0] < 3:
from StringIO import StringIO
else:
from io import StringIO
DF1 = StringIO("""id Name score isEnrolled Comment
111 Jack 2.17 True "He was late to class"
112 Nick 1.11 False "Graduated"
113 Zoe NaN True " "
""")
DF2 = StringIO("""id Name score isEnrolled Comment
111 Jack 2.17 True "He was late to class"
112 Nick 1.21 False "Graduated"
113 Zoe NaN False "On vacation" """)
df1 = pd.read_table(DF1, sep='\s+', index_col='id')
df2 = pd.read_table(DF2, sep='\s+', index_col='id')
diff_pd(df1, df2)
输出:
from to
id col
112 score 1.11 1.21
113 isEnrolled True False
Comment On vacation
https://stackoverflow.com/questions/17095101
复制相似问题