Pandas根据值升降提取DataFrame首个充放电周期行数据
解决方案
核心逻辑是先标记每个数据点的充放电趋势,平段自动归属到相邻的同周期段,再通过连续段分组直接定位目标周期,完全不受初始数据状态影响,同时兼容重复时间索引、充放电中间夹带平台段的场景。
步骤说明
- 计算SoC列逐点差分,标记三类趋势:差值为正属于充电上升、差值为负属于放电下降、差值为0属于平台暂留
- 对趋势做双向填充:平台段优先继承前序趋势,开头无参考的初始平台段继承后续第一个有效趋势
- 对连续相同趋势的段做分组,每个分组对应一个完整的充/放电子段
- 筛选第一个充电分组得到首个充电周期,再筛选充电段之后的第一个放电分组得到首个放电周期
实现代码
import pandas as pd # 标记SoC变化趋势:1=充电,-1=放电,0=平台 soc_diff = df["SoC"].diff() trend = pd.Series(0, index=df.index, dtype=int) trend[soc_diff > 0] = 1 trend[soc_diff < 0] = -1 # 填充趋势:平台段继承前序趋势,初始开头平台继承后续第一个有效趋势 trend = trend.ffill().bfill() # 为连续相同趋势的段分配唯一分组ID segment_id = (trend != trend.shift()).cumsum() # 遍历整理所有连续段的位置信息 segments = [] for sid, group in df.groupby(segment_id): seg_trend = trend.loc[group.index[0]] segments.append({ "trend": seg_trend, "start_iloc": df.index.get_loc(group.index[0]), "end_iloc": df.index.get_loc(group.index[-1]) }) # 提取首个充电周期 first_charge = next(seg for seg in segments if seg["trend"] == 1) df_charging = df.iloc[first_charge["start_iloc"] : first_charge["end_iloc"] + 1] # 提取首个充电周期之后的第一个放电周期 first_discharge = next(seg for seg in segments if seg["trend"] == -1 and seg["start_iloc"] > first_charge["start_iloc"]) df_discharging = df.iloc[first_discharge["start_iloc"] : first_discharge["end_iloc"] + 1]
边界说明
- 代码使用整数位置
iloc做切片,即使存在重复时间索引也不会出现切片错误 - 如果数据集全程没有充电/放电趋势,上述代码会触发
StopIteration异常,可根据业务需求增加前置判断做异常处理 - 充放电过程中任意长度的恒定值平台段都会被自动归属到对应周期,不需要额外处理
内容的提问来源于stack exchange,提问作者OAP
相关产品推荐
相关产品推荐

