如何基于其他 DataFrame 行过滤器创建列?
问题内容
我有一个名为“hourly_data”的 lazyframe,其中包含一个名为“time”的每小时日期时间列。我还有一个名为“future_periods”的 dataframe,其中包含两个日期时间列,称为“start”(未来周期的开始日期时间)和“end”(未来周期的结束时间)。重要的是,这些未来时期并不重叠。
我想为 hourly_data lazyframe 创建一个名为“period”的列,它应该有一个 int 值,该值基于哪个周期(future_periods dataframe 行,如果有 10 个周期,则从 0 到 9)时间列值hourly_data 的值介于 future_periods 的开始列值和结束列值之间。
我尝试执行以下操作:
periods = pl.series(range(future_periods.height))hourly_data = hourly_data.with_columns( ( pl.when(((future_periods.get_column('start') <p>但这给了我错误:typeerror:使用 values 参数的不支持类型“expr”调用系列构造函数</p><p>我想要实现的目标:输入:</p><pre class="brush:php;toolbar:false;">hourly_data:┌────────────────────┐│ time ││ --- ││ datetime │╞════════════════════╡│ 2024-01-01 00:00:00││ 2024-01-01 01:00:00││ 2024-01-01 02:00:00││ ... ││ 2024-03-31 23:00:00││ 2024-04-01 00:00:00││ 2024-04-01 01:00:00││ ... ││ 2024-06-01 00:00:00│└────────────────────┘future_periods:┌─────────────────────────┬───────────────────────┐│ start ┆ end ││ --- ┆ --- ││ datetime ┆ datetime │╞═════════════════════════╪═══════════════════════╡│ 2024-01-01 00:00:00 ┆ 2024-01-31 23:00:00 ││ 2024-02-01 00:00:00 ┆ 2024-02-28 23:00:00 ││ 2024-03-01 00:00:00 ┆ 2024-03-31 23:00:00 ││ 2024-04-01 00:00:00 ┆ 2024-05-31 23:00:00 │└─────────────────────────┴───────────────────────┘
输出:
hourly_data:┌─────────────────────────┬────────┐│ time ┆ period ││ --- ┆ --- ││ datetime ┆ int │╞═════════════════════════╪════════╡│ 2024-01-01 00:00:00 ┆ 0 ││ 2024-01-01 01:00:00 ┆ 0 ││ 2024-01-01 02:00:00 ┆ 0 ││ ... ┆ ... ││ 2024-03-31 23:00:00 ┆ 2 ││ 2024-04-01 00:00:00 ┆ 3 ││ 2024-04-01 01:00:00 ┆ 3 ││ ... ┆ ... ││ 2024-06-01 00:00:00 ┆ None │└─────────────────────────┴────────┘
正确答案
一般来说,它是不等式连接,或者在您的情况下,在范围内连接。这是执行此操作的一种方法。让我们首先创建一些示例数据:
hourly_data = pl.dataframe({ "time": ['2023-01-01 14:00','2023-01-02 09:00', '2023-01-04 11:00']}).lazy()future_periods = pl.dataframe({ "id": [1,2,3,4], "start": ['2023-01-01 11:00','2023-01-02 10:00', '2023-01-03 15:00', '2023-01-04 10:00'], "end": ['2023-01-01 16:00','2023-01-02 11:00', '2023-01-03 18:00', '2023-01-04 15:00']}).lazy()┌──────────────────┬──────┐│ time ┆ data ││ --- ┆ --- ││ str ┆ str │╞══════════════════╪══════╡│ 2023-01-01 14:00 ┆ a ││ 2023-01-02 09:00 ┆ b ││ 2023-01-04 11:00 ┆ c │└──────────────────┴──────┘ ┌─────┬──────────────────┬──────────────────┐│ id ┆ start ┆ end ││ --- ┆ --- ┆ --- ││ i64 ┆ str ┆ str │╞═════╪══════════════════╪══════════════════╡│ 1 ┆ 2023-01-01 11:00 ┆ 2023-01-01 16:00 ││ 2 ┆ 2023-01-02 10:00 ┆ 2023-01-02 11:00 ││ 3 ┆ 2023-01-03 15:00 ┆ 2023-01-03 18:00 ││ 4 ┆ 2023-01-04 10:00 ┆ 2023-01-04 15:00 │└─────┴──────────────────┴──────────────────┘
现在,您可以分两步完成 - 首先,计算 time 和未来时段 id 之间的链接:
time_periods = ( hourly_data .join(future_periods, how="cross") .filter( pl.col("time") > pl.col("start"), pl.col("time") <p>然后您可以将其与原始数据框连接起来:</p><pre class="brush:py;toolbar:false;">hourly_data.join(time_periods, how="left", on="time").collect()┌──────────────────┬──────┬──────┐│ time ┆ data ┆ id ││ --- ┆ --- ┆ --- ││ str ┆ str ┆ i64 │╞══════════════════╪══════╪══════╡│ 2023-01-01 14:00 ┆ a ┆ 1 ││ 2023-01-02 09:00 ┆ b ┆ null ││ 2023-01-04 11:00 ┆ c ┆ 4 │└──────────────────┴──────┴──────┘
执行此操作的另一种方法可能是使用 duckdb 感谢 与 polars 集成:
import duckdbimport polars as plduckdb.sql(""" select h.time, h.data, p.id from hourly_data as h left join future_periods as p on p.start h.time""").pl()┌──────────────────┬──────┬──────┐│ time ┆ data ┆ id ││ --- ┆ --- ┆ --- ││ str ┆ str ┆ i64 │╞══════════════════╪══════╪══════╡│ 2023-01-01 14:00 ┆ A ┆ 1 ││ 2023-01-04 11:00 ┆ C ┆ 4 ││ 2023-01-02 09:00 ┆ B ┆ null │└──────────────────┴──────┴──────┘