如何在Pandas中基于另一列Datetime对Datetime列分组匹配?
Pandas日期匹配实现方案
问题描述
现有包含两列日期时间的Pandas DataFrame,原始数据如下:
| Col_1 | Col_2 |
|---|---|
| 2023-01-02 | 2023-01-02 9:00 |
| 2023-01-03 | 2023-01-02 20:00 |
| 2023-01-04 | 2023-01-03 1:00 |
| 2023-01-05 | 2023-01-04 9:00 |
| 2023-01-08 | 2023-01-05 16:00 |
| 2023-01-06 9:00 | |
| 2023-01-08 12:00 |
需要按照以下规则将Col_2的日期时间匹配到Col_1的日期:
- 若
Col_2时间早于12点:若Col_1存在相同日期则保留该日期,否则匹配Col_1的下一个日期; - 若
Col_2时间大于等于12点,则匹配Col_1的下一个日期; - 若最后一个值时间过12点且
Col_1无对应日期,则使用Col_1最后一天加1天。
期望得到的结果如下:
| Col_1 | Col_2 |
|---|---|
| 2023-01-02 | 2023-01-02 |
| 2023-01-03 | 2023-01-03 |
| 2023-01-04 | 2023-01-03 |
| 2023-01-05 | 2023-01-04 |
| 2023-01-08 | 2023-01-08 |
| 2023-01-08 | |
| 2023-01-09 |
实现步骤
Pandas没有直接对应该规则的内置函数,但可以通过日期处理、条件判断和查找匹配实现,具体代码如下:
1. 导入库并构造原始DataFrame
import pandas as pd from datetime import timedelta # 构造原始数据 data = { 'Col_1': ['2023-01-02', '2023-01-03', '2023-01-04', '2023-01-05', '2023-01-08', '', ''], 'Col_2': ['2023-01-02 9:00', '2023-01-02 20:00', '2023-01-03 1:00', '2023-01-04 9:00', '2023-01-05 16:00', '2023-01-06 9:00', '2023-01-08 12:00'] } df = pd.DataFrame(data)
2. 数据类型转换
将两列转换为日期时间类型,空值会转为NaT:
df['Col_1'] = pd.to_datetime(df['Col_1']) df['Col_2'] = pd.to_datetime(df['Col_2'])
3. 提取关键日期和时间条件
提取Col_2的日期部分,同时标记时间是否早于12点:
col2_date = df['Col_2'].dt.date is_before_12 = df['Col_2'].dt.hour < 12
4. 整理Col_1的有效日期列表
获取Col_1中非空的日期并排序,作为匹配基准:
valid_col1_dates = df['Col_1'].dropna().dt.date.sort_values().tolist() last_col1_date = valid_col1_dates[-1]
5. 编写匹配函数
按照规则实现每个Col_2日期的匹配逻辑:
def match_date(col2_date_val, is_before_12_val): # 规则2:时间>=12点,目标日期为Col_2日期加1天 if not is_before_12_val: target_date = col2_date_val + timedelta(days=1) else: # 规则1:时间<12点,先检查Col_1是否有相同日期 if col2_date_val in valid_col1_dates: target_date = col2_date_val else: target_date = col2_date_val + timedelta(days=1) # 检查目标日期是否在Col_1有效日期中,不在则找第一个大于它的日期 if target_date not in valid_col1_dates: for d in valid_col1_dates: if d > target_date: target_date = d break else: # 规则3:找不到后续有效日期,用Col_1最后一天加1天 target_date = last_col1_date + timedelta(days=1) return pd.to_datetime(target_date)
6. 应用函数并生成结果
df['Col_2'] = df.apply(lambda row: match_date(row['Col_2'].dt.date, row['Col_2'].dt.hour < 12), axis=1) # 格式化日期为字符串(和期望结果格式一致,可根据需求保留日期时间类型) df['Col_2'] = df['Col_2'].dt.strftime('%Y-%m-%d') df['Col_1'] = df['Col_1'].dt.strftime('%Y-%m-%d').fillna('') print(df)
运行后即可得到符合要求的结果。
说明
- 通过
timedelta处理日期加减,遍历有效日期列表查找匹配的后续日期; - 针对边界情况(如最后一个值无对应日期),直接使用
Col_1最后一天加1天; - 若需保留日期时间类型,可去掉最后的字符串格式化步骤。
内容的提问来源于stack exchange,提问作者Chi-Yuan Li
相关产品推荐
相关产品推荐

