0%

「pandas笔记」对比两个dataframe

今天遇到问题主要是对比两个不同时间、同个数据库导出的csv文件。因为这次主要用pandas去处理csv文件,那么问题主要就是怎么实现通过对比两个dataframe获取新的数据以及更新了的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import chardet

import pandas as pd


def get_file_encoding(file_path):
f = open(file_path, 'rb')
file_encoding = chardet.detect(f.read())['encoding']
f.close()
return file_encoding


def get_df(file_path, id_name, field_list):
# 获取file 的编码格式
file_encoding = get_file_encoding(file_path)

# 初始化df,包括把id_name替换成索引,以及替换nan为空,不然会有异常,最后再来一个过滤显示的字段
df = pd.read_csv(file_path, encoding=file_encoding).set_index([id_name])[field_list].fillna('').sort_index()
return df


def contrast_df(new_path, old_path, id_name, field_list, save_file_path='./auto_create/'):
# 把id的列移除list
field_list.pop(field_list.index(id_name))

# 获取file_name
file_name = new_path.split('/')[-1]

# 获取新旧的df
new_df = get_df(new_path, id_name, field_list)
old_df = get_df(old_path, id_name, field_list)

# 比较数据是否有更新前,须要先看是否有新增的数据,不然size不同会报错
old_index = old_df.index.values
add_df = new_df[~new_df.index.isin(old_index)]
if not add_df.empty:
print('有{}条数据新插入了'.format(len(add_df)))
# 把新增的数据从new_df 中删除
add_index = add_df.index.values
new_df = new_df[~new_df.index.isin(add_index)]

# 新建csv文件
add_df.to_csv(save_file_path + 'add_' + file_name)
else:
print('没有数据新插入')

ne_stacked = (new_df != old_df).stack()
changed = ne_stacked[ne_stacked]
changed.index.names = ['ID_P', 'col']
changed_index = set([seri[0] for seri in changed.index])
update_df = new_df[new_df.index.isin(changed_index)]

if not update_df.empty:
print('有{}条数据更新'.format(len(update_df)))
# 新建csv文件
update_df.to_csv(save_file_path + 'update_' + file_name)
else:
print('没有数据更新')

return add_df, update_df

基本思路是:

  1. 先把新增的数据移除,并保存成新的csv文件;
  2. 两个新旧的dataframe进行比较;
  3. 通过行列转化的形式获取changed,并从中获得发生改变的数据的index
  4. 将更新的数据保存成新的csv文件。

最后补充一下:

  1. 上边的changed能做得更多,它还能识别数据哪个字段发生了改变;
  2. 中间还试了别的方法去完成这个功能,但是没有跑通,不过思路还是挺有趣的,代码丢上来mark一下
1
2
3
4
df_3 = pd.concat([new_df, old_df])
df_gpby = df_3.groupby(list(df_3.columns))
idx = [x[0] for x in df_gpby.groups.values() if len(x) == 1]
df_3.iloc[idx]