如何从Pandas DataFrame首个非NaN条目提取客户首次付款日期
解决思路
- 第一步:先做数据结构转换,把12列的宽表月份数据转为长格式,让每一条记录对应「客户ID-年份-月份-付款金额」的结构,方便后续筛选排序
- 第二步:过滤掉付款金额为空的记录,仅保留实际有付款的条目
- 第三步:建立月份名称到数字的映射,避免按英文名称字母序排序出错,再按客户ID分组,取每个客户分组内年份最小、同年份内月份数字最小的记录
- 第四步:补全所有原始客户ID,无有效付款记录的标记为「-」,最后按要求格式化日期输出
可运行示例代码
import pandas as pd # 此处为模拟的和你场景一致的MultiIndex数据,实际使用时替换成你自己的df即可 ids = [1001,1001,1002,1003,1003] years = [2021,2022,2022,2021,2022] index = pd.MultiIndex.from_tuples(list(zip(ids,years)), names=['客户ID','付款年份']) cols = ['January__c','February__c','March__c','April__c','May__c','June__c','July__c','August__c','September__c','October__c','November__c','December__c'] data = [ [None, None, 300, None, None, None, None, None, None, None, None, None], [100, None, None, None, None, None, None, None, None, None, None, None], [None, None, None, None, None, None, None, None, None, None, None, None], [None, None, None, None, 500, None, None, None, None, None, None, None], [None, 200, None, None, None, None, None, None, None, None, None, None] ] df = pd.DataFrame(data, index=index, columns=cols) # 建立月份和数字的双向映射,用于排序和格式化输出 month_to_num = { 'January':1, 'February':2, 'March':3, 'April':4, 'May':5, 'June':6, 'July':7, 'August':8, 'September':9, 'October':10, 'November':11, 'December':12 } # 1. 处理列名,转为长表结构 df_long = df.rename(columns=lambda x: x.replace('__c','')).stack(dropna=False).reset_index() df_long.columns = ['客户ID','付款年份','月份','付款金额'] # 2. 过滤有付款的记录,添加排序用的月份数字列 df_valid_pay = df_long.dropna(subset=['付款金额']).copy() df_valid_pay['month_order'] = df_valid_pay['月份'].map(month_to_num) # 3. 按年份、月份排序后取每个客户的第一条记录,即为首次付款 first_pay = df_valid_pay.sort_values(['付款年份','month_order']).groupby('客户ID').first().reset_index() first_pay['首次付款日期'] = first_pay['月份'] + ' ' + first_pay['付款年份'].astype(str) # 4. 补全所有客户,无付款记录标记为- all_customer_ids = df.index.get_level_values('客户ID').unique() result = pd.DataFrame({'客户ID':all_customer_ids}).merge( first_pay[['客户ID','首次付款日期']], on='客户ID', how='left' ).fillna({'首次付款日期':'-'})
输出说明
最终得到的result即为符合要求的统计结果,以上示例的输出效果如下:
| 客户ID | 首次付款日期 |
|---|---|
| 1001 | March 2021 |
| 1002 | - |
| 1003 | May 2021 |
内容的提问来源于stack exchange,提问作者sonnen_flo
相关产品推荐
相关产品推荐

