Pandas时间序列分组:产品首尾0删除与中间双0替换的实现问题
解决方案
我们可以通过pandas的groupby结合自定义处理函数来实现需求,分两步处理每个产品的时间序列数据:
步骤1:准备示例数据
先构造符合需求的测试数据:
import pandas as pd import numpy as np # 构造示例数据 data = { 'Date': [1,2,3,4,5,6,1,2,3,4,5,6], 'Id': ['a','a','a','a','a','a','b','b','b','b','b','b'], 'Units': [0,5,0,0,1,3,4,2,0,4,0,0] } df = pd.DataFrame(data)
步骤2:定义分组处理函数
编写一个函数,对每个产品的子数据集依次执行删除首尾0值行和替换连续两个0为np.nan的操作:
def process_product_data(group): # 1. 删除首尾位置的0值行 # 找到第一个非0值的索引 first_valid_idx = (group['Units'] != 0).idxmax() # 找到最后一个非0值的索引(反向查找) last_valid_idx = (group['Units'] != 0).iloc[::-1].idxmax() # 截取首尾非0之间的有效数据 trimmed_data = group.loc[first_valid_idx:last_valid_idx].copy() # 2. 将中间连续出现的两个0替换为np.nan # 标记出连续0的位置:当前值为0,且前一个或后一个值也是0 consecutive_zero_mask = (trimmed_data['Units'] == 0) & ( (trimmed_data['Units'].shift(1) == 0) | (trimmed_data['Units'].shift(-1) == 0) ) # 替换对应位置为np.nan trimmed_data.loc[consecutive_zero_mask, 'Units'] = np.nan return trimmed_data
步骤3:执行分组处理
用groupby按产品ID分组,应用上面的处理函数:
final_result = df.groupby('Id', group_keys=False).apply(process_product_data)
结果验证
处理后的结果与示例完全匹配:
- 产品a:保留Date2-6的行,Units列变为
5, np.nan, np.nan, 1, 3 - 产品b:保留Date1-4的行,Units列保持
4, 2, 0, 4
关键逻辑说明
- 首尾0值删除:通过
idxmax找到第一个和最后一个非0值的索引,直接截取中间区间,避免循环遍历行。 - 连续0替换:利用
shift()函数判断当前0值的前后是否也是0,精准标记连续出现的0,批量替换为np.nan,效率远高于逐行判断。
内容的提问来源于stack exchange,提问作者Fernando Quintino
相关产品推荐
相关产品推荐

