看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
在办公自动化场景下,最常见的需求就是信息的整理,pandas 最擅长复杂数据逻辑的处理,能够让整理工作更加高效,同时不容易出错。今天的案例是将一个平铺的书单按品类进行整理,合并为一行。
如以下代码构造原数据:
from io import StringIO
import pandas as pd
data = '''
书单,作者,ISBN
资本论 1,袁某,23445-2342
资本论 2,袁某,23445-2342
资本论 3,袁某,23445-2342
大学语文 上,李四,a25245-32425
大学语文 下,李四,a25245-32425
数据结构,王某,x342w-ssa
'''
df = pd.read_csv(StringIO(data))
df
'''
书单 作者 ISBN
0 资本论 1 袁某 23445-2342
1 资本论 2 袁某 23445-2342
2 资本论 3 袁某 23445-2342
3 大学语文 上 李四 a25245-32425
4 大学语文 下 李四 a25245-32425
5 数据结构 王某 x342w-ssa
'''
该数据共有三列,在书单列如果一种书有多个分册,册名则在书名后用空格分开显示。
现在的需求为:
既然要按书名分组,同时册名要整理在备注中,那我们就要拆书名和册名,这个可以用字符访问器(.str.xx)来操作。
分组后可以用 agg() 来聚合不同的列。
接下来按书名进行分组,作者和 ISBN 编码同组内相同,随便显示其中一个即可,我们可以用 max。
接下来最复杂的就是备注列了,我们可以写一个备注处理的函数来专门处理。
备注列依赖我们将书单列拆分的册名(为了方便后期处理,我们拆分时可以直接叫备注)。这个处理的逻辑是:
理清了以上逻辑,接下来我们就开始编写代码。
先拆分书单列:
df.书单.str.split(' ', expand=True)
'''
0 1
0 资本论 1
1 资本论 2
2 资本论 3
3 大学语文 上
4 大学语文 下
5 数据结构 None
'''
给它起列列索引名,赋值为一个新的 DataFrame 备用:
df1 = df.书单.str.split(' ', expand=True)
df1 = df1.set_axis(['书名', '备注'], axis=1)
df1
'''
书名 备注
0 资本论 1
1 资本论 2
2 资本论 3
3 大学语文 上
4 大学语文 下
5 数据结构 None
'''
将这个拆分的数据合并到原数据中,方便下一步分组:
new_df = pd.concat([df, df1], axis=1)
new_df
'''
书单 作者 ISBN 书名 备注
0 资本论 1 袁某 23445-2342 资本论 1
1 资本论 2 袁某 23445-2342 资本论 2
2 资本论 3 袁某 23445-2342 资本论 3
3 大学语文 上 李四 a25245-32425 大学语文 上
4 大学语文 下 李四 a25245-32425 大学语文 下
5 数据结构 王某 x342w-ssa 数据结构 None
'''
接下来,编写我们提到的备注处理聚合函数(它的参数备注列分组后的一个 Series):
def mark(ser: pd.Series):
# 判断是否全为空值
if ser.isna().all():
return ''
# 判断是否全为数字
elif ser.str.isdecimal().all():
return f'{ser.min()}-{ser.max()}'
else:
return ser.sum()
分组,聚合并应用以上函数:
(
new_df.groupby('书名', as_index=False, sort=False)
.agg({'作者': 'max',
'ISBN': 'max',
'备注': mark
})
)
'''
书名 作者 ISBN 备注
0 资本论 袁某 23445-2342 1-3
1 大学语文 李四 a25245-32425 上下
2 数据结构 王某 x342w-ssa
'''
在分组时,我们取消了让分组名成为索引,取消了分组的重新排序,保持与原数据相同的顺序。
整理最终代码如下:
def mark(ser: pd.Series):
# 判断是否全为空值
if ser.isna().all():
return ''
# 判断是否全为数字
elif ser.str.isdecimal().all():
return f'{ser.min()}-{ser.max()}'
else:
return ser.sum()
(
df.assign(备注=df.书单.str.split(' ').str.get(1))
.assign(书单=df.书单.str.split(' ').str.get(0))
.rename({'书单': '书名'}, axis=1)
.groupby('书名', as_index=False, sort=False)
.agg({'作者': 'max',
'ISBN': 'max',
'备注': mark
})
)
这样我们就完成了需求。
(完)
更新时间:Aug. 18, 2024, 4 p.m. 标签:pandas python 整理 合并