我正在将管道从pandas
迁移到polars
,数据是停靠在仓库中的卡车的到达和离开,在管道的某个步骤中,我需要计算在任何给定时间停靠的卡车数量,即,对于每一行(一辆停靠的卡车)我需要计算在一个时间窗口(- 1分钟的到达时间和+ 1分钟的离开时间)内存在的唯一卡车(“ID”)的数量。我还没有找到一种有效的方法,不依赖于逐行应用函数(pandas
的风格)。
data = pl.from_repr("""
┌─────────────────────┬─────────────────────┬─────┐
│ arrival_time ┆ departure_time ┆ ID │
│ --- ┆ --- ┆ --- │
│ datetime[μs] ┆ datetime[μs] ┆ str │
╞═════════════════════╪═════════════════════╪═════╡
│ 2023-01-01 06:23:47 ┆ 2023-01-01 06:25:08 ┆ A1 │
│ 2023-01-01 06:26:42 ┆ 2023-01-01 06:28:02 ┆ A1 │
│ 2023-01-01 06:30:20 ┆ 2023-01-01 06:35:01 ┆ A5 │
│ 2023-01-01 06:32:06 ┆ 2023-01-01 06:33:48 ┆ A6 │
│ 2023-01-01 06:33:09 ┆ 2023-01-01 06:36:01 ┆ B3 │
│ 2023-01-01 06:34:08 ┆ 2023-01-01 06:39:49 ┆ C3 │
│ 2023-01-01 06:36:40 ┆ 2023-01-01 06:38:34 ┆ A6 │
│ 2023-01-01 06:37:43 ┆ 2023-01-01 06:40:48 ┆ A5 │
│ 2023-01-01 06:39:48 ┆ 2023-01-01 06:46:10 ┆ A6 │
└─────────────────────┴─────────────────────┴─────┘
""")
到目前为止,我的代码,第一部分是在polars
和最后一个仍然使用pandas
:
processed_data = (
data.sort(by=pl.col("arrival_time"))
.with_columns(
arrival_time_expanded=pl.col("arrival_time").dt.offset_by("-1m"),
departure_time_expanded=pl.col("departure_time").dt.offset_by("1m"),
)
.to_pandas()
)
processed_data = processed_data.assign(
docked_trucks=processed_data.apply(
lambda row: processed_data[
(processed_data.arrival_time_expanded <= row.departure_time)
& (processed_data.departure_time_expanded >= row.arrival_time)
]["ID"].nunique(),
axis=1,
)
)
结果:
┌──────────────┬────────────────┬─────┬──────────────────────┬─────────────────────┬───────────────┐
│ arrival_time ┆ departure_time ┆ ID ┆ arrival_time_expande ┆ departure_time_expa ┆ docked_trucks │
│ --- ┆ --- ┆ --- ┆ d ┆ nded ┆ --- │
│ datetime[ns] ┆ datetime[ns] ┆ str ┆ --- ┆ --- ┆ i64 │
│ ┆ ┆ ┆ datetime[ns] ┆ datetime[ns] ┆ │
╞══════════════╪════════════════╪═════╪══════════════════════╪═════════════════════╪═══════════════╡
│ 2023-01-01 ┆ 2023-01-01 ┆ A1 ┆ 2023-01-01 06:22:47 ┆ 2023-01-01 06:26:08 ┆ 1 │
│ 06:23:47 ┆ 06:25:08 ┆ ┆ ┆ ┆ │
│ 2023-01-01 ┆ 2023-01-01 ┆ A1 ┆ 2023-01-01 06:25:42 ┆ 2023-01-01 06:29:02 ┆ 1 │
│ 06:26:42 ┆ 06:28:02 ┆ ┆ ┆ ┆ │
│ 2023-01-01 ┆ 2023-01-01 ┆ A5 ┆ 2023-01-01 06:29:20 ┆ 2023-01-01 06:36:01 ┆ 4 │
│ 06:30:20 ┆ 06:35:01 ┆ ┆ ┆ ┆ │
│ 2023-01-01 ┆ 2023-01-01 ┆ A6 ┆ 2023-01-01 06:31:06 ┆ 2023-01-01 06:34:48 ┆ 4 │
│ 06:32:06 ┆ 06:33:48 ┆ ┆ ┆ ┆ │
│ 2023-01-01 ┆ 2023-01-01 ┆ B3 ┆ 2023-01-01 06:32:09 ┆ 2023-01-01 06:37:01 ┆ 4 │
│ 06:33:09 ┆ 06:36:01 ┆ ┆ ┆ ┆ │
│ 2023-01-01 ┆ 2023-01-01 ┆ C3 ┆ 2023-01-01 06:33:08 ┆ 2023-01-01 06:40:49 ┆ 4 │
│ 06:34:08 ┆ 06:39:49 ┆ ┆ ┆ ┆ │
│ 2023-01-01 ┆ 2023-01-01 ┆ A6 ┆ 2023-01-01 06:35:40 ┆ 2023-01-01 06:39:34 ┆ 4 │
│ 06:36:40 ┆ 06:38:34 ┆ ┆ ┆ ┆ │
│ 2023-01-01 ┆ 2023-01-01 ┆ A5 ┆ 2023-01-01 06:36:43 ┆ 2023-01-01 06:41:48 ┆ 3 │
│ 06:37:43 ┆ 06:40:48 ┆ ┆ ┆ ┆ │
│ 2023-01-01 ┆ 2023-01-01 ┆ A6 ┆ 2023-01-01 06:38:48 ┆ 2023-01-01 06:47:10 ┆ 3 │
│ 06:39:48 ┆ 06:46:10 ┆ ┆ ┆ ┆ │
└──────────────┴────────────────┴─────┴──────────────────────┴─────────────────────┴───────────────┘
2条答案
按热度按时间ruarlubt1#
如果我们用.melt()将数据整形为“长格式
看起来这可能是一个Asof连接类型的问题。
**更新:**也许这是一个更简单的方法。
然后用
.cumsum
创建一个窗口id并计算到达时间。qojgxg4l2#
所以我想出了两个选项,这两个选项都可能会因为大量的数据而爆炸:
第一种解决方案:
首先执行交叉联接,然后过滤错误的结果,然后执行groupby。不幸的是,由于交叉连接,这个查询可能会爆炸大量的数据。
第二种解决方案:
这可能会在大数据上表现得更好,但我还没有测试过,但你也会失去一点精度。为了减少基数,我们将到达和离开时间舍入到下一分钟,然后将表分解为每分钟有哪辆卡车在仓库中。