You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

需求:筛选间隔超20天且保留最小dif_to_forelast的有效日期列表

日期筛选需求与解决方案

需求背景

现有一个包含date和dif_to_forelast列的DataFrame,已通过带for循环的函数识别出dif_to_forelast≤-0.1的簇,并提取每个簇的首个日期存入first_date列表(列表长度为0-4,示例如下):

1: []           
2: [06/07/2017]         
3: [23/05/2017, 24/06/2017] 
4: [19/05/2018, 03/06/2018, 16/06/2018]
5: [18/05/2019, 23/06/2019, 01/07/2019, 06/07/2019]

核心筛选规则

对first_date列表需执行以下筛选逻辑:

  • 列表中保留的日期需间隔超过20天;
  • 若两个日期间隔不足20天,仅保留dif_to_forelast值最小的日期;
  • 从第一对日期(first_date[0]与first_date[1])开始逐对比较,后续比较需基于前一次决策的有效日期(即前一轮筛选后保留的最后一个日期)。

示例数据与预期结果

示例DataFrame片段

date           dif_to_forelast
19/05/2018          -0.11
03/06/2018          -0.2
16/06/2018          -0.19
# End of cluster in list 4
18/05/2019          -0.15
23/06/2019          -0.14
01/07/2019          -0.11
06/07/2019          -0.13
# End of cluster in list 5

筛选逻辑示例

  • 列表4:19/05/2018与03/06/2018间隔不足20天,保留dif最小的03/06/2018;03/06/2018与16/06/2018间隔不足20天,仍保留03/06/2018,最终列表为[03/06/2018]。
  • 列表5:18/05/2019与23/06/2019间隔超20天,均保留;23/06/2019与01/07/2019、06/07/2019间隔不足20天,保留dif最小的23/06/2019,最终列表为[18/05/2019, 23/06/2019]。

现有代码问题

原尝试编写的代码逻辑混乱,无法优雅处理所有列表长度的情况,也无法正确实现连锁决策逻辑(代码片段如下):

# Handle false negatives too close to each other
# Directly pass lists with one element or less
if len(first_date) <= 1:
    results[year, field_id] = {
        'num_cuts': len(first_date),
        'cutting dates': first_date
    }
# Begin analysis if list has two or more elements
elif len(first_date) >= 2:
    # Initialise new list for valid elements
    valid_dates = []
    # First two dates always need to be inspected first to populate valid_dates
    # So that valid_dates can be compared against following elements in first_date for lists of len >= 3
    current_date = pd.to_datetime(first_date[1], dayfirst=True)
    prev_date = pd.to_datetime(first_date[0], dayfirst=True)
    days_difference = (current_date - prev_date).days
    # Branch for valid first pair of dates
    if days_difference > 20:
        # Append both dates if they have a valid distance
        valid_dates.append(prev_date)
        valid_dates.append(current_date)
        # Remove dates from the first_date list for further analysis in lists of len >= 3
        first_date.pop(prev_date)
        first_date.pop(current_date)
        # End the analysis for lists of 2
        if len(first_date) == 2:
            results[year, field_id] = {
                'num_cuts': len(valid_dates),
                'cutting dates': valid_dates
                }
        # Continue the analysis for lists of len >= 3
        # Use the last date of valid_dates, compare with first remaining date in first_date
        else:
            for i in range(1, len(first_date)):

    # Branch for first pair of dates too close to each other 
    else:
        prev_dif_to_forelast = dataframe[dataframe['date'] == prev_date]['dif_to_forelast'].iloc[0]
        current_dif_to_forelast = dataframe[dataframe['date'] == current_date]['dif_to_forelast'].iloc[0]
        # if - else conditions for if one or the other date are the valid ones
        # Analysed dates are removed from first_date in all cases for further analysis in lists of len >= 3
        if current_dif_to_forelast < prev_dif_to_forelast:
            valid_dates.append(current_date)
            first_date.pop(prev_date)
            first_date.pop(current_date)
        else:
            valid_dates.append(prev_date)
            first_date.pop(prev_date)
            first_date.pop(current_date)
        # End the analysis for lists of 2 with valid spacing
        if len(first_date) == 2:
                results[year, field_id] = {
                    'num_cuts': len(valid_dates),
                    'cutting dates': valid_dates
                }
            # Continue the analysis for lists of len >= 3
            # Use the last date of valid_dates, compare with first remaining date in first_date
            else:

解决方案代码

以下是实现上述逻辑的优雅代码,通过维护有效日期列表,逐一遍历处理每个日期,确保连锁决策逻辑正确:

import pandas as pd

def filter_valid_dates(first_date_list, dataframe):
    # 处理空列表或单元素列表,直接返回
    if len(first_date_list) <= 1:
        return {
            'num_cuts': len(first_date_list),
            'cutting dates': first_date_list.copy()
        }
    
    # 将first_date转换为带datetime和dif的DataFrame,方便后续操作
    date_df = pd.DataFrame({
        'date_str': first_date_list,
        'date': pd.to_datetime(first_date_list, dayfirst=True)
    })
    # 关联原DataFrame的dif_to_forelast值
    date_df = date_df.merge(dataframe[['date', 'dif_to_forelast']], 
                           left_on='date', right_on='date', how='left')
    
    valid_dates = []
    # 初始化第一个候选日期
    current_candidate = date_df.iloc[0]
    
    for idx in range(1, len(date_df)):
        next_date = date_df.iloc[idx]
        # 计算间隔天数
        days_diff = (next_date['date'] - current_candidate['date']).days
        
        if days_diff > 20:
            # 间隔超过20天,保留当前候选,添加下一个日期为新候选
            valid_dates.append(current_candidate['date_str'])
            current_candidate = next_date
        else:
            # 间隔不足20天,保留dif更小的那个作为候选
            if next_date['dif_to_forelast'] < current_candidate['dif_to_forelast']:
                current_candidate = next_date
    
    # 循环结束后,添加最后一个候选日期
    valid_dates.append(current_candidate['date_str'])
    
    return {
        'num_cuts': len(valid_dates),
        'cutting dates': valid_dates
    }

# 使用示例
# 假设dataframe是你的原始数据,first_date是提取的日期列表
# results[(year, field_id)] = filter_valid_dates(first_date, dataframe)

代码说明

  1. 先处理边界情况(空列表或单元素列表),直接返回结果;
  2. 将first_date列表转换为带datetime格式和对应dif_to_forelast值的DataFrame,避免多次查询原DataFrame;
  3. 维护一个current_candidate变量保存当前待保留的候选日期,遍历后续每个日期:
    • 若与候选日期间隔超20天,将候选日期加入有效列表,更新候选为当前日期;
    • 若间隔不足20天,比较两者的dif_to_forelast,保留值更小的作为新候选;
  4. 遍历结束后,将最后一个候选日期加入有效列表,返回结果字典。

这样的实现逻辑清晰,能处理0-4个元素的所有情况,且严格遵循逐对比较、连锁决策的规则。

内容的提问来源于stack exchange,提问作者Barbara Perez de Araújo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 05:55:54