如何基于特定值标记DataFrame列中的降雨事件
问题描述
现有一个包含多列的DataFrame,重点处理Rain_Stream['rain_event']列,原始数据示例如下(实际数据更长):
Rain_Stream['rain_event'] = [nan, nan, nan, nan, nan, nan, nan, 1, nan, nan, nan, nan, nan, nan, nan, nan, 2, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, 1, nan, nan, nan, nan, nan, nan, 2, nan, nan, nan, nan, nan, nan, nan, 1, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, 2, nan, nan, nan, nan, nan, 1, nan, nan, nan, nan, nan, nan, 2, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan]
其中1标记降雨事件的开始,2标记降雨事件的结束。期望处理后,该列变为:
Rain_Stream['rain_event'] = [nan, nan, nan, nan, nan, nan, nan, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, 2, 2, 2, 2, 2, 2, 2, 2, nan, nan, nan, nan, nan, nan, nan, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, nan, nan, nan, nan, nan, 4, 4, 4, 4, 4, 4, 4, 4, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan]
要求:每个降雨事件按出现顺序用对应序号标记,从开始的1到结束的2之间的所有值都替换为该事件的序号(原1和2也需替换),事件之间保留nan或0均可。
已尝试掩码、向前填充(ffill)等方法但未成功,尝试的代码如下:
# 尝试1 mask = Rain_Stream['begin_rain_checked'] == 1 Rain_Stream['rain_event'] = mask.cumsum() mask = Rain_Stream['end_rain_checked'] == 2 Rain_Stream['rain_event'] = mask.nan # 尝试2 Rain_Stream['rain_event'] = Rain_Stream['rain_event'].ffill() Rain_Stream['rain_event'] = Rain_Stream['rain_event'].mask(Rain_Stream['rain_event'].duplicated()) Rain_Stream['rain_event'] = Rain_Stream['rain_event'].ffill()
解决方案
可以通过以下步骤实现需求:
- 标记降雨事件的起始点:统计所有1出现的次数,生成事件序号的基础
- 识别事件区间:判断每行是否处于某个降雨事件的区间内(起始后、结束前)
- 填充事件序号:将事件区间内的行统一赋值为对应事件的序号
- 处理结束点:确保结束点2也被替换为对应事件的序号
具体代码实现:
import pandas as pd import numpy as np # 复制原列避免修改原始数据,若需直接覆盖原列,替换为'rain_event'即可 Rain_Stream['rain_event_processed'] = Rain_Stream['rain_event'].copy() # 生成每个事件的序号:每遇到1就递增1 event_num = Rain_Stream['rain_event'].eq(1).cumsum() # 标记哪些行处于事件区间内(起始累计数≠结束累计数) in_event = Rain_Stream['rain_event'].eq(1).cumsum() != Rain_Stream['rain_event'].eq(2).cumsum() # 给事件区间内的行填充对应序号,非区间行保留nan Rain_Stream['rain_event_processed'] = np.where(in_event, event_num, np.nan) # 处理结束点2,替换为对应事件序号 end_positions = Rain_Stream['rain_event'] == 2 Rain_Stream.loc[end_positions, 'rain_event_processed'] = event_num[end_positions]
代码说明
event_num:通过eq(1).cumsum()统计起始点1的出现次数,得到每个事件的唯一序号in_event:对比起始点和结束点的累计次数,精准锁定每个降雨事件的区间范围np.where:快速实现区间内赋值、非区间保留nan的逻辑- 单独处理结束点,确保2被正确替换为对应事件序号,避免遗漏
内容的提问来源于stack exchange,提问作者Camilla T
相关产品推荐
相关产品推荐

