看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
对两个表进行比对,是日常中经常要做的事情,但是在比对中往往会有一定的数据处理逻辑,在使用 Excel处 理时这就变得非常棘手。这时 pandas 能够帮助我们进行复杂的合并处理,今天我们利用这样的一个案例来感受一下。
我们先将两个表的数据读取到 DataFrame:
from io import StringIO
import pandas as pd
import numpy as np
data1 = '''
SSO,姓名,夜班补贴,住房补贴,全勤奖,高温津贴,岗位津贴,交通补贴
123445,张三,195,150,100,683,5344,438
112253,李四,534,150,100,584,968,695
226536,王五,555,150,83,84934,654,954
335221,陈六,694,150,100,6950,596,569
246244,高高,0,150,100,0,0,0
'''
data2 = '''
SSO,姓名,夜班补贴,住房补贴,全勤奖,高温津贴,岗位津贴,交通补贴
112253,李四,195,150,100,0,0,0
226536,王五,70,150,100,0,0,0
246244,高高,0,150,100,0,0,0
905241,小明,0,150,100,0,0,0
996365,小红,0,150,100,0,0,0
'''
df1 = pd.read_csv(StringIO(data1))
df2 = pd.read_csv(StringIO(data2))
将以上两个表合并为一个表,以 SSO 列的值为基准:
我们的思路是先将两个表之间合并,合并后我们按照一张表去处理。在新的表里面我们按照 SSO 去做分组,分组后会得到每个子 DataFrame。
我们利用函数去处理每一个人的子 DataFrame,使其只保留一条按逻辑处理后的数据。
先将两张表做简单的合并,并利用索引进行标识:
# 将两个表合并,增加表标识
df = pd.concat([df1, df2], keys=['t1', 't2'])
df
'''
SSO 姓名 夜班补贴 住房补贴 全勤奖 高温津贴 岗位津贴 交通补贴
t1 0 123445 张三 195 150 100 683 5344 438
1 112253 李四 534 150 100 584 968 695
2 226536 王五 555 150 83 84934 654 954
3 335221 陈六 694 150 100 6950 596 569
4 246244 高高 0 150 100 0 0 0
t2 0 112253 李四 195 150 100 0 0 0
1 226536 王五 70 150 100 0 0 0
2 246244 高高 0 150 100 0 0 0
3 905241 小明 0 150 100 0 0 0
4 996365 小红 0 150 100 0 0 0
'''
接下来按 SSO 列进行分组, 分组后会得到多个以 SSO 的子 DataFrame,代表着相同的人。接下来我们按照逻辑要求编写一个函数来做数据处理:
def func(d: pd.DataFrame):
# 取消多层索引, 设置表名为索引,方便操作
d = d.reset_index().set_index('level_0')
# 把表名转为列表,方便后续判断
tab_names = d.index.to_list()
# 处理一只有一个表有的情况
if d.shape[0] == 1:
# 仅表1有
if 't1' in tab_names:
pass # 保留,直接返回
else:
# 对数据部分求负值
d.loc[:,'夜班补贴':] = d.loc[:,'夜班补贴':].apply(np.negative)
# 两个表都有
else:
# 如果两个值都相同
if d.loc[:,'姓名':].duplicated().any():
d = pd.DataFrame()
else:
# 将表名排序后求差,默认降序,t2 在前,因此求差要后边减前边
d.loc[:,'夜班补贴':] = (d.sort_index()
.loc[:,'夜班补贴':]
.diff(-1)
)
d = d.head(1) # 取求差后的第一条
return d
我们应用这个函数同时对数据做进一步的处理。
(
df.groupby('SSO', as_index=False)
.apply(func)
.reset_index(drop=True)
.drop('level_1', axis=1)
.astype(df.dtypes.replace({'float64': int}))
)
'''
SSO 姓名 夜班补贴 住房补贴 全勤奖 高温津贴 岗位津贴 交通补贴
0 112253 李四 339 0 0 584 968 695
1 123445 张三 195 150 100 683 5344 438
2 226536 王五 485 0 -17 84934 654 954
3 335221 陈六 694 150 100 6950 596 569
4 905241 小明 0 -150 -100 0 0 0
5 996365 小红 0 -150 -100 0 0 0
'''
在以上代码中我们删除了索引、删除了多余的列、将数字类型转换为整型。
这样我们就完成了需求。
(完)
更新时间:Aug. 18, 2024, 3:56 p.m. 标签:pandas python 合并