如何高效判断Pandas的Datetime Index是否在指定日期范围内
问题描述
我有以下代码:
import pandas as pd, numpy as np from datetime import datetime end_dt = datetime.today() st_dt = (end_dt + pd.DateOffset(-10)).date() df_index = pd.date_range(st_dt, end_dt) df = pd.DataFrame(index=df_index, columns=['in_range']) data = [pd.to_datetime(['2022-11-08','2022-11-10']), pd.to_datetime(['2022-11-13','2022-11-15'])] dt_ranges = pd.DataFrame(data,columns={'st_dt':'datetimens[64]', 'end_dt': 'datetimens[64]'})
运行后生成两个DataFrame:
df:
in_range 2022-11-08 NaN 2022-11-09 NaN 2022-11-10 NaN 2022-11-11 NaN 2022-11-12 NaN 2022-11-13 NaN 2022-11-14 NaN 2022-11-15 NaN 2022-11-16 NaN 2022-11-17 NaN 2022-11-18 NaN
dt_ranges:
st_dt end_dt 0 2022-11-08 2022-11-10 1 2022-11-13 2022-11-15
我需要更新df的in_range列,标记其Datetime Index是否落在dt_ranges中的任意一组起止日期范围内,最终效果如下:
in_range 2022-11-08 True 2022-11-09 True 2022-11-10 True 2022-11-11 NaN 2022-11-12 NaN 2022-11-13 True 2022-11-14 True 2022-11-15 True 2022-11-16 NaN 2022-11-17 NaN 2022-11-18 NaN
我尝试用lambda和循环实现,但效率较低,且代码运行后in_range列始终为NaN(怀疑是重置索引导致对齐问题),代码如下:
def in_range(index_date, date_ranges): for r in date_ranges.values: if (r[0] >= index_date) & (r[1] <= index_date): return True return False df['in_range'] = df.reset_index().apply(lambda x: in_range(x.date, dt_ranges), axis=1)
请问是否有更Pythonic(Pandas风格)的高效实现方式?
高效实现方案
方法一:利用pd.IntervalIndex批量判断
这是最贴合Pandas风格的高效实现,无需循环,直接通过区间索引完成批量判断:
# 将dt_ranges的起止日期转换为闭合区间数组(包含首尾日期) intervals = pd.IntervalIndex.from_arrays(dt_ranges['st_dt'], dt_ranges['end_dt'], closed='both') # 检查df索引是否落在任意区间内,再将False转为NaN df['in_range'] = df.index.isin(intervals).replace({False: pd.NA})
方法二:向量化条件更新
如果不想用IntervalIndex,也可以通过向量化逻辑运算实现,相比原生循环效率提升明显:
# 先初始化in_range列为NaN df['in_range'] = pd.NA # 遍历每个日期区间,用掩码更新对应范围的in_range值 for _, row in dt_ranges.iterrows(): mask = (df.index >= row['st_dt']) & (df.index <= row['end_dt']) df.loc[mask, 'in_range'] = True
原有代码的问题说明
- 逻辑判断错误:
in_range函数里的条件写反了,正确逻辑应该是(r[0] <= index_date) & (index_date <= r[1]),原条件会导致永远返回False,最终赋值为NaN。 - 列名错误:
df.reset_index()后生成的列名为index而非date,调用x.date会触发报错,这也是结果全为NaN的原因之一。
内容的提问来源于stack exchange,提问作者mike01010
相关产品推荐
相关产品推荐

