代码之家  ›  专栏  ›  技术社区  ›  DJDuque

非公平加入波兰

  •  1
  • DJDuque  · 技术社区  · 11 月前

    如果你来自未来,希望 this PR 已合并。

    如果你不是来自未来,希望如此 this answer 解决你的问题。

    在复制粘贴上面建议的DuckDB集成并在我的真实数据中比较结果之前,我只想用polars来解决我的问题(我不是专家,但我可以跟踪正在发生的事情)。

    我有一个事件列表(名称和时间戳)和一个时间窗口列表。我想计算每个时间窗口中每个事件发生的次数。

    我觉得我即将得到一个正常工作的东西,但我已经被困了几个小时了:

    import polars as pl
    
    events = {
        "name": ["a", "b", "a", "b", "a", "c", "b", "a", "b", "a", "b", "a", "b", "a", "b", "a", "b", "a", "b"],
        "time": [0.0, 1.0, 1.5, 2.0, 2.25, 2.26, 2.45, 2.5, 3.0, 3.4, 3.5, 3.6, 3.65, 3.7, 3.8, 4.0, 4.5, 5.0, 6.0],
    }
    
    windows = {
        "start_time": [1.0, 2.0, 3.0, 4.0],
        "stop_time": [3.5, 2.5, 3.7, 5.0],
    }
    
    events_df = pl.DataFrame(events).sort("time").with_row_index()
    windows_df = (
        pl.DataFrame(windows)
        .sort("start_time")
        .join_asof(events_df, left_on="start_time", right_on="time", strategy="forward")
        .drop("name", "time")
        .rename({"index": "first_index"})
        .sort("stop_time")
        .join_asof(events_df, left_on="stop_time", right_on="time", strategy="backward")
        .drop("name", "time")
        .rename({"index": "last_index"})
    )
    
    print(windows_df)
    """
    shape: (4, 4)
    ┌────────────┬───────────┬─────────────┬────────────┐
    │ start_time ┆ stop_time ┆ first_index ┆ last_index │
    │ ---        ┆ ---       ┆ ---         ┆ ---        │
    │ f64        ┆ f64       ┆ u32         ┆ u32        │
    ╞════════════╪═══════════╪═════════════╪════════════╡
    │ 2.0        ┆ 2.5       ┆ 3           ┆ 7          │
    │ 1.0        ┆ 3.5       ┆ 1           ┆ 10         │
    │ 3.0        ┆ 3.7       ┆ 8           ┆ 13         │
    │ 4.0        ┆ 5.0       ┆ 15          ┆ 17         │
    └────────────┴───────────┴─────────────┴────────────┘
    """
    

    到目前为止,对于每个时间窗口,我都可以得到我关心的第一个和最后一个事件的索引。现在我“只”需要计算每种类型的数量。我能得到一些关于如何做到这一点的帮助吗?

    我要查找的输出应该如下:

    shape: (4, 5)
    ┌────────────┬───────────┬─────┬─────┬─────┐
    │ start_time ┆ stop_time ┆ a   ┆ b   ┆ c   │
    │ ---        ┆ ---       ┆ --- ┆ --- ┆ --- │
    │ f64        ┆ f64       ┆ i64 ┆ i64 ┆ i64 │
    ╞════════════╪═══════════╪═════╪═════╪═════╡
    │ 1.0        ┆ 3.5       ┆ 4   ┆ 5   ┆ 1   │
    │ 2.0        ┆ 2.5       ┆ 2   ┆ 2   ┆ 1   │
    │ 3.0        ┆ 3.7       ┆ 3   ┆ 3   ┆ 0   │
    │ 4.0        ┆ 5.0       ┆ 2   ┆ 1   ┆ 0   │
    └────────────┴───────────┴─────┴─────┴─────┘
    

    我想用类似的东西 int_ranges() , gather() ,以及 explode() 可以给我一个包含每个时间窗口及其所有相应事件的数据帧。最后,类似 group_by() , count() ,以及 pivot() 可以让我找到我想要的数据帧。但我已经为此挣扎了一段时间。

    1 回复  |  直到 11 月前
        1
  •  1
  •   roman    11 月前

    不确定它是否会更有性能,但你可以改变你的 windows_df 通过以下方式获得理想的输出:

    • int_ranges() 从以下位置创建索引列表 first_index last_index .
    • explode() 以炸开这些行。
    • join() 要重新加入 events_df .
    • pivot() 将行转换为列。
    (
        windows_df
        .with_columns(index = pl.int_ranges(pl.col.first_index, pl.col.last_index, dtype=pl.UInt32))
        .explode("index")
        .join(events_df, on="index", how="inner")
        .pivot(on="name", index=["start_time","stop_time"], aggregate_function="len", values="index")
        .fill_null(0)
    )
    
    ┌────────────┬───────────┬─────┬─────┬─────┐
    │ start_time ┆ stop_time ┆ a   ┆ b   ┆ c   │
    │ ---        ┆ ---       ┆ --- ┆ --- ┆ --- │
    │ f64        ┆ f64       ┆ u32 ┆ u32 ┆ u32 │
    ╞════════════╪═══════════╪═════╪═════╪═════╡
    │ 2.0        ┆ 2.5       ┆ 1   ┆ 2   ┆ 1   │
    │ 1.0        ┆ 3.5       ┆ 4   ┆ 4   ┆ 1   │
    │ 3.0        ┆ 3.7       ┆ 2   ┆ 3   ┆ 0   │
    │ 4.0        ┆ 5.0       ┆ 1   ┆ 1   ┆ 0   │
    └────────────┴───────────┴─────┴─────┴─────┘