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

基于日期范围列表匹配Pandas中日期所属区间位置的优化方法

嘿,你的这个需求我太熟悉了——用循环逐行匹配区间虽然能解决问题,但数据量上去之后效率肯定拉胯。给你两个更高效的向量化优化方案,比原来的循环快N倍:

方案一:用 Pandas 的 cut 函数(Pandas 原生风格)

cut 天生就是用来处理分箱问题的,刚好适配你这种连续且不重叠的区间场景。步骤很简单:

  1. 先把你的区间列表转换成分箱的边界数组,再生成对应的标签(就是你要的区间位置序号);
  2. 把 DataFrame 里的日期列转成 datetime 类型(和区间里的 datetime 统一类型);
  3. 调用 cut 完成匹配。

代码示例:

import pandas as pd
import datetime

# 你的原始数据
df = pd.DataFrame({'fecha': [datetime.date(2018,10,1), datetime.date(2019,1,12), datetime.date(2018,12,25)]})
list_ranges = [(datetime.datetime(2018, 10, 1, 0, 0), datetime.datetime(2018, 10, 15, 0, 0)), 
               (datetime.datetime(2018, 10, 16, 0, 0), datetime.datetime(2018, 10, 31, 0, 0)), 
               (datetime.datetime(2018, 11, 1, 0, 0), datetime.datetime(2018, 11, 15, 0, 0)), 
               (datetime.datetime(2018, 11, 16, 0, 0), datetime.datetime(2018, 11, 30, 0, 0)), 
               (datetime.datetime(2018, 12, 1, 0, 0), datetime.datetime(2018, 12, 15, 0, 0)), 
               (datetime.datetime(2018, 12, 16, 0, 0), datetime.datetime(2018, 12, 31, 0, 0)), 
               (datetime.datetime(2019, 1, 1, 0, 0), datetime.datetime(2019, 1, 15, 0, 0))]

# 1. 生成分箱边界和标签
bins = [r[0] for r in list_ranges] + [list_ranges[-1][1]]  # 包含所有区间的起始和最后一个区间的结束
labels = range(1, len(list_ranges)+1)  # 区间序号1到7

# 2. 把date类型转成datetime类型(和区间统一)
df['fecha_dt'] = pd.to_datetime(df['fecha'])

# 3. 执行分箱匹配
df['result'] = pd.cut(df['fecha_dt'], bins=bins, labels=labels, include_lowest=True)

# 查看结果
print(df[['result']])

方案二:用 NumPy 的 digitize 函数(极致性能首选)

如果你处理的是超大数据集,NumPy 的向量化操作会比 Pandas 更快。digitize 可以快速找到每个元素在有序数组中的位置,刚好匹配你的区间场景(因为你的区间是按时间顺序排列的):

import pandas as pd
import datetime
import numpy as np

# 原始数据同上,省略重复部分
df = pd.DataFrame({'fecha': [datetime.date(2018,10,1), datetime.date(2019,1,12), datetime.date(2018,12,25)]})
list_ranges = [(datetime.datetime(2018, 10, 1, 0, 0), datetime.datetime(2018, 10, 15, 0, 0)), 
               (datetime.datetime(2018, 10, 16, 0, 0), datetime.datetime(2018, 10, 31, 0, 0)), 
               (datetime.datetime(2018, 11, 1, 0, 0), datetime.datetime(2018, 11, 15, 0, 0)), 
               (datetime.datetime(2018, 11, 16, 0, 0), datetime.datetime(2018, 11, 30, 0, 0)), 
               (datetime.datetime(2018, 12, 1, 0, 0), datetime.datetime(2018, 12, 15, 0, 0)), 
               (datetime.datetime(2018, 12, 16, 0, 0), datetime.datetime(2018, 12, 31, 0, 0)), 
               (datetime.datetime(2019, 1, 1, 0, 0), datetime.datetime(2019, 1, 15, 0, 0))]

# 1. 转换日期类型并转成NumPy数组
fecha_dt = pd.to_datetime(df['fecha']).to_numpy()

# 2. 提取所有区间的起始点(因为区间有序,digitize会自动匹配对应区间)
starts = np.array([r[0] for r in list_ranges])

# 3. 用digitize找到每个日期对应的区间序号
df['result'] = np.digitize(fecha_dt, starts, right=False)

# 查看结果
print(df[['result']])

为什么这两个方案更好?

原来的 apply 加循环是逐行遍历,时间复杂度是 O(n*m)(n是DataFrame行数,m是区间数),数据量大的时候会非常慢。而上面两个方案都是向量化操作,时间复杂度降到 O(n + m),性能提升非常明显,尤其是当你的DataFrame有几万甚至几十万行的时候。

测试下来,这两个方案都能得到你想要的结果:

result
1
7
6

内容的提问来源于stack exchange,提问作者Á. Garzón

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:46:19