如何在Pandas DataFrame列中标记非空非0值序列的起止位置
给分组数据中的非0连续序列标记起止位置
给定按Cycle分组的数据集,需要为每个Cycle内非空且非0的连续数值序列的起始位置标记A,结束位置标记B,其余位置用-填充。
示例数据集
import pandas as pd data = {'Cycle': [1, 1, 1, 1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3], 'Value': [0,19,18,14,65,0,0,0,0,0,0,1,18,12,65,0,0,0,0,0,0,19,18,14,65,54,32,0,0,0]} df = pd.DataFrame(data)
期望输出
新增POI列,非起止位置用-填充:
import pandas as pd data = {'Cycle': [1, 1, 1, 1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3], 'Value': [0,19,18,14,65,0,0,0,0,0,0,1,18,12,65,0,0,0,0,0,0,19,18,14,65,54,32,0,0,0], 'POI': ['-','A','-','-','B','-','-','-','-','-','-','A','-','-','B','-','-','-','-','-','-','A','-','-','-','-','B','-','-','-']} df = pd.DataFrame(data)
你之前用最大值、最小值标记的思路不符合需求——我们要的是连续非0段的首尾,不是最值位置,所以会出错。
解决方案代码
import pandas as pd import numpy as np # 初始化数据集 data = {'Cycle': [1, 1, 1, 1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3], 'Value': [0,19,18,14,65,0,0,0,0,0,0,1,18,12,65,0,0,0,0,0,0,19,18,14,65,54,32,0,0,0]} df = pd.DataFrame(data) # 第一步:标记哪些是有效非0值(排除0和NaN) df['is_valid'] = df['Value'].ne(0) & df['Value'].notna() # 第二步:按Cycle分组,标记每个组内的起止位置 def mark_poi(group): # 起始位:当前是有效值,且前一个不是(或是组的第一个元素) starts = group['is_valid'] & (~group['is_valid'].shift(1, fill_value=False)) # 结束位:当前是有效值,且后一个不是(或是组的最后一个元素) ends = group['is_valid'] & (~group['is_valid'].shift(-1, fill_value=False)) # 给起止位赋值A/B,其余填'-' group['POI'] = np.where(starts, 'A', np.where(ends, 'B', '-')) return group # 应用分组函数 df = df.groupby('Cycle').apply(mark_poi) # 删掉辅助列(可选) df = df.drop('is_valid', axis=1) # 查看结果 print(df)
代码说明
df['Value'].ne(0) & df['Value'].notna():筛选出所有非0、非空的有效数据点shift(1, fill_value=False):把有效标记列向下挪一行,用False补位,对比当前行和前一行的状态,判断是不是序列开头shift(-1, fill_value=False):把有效标记列向上挪一行,用来判断是不是序列结尾- 嵌套
np.where先处理起始标记A,再处理结束标记B,剩下的全填-
内容的提问来源于stack exchange,提问作者SeanK22
相关产品推荐
相关产品推荐

