Pandas生成各日志记录器相邻时段时如何移除双重for循环
无嵌套循环的实现方案
核心是利用Pandas的分组移位向量化操作替代双层循环,不需要逐行遍历每个日志主体、再逐行配对相邻日志,数据量越大时性能优势越明显。
完整可运行代码
import uuid from datetime import datetime import pandas as pd # 原测试数据初始化部分保持不变 df = pd.DataFrame({ "log_item_id": [str(uuid.uuid4()) for _ in range(6)], "when": [datetime(2021, 4, d, 12) for d in [1, 8, 15]] * 2, "logger_id": [str(uuid.uuid4()), str(uuid.uuid4())] * 3, }).set_index("log_item_id") # 替换原嵌套双重for循环的实现部分 # 1. 按日志主体、记录时间排序,保证配对的是时间顺序相邻的日志 # reset_index()将原日志ID索引转为普通列,方便后续做移位配对 df_sorted = df.sort_values(["logger_id", "when"]).reset_index() # 2. 按日志主体分组,取分组内上一行的日志ID作为时段的起始项 df_sorted["item_start"] = df_sorted.groupby("logger_id")["log_item_id"].shift(1) # 3. 过滤掉没有前置日志的无效行(即每个日志主体的第一条日志,无法构成相邻时段),选取需要的列 periods = df_sorted.dropna(subset=["item_start"])[["item_start", "log_item_id"]].copy() # 4. 重命名列,将原日志ID列映射为item_finish periods = periods.rename(columns={"log_item_id": "item_finish"}) # 5. 批量生成新的UUID作为结果表的唯一索引 periods.index = [str(uuid.uuid4()) for _ in range(len(periods))]
逻辑说明
- 输出结构和原嵌套循环生成的结果完全对齐:以新生成的唯一ID为索引,包含
item_start、item_finish两列,分别对应时段的起始、结束日志ID - 排序步骤用来保证配对的日志是严格按时间先后相邻的,如果原始数据已经明确保证每个
logger_id下的日志就是按时间升序存储的,可以省略排序步骤 - 全流程没有Python层面的逐行循环,所有分组、移位、过滤操作都是Pandas底层的向量化实现,处理十万行以上的大规模日志时,运行速度会比原嵌套循环快几个数量级
内容的提问来源于stack exchange,提问作者joris
相关产品推荐
相关产品推荐

