pandas按日期过滤DataFrame返回空结果的解决方法
问题根因
空返回结果和Timestamp/datetime类型差异无关,核心是三个代码逻辑错误:
- 三层循环做了笛卡尔积匹配,没有把车辆和它对应的品牌生效/失效时间绑定,会出现拿A车的订单匹配B车有效期的错误。
DataFrame.append()不会原地修改对象,循环中只调用不赋值,最终的filtered_orders始终是空初始化的DataFrame。- 手动循环做时间转换效率极低,且容易引入格式解析错误。
注:pandas的Timestamp类型原生兼容和Python标准库datetime.datetime的大小比较,不需要额外做类型转换。
修正方案
放弃多层循环写法,先建立车辆和品牌有效期的一一映射关系,通过表关联一次性完成过滤,代码更简洁且运行效率更高:
import pandas as pd # 构建车辆与品牌有效期的映射表,保证车和时间一一对应 car_valid_period = pd.DataFrame({ "Car": ["AAA111", "BBB222", "CCC333"], "branded": pd.to_datetime(["2020-11-19", "2019-04-30", "2019-09-10"]), "debranded": pd.to_datetime(["2022-06-21", "2020-03-01", "2020-03-01"]) }) # 读取并预处理订单数据 orders = pd.read_csv("filtered_orders.csv", index_col=0) orders = orders.rename({"Created Time": "time"}, axis="columns") # 用pandas原生方法批量转换时间格式,无需手动循环 orders["time"] = pd.to_datetime(orders["time"]) # 关联订单和对应车辆的有效期,直接完成过滤 order_merge = orders.merge(car_valid_period, on="Car", how="left") filtered_orders = order_merge[ (order_merge["time"] >= order_merge["branded"]) & (order_merge["time"] <= order_merge["debranded"]) ].drop(columns=["branded", "debranded"]) # 如需还原原列名,执行以下代码 filtered_orders = filtered_orders.rename({"time": "Created Time"}, axis="columns")
结果验证
用提供的样例数据运行上述代码,输出结果和预期完全一致:
Created Time Ride price Car 0 2022-06-20 16:09:53 AAA111 2 2019-06-30 16:09:51 BBB222
- AAA111的订单时间2022-06-20处于品牌有效期2020-11-19~2022-06-21内,保留。
- BBB222仅2019-06-30的订单处于品牌有效期2019-04-30~2020-03-01内,其余订单要么早于品牌生效时间,要么晚于摘牌时间,被过滤。
- CCC333的样例订单均不在品牌有效期2019-09-10~2020-03-01范围内,无保留数据。
注意事项
- 所有DataFrame的匹配、关联操作优先用pandas内置的
merge、query等方法,避免手写多层循环,既容易出逻辑错误,性能也远低于内置方法。 - pandas高版本已经废弃
DataFrame.append()方法,批量拼接数据推荐使用pd.concat()。 - 时间格式转换统一用
pd.to_datetime(),支持批量处理,自动适配绝大多数常见时间格式,不需要手动写datetime.strptime逐行解析。
内容的提问来源于stack exchange,提问作者AleksLi
相关产品推荐
相关产品推荐

