如何基于Pandas DataFrame某列值创建倒计数新列
问题描述
我需要在Pandas DataFrame中基于is_longest_activation列创建新列is_in_longest_activation,规则如下:
- 当
is_longest_activation列出现非零值N时,从该行开始向上倒计数至0,覆盖N行(包含当前行) - 若计数范围出现重叠(前一个计数还未到0时又出现新的非零值),则以新的非零值为起点重新计数
示例数据
| quarter_hour | is_longest_activation | is_in_longest_activation |
|---|---|---|
| 1 | 0 | 0 |
| 2 | 0 | 0 |
| 3 | 0 | 1 |
| 4 | 2 | 2 |
| 5 | 0 | 5 |
| 6 | 0 | 6 |
| 7 | 0 | 7 |
| 8 | 0 | 8 |
| 9 | 0 | 9 |
| 10 | 10 | 10 |
| 11 | 0 | 0 |
当前尝试的代码
UpEnergy["is_longest_activation"] = UpEnergy["consecutive_activations_count"].where( UpEnergy["consecutive_activations_count"] == UpEnergy["consecutive_activations_count_daily_max"], 0 ) counter = UpEnergy["is_longest_activation"].where(UpEnergy["is_longest_activation"].ne(0)).bfill().fillna(0, downcast='infer') UpEnergy["is_in_longest_activation"] = counter.sub( UpEnergy.groupby(counter).cumcount(ascending=False) ).clip(lower=0)
解决方案
现有代码的bfill()逻辑无法处理计数重叠的情况,下面提供两种可行实现:
方法1:反向遍历(直观易理解)
通过从DataFrame末尾向前遍历,天然优先处理靠后的非零值,解决重叠覆盖问题:
# 初始化目标列 UpEnergy["is_in_longest_activation"] = 0 current_count = 0 # 从最后一行向前遍历 for i in reversed(range(len(UpEnergy))): # 遇到非零值时重置计数 if UpEnergy.loc[i, "is_longest_activation"] != 0: current_count = UpEnergy.loc[i, "is_longest_activation"] # 赋值当前计数并递减 UpEnergy.loc[i, "is_in_longest_activation"] = current_count if current_count > 0: current_count -= 1
方法2:向量化优化(适合大数据集)
通过计算非零值的覆盖区间,去重后生成计数序列,效率更高:
# 提取所有非零值的位置和对应数值 non_zero_records = UpEnergy[UpEnergy["is_longest_activation"] != 0].reset_index() non_zero_records["start_idx"] = non_zero_records["index"] - non_zero_records["is_longest_activation"] + 1 non_zero_records["end_idx"] = non_zero_records["index"] # 从后往前排序,保留每个位置最新的覆盖区间(解决重叠) non_zero_records = non_zero_records.sort_values("index", ascending=False).drop_duplicates(subset=pd.RangeIndex(len(UpEnergy)), keep="first") # 生成目标列结果 result = pd.Series(0, index=UpEnergy.index) for _, row in non_zero_records.iterrows(): start_pos = max(0, row["start_idx"]) end_pos = row["end_idx"] # 生成从N到0的倒计数序列 result.loc[start_pos:end_pos] = range(row["is_longest_activation"], -1, -1) UpEnergy["is_in_longest_activation"] = result
内容的提问来源于stack exchange,提问作者arj
相关产品推荐
相关产品推荐

