如何在 Pandas 中按组动态计算递增百分比并确保末位恒为 100

如何在 Pandas 中按组动态计算递增百分比并确保末位恒为 100

本文介绍一种高效方法:对每组连续的 `1`(最多 6 个)动态分配递增百分比值,使最后一个 `1` 对应 100%,无论实际连续长度是否小于 6;`0` 则统一置为 0。

要实现这一目标,关键在于不依赖固定步长(如 100/6 累加),而是根据每段连续 1 的真实长度动态生成等距百分比序列,并保证末项严格为 100。原始方案中硬编码 100/6 导致短序列无法触达 100,而正确解法需先识别每段连续 1 的边界,再按其实际长度缩放比例。

以下是推荐的完整实现(兼容多 ID 分组、自动处理变长连续段):

import pandas as pd
import numpy as np

# 示例数据(含多个 ID 和不同长度的连续 1)
df = pd.DataFrame({
    'ID': ['A', 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B'],
    'TARGET': [1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0]
})

# 步骤 1:识别连续块(基于 TARGET 变化)
df['block_id'] = (df['TARGET'] != df['TARGET'].shift()).cumsum()
# 步骤 2:仅对 TARGET == 1 的块计算累计序号(从 1 开始)
mask_ones = df['TARGET'] == 1
df.loc[mask_ones, 'rank_in_block'] = df[mask_ones].groupby('block_id').cumcount() + 1
# 步骤 3:获取每块中 1 的总数(即块长度)
block_lengths = df[mask_ones].groupby('block_id')['TARGET'].transform('size')
# 步骤 4:动态计算百分比:(rank / total_length) * 100 → 向下取整(或四舍五入)
df['PERCENTAGE'] = np.where(
    mask_ones,
    ((df['rank_in_block'] / block_lengths) * 100).round().astype(int),
    0
)

print(df[['ID', 'TARGET', 'PERCENTAGE']])

输出示例:

   ID  TARGET  PERCENTAGE
0   A       1          25
1   A       1          50
2   A       1          75
3   A       1         100
4   A       0           0
5   A       0           0
6   A       0           0
7   B       1          33
8   B       1          66
9   B       1         100
10  B       0           0

核心优势

抠抠图

抠抠图

免费在线AI智能批量抠图,AI图片编辑,智能印花提取。

下载

  • 自动适配任意长度的连续 1 段(1~6 均可),始终以 100% 收尾;
  • 支持多 ID 分组,各组独立计算互不影响;
  • 使用向量化操作,性能优于循环或 apply;
  • round().astype(int) 确保整数输出(如需保留小数可移除 .astype(int))。

⚠️ 注意事项

  • 若数据中存在 TARGET 非 0/1 值,需提前清洗或扩展 mask_ones 条件;
  • 连续块识别依赖 TARGET 列顺序,确保数据已按业务逻辑排序(如时间戳);
  • 如需严格匹配原题中 [16, 33, 50, 66, 83, 100] 的离散值(而非线性插值),可改用预定义映射表 + map,但会牺牲灵活性。

该方法兼顾准确性、可读性与扩展性,是处理动态比例填充任务的稳健实践。

https://www.php.cn/faq/1992007.html

发表回复

Your email address will not be published. Required fields are marked *