基于日期及分组列更新Pandas DataFrame的NEWVAL列问题
基于Pandas分组+日期条件更新列的解决方案
核心思路
- 保留日期列的
datetime64[ns]类型,直接通过.dt.year和.dt.month提取年月进行匹配,无需转换为字符串 - 按
Group1和Group2分组后,在每个组内应用日期匹配逻辑,更新NEWVAL列
步骤与代码示例
1. 准备示例数据
先构造包含分组列、日期列、值列的DataFrame,确保日期列是datetime64[ns]类型:
import pandas as pd import numpy as np data = { 'Group1': ['A', 'A', 'B', 'B', 'A', 'B'], 'Group2': ['X', 'X', 'Y', 'Y', 'Z', 'Z'], 'date1': pd.to_datetime(['2023-01-15', '2023-02-20', '2023-03-10', '2023-01-05', '2023-02-18', '2023-03-22']), 'date2': pd.to_datetime(['2023-03-01', '2023-01-10', '2023-02-15', '2023-03-05', '2023-01-25', '2023-02-10']), 'date3': pd.to_datetime(['2023-01-01', '2023-01-01', '2023-03-01', '2023-03-01', '2023-02-01', '2023-02-01']), 'Val1': [100, 200, 300, 400, 500, 600], 'NEWVAL': [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan] } df = pd.DataFrame(data)
2. 分组更新的两种实现方式
方式一:使用groupby.apply(直观易读,适合复杂逻辑)
定义组内更新函数,按分组应用后返回结果:
def update_newval(group): # 组内每行判断:date1或date2的年月与date3的年月匹配 match_mask = ( (group['date1'].dt.year == group['date3'].dt.year) & (group['date1'].dt.month == group['date3'].dt.month) ) | ( (group['date2'].dt.year == group['date3'].dt.year) & (group['date2'].dt.month == group['date3'].dt.month) ) # 满足条件的行,将Val1赋值给NEWVAL group.loc[match_mask, 'NEWVAL'] = group.loc[match_mask, 'Val1'] return group # 按Group1+Group2分组,应用更新逻辑 df = df.groupby(['Group1', 'Group2'], group_keys=False).apply(update_newval)
group_keys=False:避免分组键作为索引添加到结果,保持原DataFrame结构- 全程未修改原日期列的类型,
date1/date2/date3仍为datetime64[ns]
方式二:结合布尔索引与全局判断(高效,适合大数据集)
如果分组仅作为逻辑边界,无需额外组内规则,可直接计算全局匹配掩码后更新:
# 计算全局日期匹配掩码 date_match = ( (df['date1'].dt.year == df['date3'].dt.year) & (df['date1'].dt.month == df['date3'].dt.month) ) | ( (df['date2'].dt.year == df['date3'].dt.year) & (df['date2'].dt.month == df['date3'].dt.month) ) # 满足条件的行赋值Val1到NEWVAL df.loc[date_match, 'NEWVAL'] = df.loc[date_match, 'Val1']
3. 扩展:组内date3年月统一的场景
如果每个分组内的date3年月固定,可修改函数逻辑匹配组内统一目标年月:
def update_newval_group_date(group): # 获取组内date3的统一年月 target_year = group['date3'].dt.year.iloc[0] target_month = group['date3'].dt.month.iloc[0] # 判断date1或date2的年月是否与组内目标年月匹配 match_mask = ( (group['date1'].dt.year == target_year) & (group['date1'].dt.month == target_month) ) | ( (group['date2'].dt.year == target_year) & (group['date2'].dt.month == target_month) ) group.loc[match_mask, 'NEWVAL'] = group.loc[match_mask, 'Val1'] return group df = df.groupby(['Group1', 'Group2'], group_keys=False).apply(update_newval_group_date)
验证结果
执行后查看列类型,确认日期列仍为datetime64[ns]:
print(df.dtypes) # 输出示例: # Group1 object # Group2 object # date1 datetime64[ns] # date2 datetime64[ns] # date3 datetime64[ns] # Val1 int64 # NEWVAL float64 # dtype: object
内容的提问来源于stack exchange,提问作者ImNotSureAboutStats
相关产品推荐
相关产品推荐

