我有两个文件,两者之间有微小差异。我想输出不同的值,以便可以看到更改的内容。有很多要比较的列。
这是示例数据(示例中唯一的区别是第一行的状态):
数据1
ID PROGRAM_CODE Status
123 888 Active
123 777 Active
345 777 Inactive
345 999 Active
678 666 Inactive
901 777 Inactive
901 888 Active
数据2
ID PROGRAM_CODE Status
123 888 BLAH
123 777 Active
345 777 Inactive
345 999 Active
678 666 Inactive
901 777 Inactive
901 888 Active
所需输出:
ID Status_1 Status_2
123 Active Inactive
我当前的方法是创建列列表,合并两个数据框,然后在for循环中使用列列表进行比较。我相信我的代码会比较系列并输出整个系列(如果有任何区别的话)。我只想查看具有不同值的一行。此外,如果一个字段具有值,而另一字段中为空白,则此方法不起作用。
码:
import pandas as pd
df1 = pd.read_excel(r"P:\data_files\data1.xlsx")
df2 = pd.read_excel(r"P:\data_files\data2.xlsx")
# create list of columns
l1 = list(df1)
# dropping the join values from the list because I don't want to compare those
l1 = [e for e in l1 if e not in ('ID','PROGRAM_CODE')]
# merge dataframes
df3 = df1.merge(df2, how='outer', on=['ID','PROGRAM_CODE'], suffixes=['_1', '_2'])
for x in l1:
if df3[x+'_1'].any() != df3[x+'_2'].any():
print(df3[['ID', x+'_1',x+'_2']])
上面代码的输出:
即使只有第一行的数据框之间的值不同,也会显示"状态"列的所有值。
ID Status_1 Status_2
123 Active Blah
123 Active Active
345 Inactive Inactive
345 Active Active
678 Inactive Inactive
901 Inactive Inactive
901 Active Active
编辑17/12/12
下面来自Wen的示例似乎适用于一列,但是我需要比较ID和Program_Code相同的两个文件的每一行和每一列。
我尝试了以下循环:
for x in l1:
print(df3.groupby('STUDENT_CID').x.apply(list).apply(pd.Series).add_prefix(x+'_'))
但我收到以下错误:
AttributeError: 'DataFrameGroupBy' object has no attribute 'x'
我需要一种遍历每一列的方式(两个文件都包含相同的列)。
附加示例:
数据文件1
ID PROGRAM_CODE I_CODE INSTITUTION TERM TYPE STATUS Hire_Date
123 888 111 ZBD Fall FINAL Active 1/1/2017 0:00
123 777 111 ZBD Fall FINAL Active 1/1/2017 0:00
345 777 125 GUB Fall FINAL Inactive 2/3/2017 0:00
345 999 125 GUB Fall FINAL Inactive 2/3/2017 0:00
678 999 111 ZBD Fall FINAL Active 1/1/2017 0:00
678 888 111 ZBD Fall FINAL Active 1/1/2017 0:00
901 888 654 YUI Fall FINAL Inactive 5/1/2017 0:00
901 777 654 YUI Fall FINAL Inactive 5/1/2017 0:00
数据文件2
ID PROGRAM_CODE I_CODE INSTITUTION TERM TYPE STATUS Hire_Date
123 888 111 ZBD Fall FINAL Inactive 1/1/2017 0:00
123 777 111 ZBD Fall FINAL Active 1/1/2017 0:00
345 777 111 ZBD Fall FINAL Inactive 2/3/2017 0:00
345 999 111 ZBD Fall FINAL Inactive 2/3/2017 0:00
678 999 111 ZBD Fall FINAL Active 1/1/2017 0:00
678 888 111 ZBD Fall FINAL Active 1/1/2017 0:00
901 888 654 YUI Fall FINAL Inactive 5/1/2017 0:00
901 777 654 YUI Fall FINAL Inactive 5/1/2017 0:00
期望的输出
ID STATUS_1 STATUS_2
123 Active Inactive
ID INSTITUTION_1 INSTITUTION_2
345 125 111
我们使用pd.concat + drop_duplicates
df1=pd.concat([df1,df2]).drop_duplicates(keep=False)
df1
Out[1085]:
ID PROGRAM_CODE Status
0 123 888 Active
0 123 888 BLAH
然后我们groupby创建您需要的表
df1.groupby('ID').Status.apply(list).apply(pd.Series).add_prefix('Status_')
Out[1094]:
Status_0 Status_1
ID
123 Active BLAH
更新
df=pd.concat([df1,df2]).drop_duplicates(keep=False)
dd=df.groupby('ID').agg(lambda x:sorted(set(x), key=list(x).index)).stack()
dd[dd.apply(len)>1]
Out[1194]:
ID
123 STATUS [Active, Inactive]
345 PROGRAM_CODE [777, 999]
I_CODE [125, 111]
INSTITUTION [GUB, ZBD]
我如何将groupby应用于大量的列? 仅以状态为例,我有一百多个列可供比较。
它基本上类似于示例,但具有更多列,例如修改日期,citizenship_code等。其中包含日期,ID号,各种长度的字符串等。
@Dread是否需要找到所有不同的地方? 抱歉,您可以编一个小样本,然后向我展示预期的结果吗?
我添加了另一个示例,其中状态和I_Code在第二个文件中更改。 感谢您的帮助,如果我不清楚,则对不起。
我确定有更好的方法来执行此操作,但是您是否尝试过合并数据框(如您现有的那样),创建一个比较Status_1和Status_2的新列,然后删除匹配项为True的任何行? 如果您之后删除了"它们是否匹配"列,我相信您会获得理想的输出。