基于时间的Pandas智能索引:设备状态任意日期查询实现
Pandas实现设备状态的时间点查询(支持自定义初始状态)
我来给你梳理一个优雅的Pandas实现方案,完美覆盖你提到的所有查询场景,还能灵活切换初始状态。
步骤1:数据预处理
首先我们先把原始数据转换成Pandas能高效处理的格式,核心是把Date列转为datetime类型,方便后续的时间比较和索引操作:
import pandas as pd # 构建你的示例数据 data = { "Date": ["1990/01", "1990/01", "1990/03", "1990/05", "2000/01"], "Device": [50, 20, 25, 50, 20], "Status": ["ON", "ON", "ON", "OFF", "OFF"] } df = pd.DataFrame(data) # 将日期转换为datetime格式,这是时间序列操作的基础 df["Date"] = pd.to_datetime(df["Date"])
步骤2:构建设备状态的时间映射表
我们需要为每个设备生成一个包含初始状态的完整时间-状态映射,这样查询时就能通过前向填充的逻辑自动延续状态。这里写一个通用函数,支持传入自定义初始状态:
def prepare_status_map(df, initial_status="OFF"): # 按设备分组处理,每个设备单独维护状态序列 status_maps = {} for device, group in df.groupby("Device"): # 先按日期排序,确保状态变更的时间顺序正确 sorted_group = group.sort_values("Date").reset_index(drop=True) # 生成一个比该设备最早记录早一天的虚拟行,用来定义初始状态 earliest_date = sorted_group["Date"].min() initial_row = pd.DataFrame({ "Date": [earliest_date - pd.Timedelta(days=1)], "Device": [device], "Status": [initial_status] }) # 合并初始行和原始数据,再重新排序 combined = pd.concat([initial_row, sorted_group]).sort_values("Date") # 将日期设为索引,方便后续快速查询 status_maps[device] = combined.set_index("Date")["Status"] return status_maps
步骤3:实现查询函数
利用Pandas的索引定位能力,我们可以高效找到任意日期对应的设备状态,逻辑完全匹配你的需求:
def query_device_status(status_maps, device, query_date): # 统一转换查询日期为datetime格式 query_date = pd.to_datetime(query_date) # 如果设备无任何记录,返回初始状态(取映射表中任意设备的初始值,或默认OFF) if device not in status_maps: return status_maps[next(iter(status_maps.keys()))].iloc[0] if status_maps else "OFF" device_status = status_maps[device] try: # 使用pad模式找到小于等于查询日期的最近索引,获取对应状态 idx = device_status.index.get_loc(query_date, method="pad") return device_status.iloc[idx] except KeyError: # 若查询日期早于初始虚拟行的日期,直接返回初始状态 return device_status.iloc[0]
测试所有场景
场景1:默认初始状态为OFF(你的基础需求)
# 构建初始状态为OFF的映射表 status_maps_off = prepare_status_map(df, initial_status="OFF") # 测试各个查询场景 print(query_device_status(status_maps_off, 50, "1990/01")) # 输出: ON(直接匹配) print(query_device_status(status_maps_off, 50, "1990/02")) # 输出: ON(无记录,保持上一次状态) print(query_device_status(status_maps_off, 50, "1990/05")) # 输出: OFF(直接匹配) print(query_device_status(status_maps_off, 50, "2000/09")) # 输出: OFF(最后一次变更后保持) print(query_device_status(status_maps_off, 50, "1900/01")) # 输出: OFF(首次记录前默认OFF)
场景2:初始状态为ON(扩展需求)
只需要在构建映射表时传入initial_status="ON"即可:
# 构建初始状态为ON的映射表 status_maps_on = prepare_status_map(df, initial_status="ON") # 测试首次记录前的情况 print(query_device_status(status_maps_on, 50, "1900/01")) # 输出: ON
方案优势
- 优雅高效:利用Pandas的分组、索引和定位能力,避免了繁琐的循环遍历,性能更优
- 灵活扩展:通过参数
initial_status轻松切换两种初始状态场景 - 鲁棒性强:处理了设备无记录、查询日期早于所有记录等边缘情况
内容的提问来源于stack exchange,提问作者Quant Christo
相关产品推荐
相关产品推荐

