看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gr99123(备注: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
    })
)
这样我们就完成了需求。
(完)
更新时间:2024-08-18 16:00:19 标签:pandas python 整理 合并