看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gr99123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
量化回测或店铺日报中,常要定位“连续亏损”的最大区间——不仅想知道最长亏几天,还想把每一段的起点/终点/总亏损额都拆出来。阅读本文,你会把 query
(布尔过滤)与 cumsum
(累加)组合成链式表达式,无需循环,两步标出所有连续亏损段,直接导出 Excel 给老板交差。
原始数据如下:
import pandas as pd
from io import StringIO
raw = """日期,净利润
2024-06-01,-120
2024-06-02,-80
2024-06-03,50
2024-06-04,-200
2024-06-05,-90
2024-06-06,0
2024-06-07,-60
2024-06-08,100"""
df = pd.read_csv(StringIO(raw), parse_dates=['日期'])
df
# ...
需求如下:
正确结果示意:
起始日期 结束日期 天数 亏损额
0 2024-06-01 2024-06-02 2 -200
1 2024-06-04 2024-06-05 2 -290
2 2024-06-07 2024-06-07 1 -60
我们的思路如下:
query('净利润 < 0')
筛出亏损日,保留原索引;cumsum
差分,断裂处数值跳跃,可分组;groupby
聚合得到每段起始/结束日期、天数、求和;根据思路,我们的代码如下:
(
df
.query('净利润 < 0') # ① 只留亏损日
.assign(grp=lambda x: (x.index.to_series()
.diff()
.ne(1)
.cumsum())) # ② 断裂分组
.groupby('grp')
.agg(起始日期=('日期', 'min'),
结束日期=('日期', 'max'),
天数=('日期', 'count'),
亏损额=('净利润', 'sum'))
.reset_index(drop=True)
)
代码拆解:
query
一步过滤负数,比布尔切片更简洁,且支持字符串表达式。index.to_series().diff().ne(1).cumsum()
是经典“连续段分组”技巧:索引差 ≠1 说明断裂,累加后每段唯一 grp。groupby.agg
同时拿到起止、天数、求和,列名直接重命名,干净清爽。reset_index(drop=True)
只保留业务字段,导出 Excel 即可交差。(完)
更新时间:2025-09-07 17:10:13 标签:pandas python 连续 亏损