
本文介绍如何基于分组(如客户名称)识别某列中特定字符(如 'y')的首次出现,并将对应日期填充到新列中,其余位置设为 nan。核心思路是结合布尔索引、分组累积计数与条件筛选。
在数据分析中,常需定位某个关键事件(如首次下单、首次响应“Y”)的发生时间。本例中,目标是:对每个 CUS_NAME 分组,找出 'Y/N' 列中第一个 'Y' 所在行的 BAS_DT 值,并仅在该行填入该日期,其余行置为 NaN。
实现的关键在于三步逻辑组合:
- 构造基础条件:df['Y/N'].eq('Y') 生成布尔序列,标记所有 'Y' 出现位置;
- 分组内首次标识:cond.groupby(df['CUS_NAME']).cumsum().eq(1) 对每组内 'Y' 的累计次数做判断,仅当累计值为 1 时返回 True(即该 'Y' 是组内首个);
- 精准赋值:使用 df['BAS_DT'].where(cond & cond1) —— 仅当同时满足“是 Y”且“是组内首个 Y”时,才保留对应 BAS_DT,否则自动填充 NaN。
完整代码如下:
import pandas as pd
import numpy as np
df = pd.DataFrame({
'BAS_DT': ['2023-01-02', '2023-01-03', '2023-01-04', '2023-01-02', '2023-01-03'],
'CUS_NAME': ['A', 'A', 'A', 'B', 'B'],
'Y/N': ['Y', 'Y', 'Y', 'N', 'Y'],
'cum_count': [1, 2, 3, 1, 2]
})
# 核心三步逻辑
cond = df['Y/N'].eq('Y') # 步骤1:标记所有Y
cond1 = cond.groupby(df['CUS_NAME']).cumsum().eq(1) # 步骤2:标记每组首个Y
df['occur_date'] = df['BAS_DT'].where(cond & cond1) # 步骤3:条件赋值
print(df)✅ 输出结果完全匹配预期:
BAS_DT CUS_NAME Y/N cum_count occur_date 0 2023-01-02 A Y 1 2023-01-02 1 2023-01-03 A Y 2 NaN 2 2023-01-04 A Y 3 NaN 3 2023-01-02 B N 1 NaN 4 2023-01-03 B Y 2 2023-01-03
⚠️ 注意事项:
- 若某客户组内无 'Y'(如全为 'N'),则整组 occur_date 均为 NaN,符合业务逻辑;
- cumsum().eq(1) 比 idxmax() 更安全:后者在无 'Y' 时会报错,而前者天然兼容空情况;
- 时间列 BAS_DT 应为字符串或 datetime 类型;若为 datetime,结果仍保持原类型,无需额外转换;
- 如需扩展为“首次满足多条件”(如 'Y' 且 cum_count > 1),只需将 cond 替换为复合布尔表达式即可。
该方法简洁高效,不依赖循环或 apply,充分利用 Pandas 向量化操作,适用于百万级数据场景。










