У меня есть DataFrame (df
), который содержит столбцы: ID
, Initial Date
, Final Date
и Value
, а также еще один DataFrame (dates
), который содержит все дни для каждого идентификатора из df
.
В кадре данных dates
я хочу суммировать значения, если они существуют в диапазоне каждого ID
.
Вот мой код
import polars as pl
from datetime import datetime
data = {
"ID" : [1, 2, 3, 4, 5],
"Initial Date" : ["2022-01-01", "2022-01-02", "2022-01-03", "2022-01-04", "2022-01-05"],
"Final Date" : ["2022-01-03", "2022-01-06", "2022-01-07", "2022-01-09", "2022-01-07"],
"Value" : [10, 20, 30, 40, 50]
}
df = pl.DataFrame(data)
dates = pl.datetime_range(
start=datetime(2022,1,1),
end=datetime(2022,1,7),
interval = "1d",
eager = True,
closed = "both"
).to_frame("date")
shape: (5, 4)
┌─────┬──────────────┬────────────┬───────┐
│ ID ┆ Initial Date ┆ Final Date ┆ Value │
│ --- ┆ --- ┆ --- ┆ --- │
│ i64 ┆ str ┆ str ┆ i64 │
╞═════╪══════════════╪════════════╪═══════╡
│ 1 ┆ 2022-01-01 ┆ 2022-01-03 ┆ 10 │
│ 2 ┆ 2022-01-02 ┆ 2022-01-06 ┆ 20 │
│ 3 ┆ 2022-01-03 ┆ 2022-01-07 ┆ 30 │
│ 4 ┆ 2022-01-04 ┆ 2022-01-09 ┆ 40 │
│ 5 ┆ 2022-01-05 ┆ 2022-01-07 ┆ 50 │
└─────┴──────────────┴────────────┴───────┘
shape: (7, 1)
┌─────────────────────┐
│ date │
│ --- │
│ datetime[μs] │
╞═════════════════════╡
│ 2022-01-01 00:00:00 │
│ 2022-01-02 00:00:00 │
│ 2022-01-03 00:00:00 │
│ 2022-01-04 00:00:00 │
│ 2022-01-05 00:00:00 │
│ 2022-01-06 00:00:00 │
│ 2022-01-07 00:00:00 │
└─────────────────────┘
В этом случае 01 января 2022 г. это значение будет 10. 02 января 2022 г. оно будет 10 + 20, а 03 января 2022 г. оно будет 10 + 20 + 30 и т. д. . Другими словами, я хочу проверить, существует ли дата в диапазоне каждой строки в DataFrame (df
), и если да, суммировать значения.
Я думаю, что подход к этому такой:
(
dates.with_columns(
pl.sum(
pl.when(
(df["Initial Date"] <= pl.col("date")) & (df["Final Date"] >= pl.col("date"))
).then(df["Value"]).otherwise(0)
).alias("Summed Value")
)
)
Если вы просто хотите узнать сумму значений на каждую дату в диапазонах в df
, вам даже не нужен dates
фрейм данных.
(
df
.with_columns(date = pl.date_ranges("Initial Date", "Final Date"))
.explode("date")
.group_by("date", maintain_order = True)
.agg(pl.col.Value.sum())
)
┌────────────┬───────┐
│ date ┆ Value │
│ --- ┆ --- │
│ date ┆ i64 │
╞════════════╪═══════╡
│ 2022-01-01 ┆ 10 │
│ 2022-01-02 ┆ 30 │
│ 2022-01-03 ┆ 60 │
│ 2022-01-04 ┆ 90 │
│ 2022-01-05 ┆ 140 │
│ 2022-01-06 ┆ 140 │
│ 2022-01-07 ┆ 120 │
│ 2022-01-08 ┆ 40 │
│ 2022-01-09 ┆ 40 │
└────────────┴───────┘
Если вы действительно хотите использовать dates
, вы можете join() получить результат на dates
dataframe:
(
df
.with_columns(date = pl.date_ranges("Initial Date", "Final Date"))
.explode("date")
.group_by("date", maintain_order = True)
.agg(pl.col.Value.sum())
.join(dates, on = "date", how = "semi")
)
┌────────────┬───────┐
│ date ┆ Value │
│ --- ┆ --- │
│ date ┆ i64 │
╞════════════╪═══════╡
│ 2022-01-01 ┆ 10 │
│ 2022-01-02 ┆ 30 │
│ 2022-01-03 ┆ 60 │
│ 2022-01-04 ┆ 90 │
│ 2022-01-05 ┆ 140 │
│ 2022-01-06 ┆ 140 │
│ 2022-01-07 ┆ 120 │
└────────────┴───────┘
Или просто filter() результат:
(
df
.with_columns(date = pl.date_ranges("Initial Date", "Final Date"))
.explode("date")
.group_by("date", maintain_order = True)
.agg(pl.col.Value.sum())
.filter(pl.col.date.is_between(datetime(2022,1,1), datetime(2022,1,7)))
)
┌────────────┬───────┐
│ date ┆ Value │
│ --- ┆ --- │
│ date ┆ i64 │
╞════════════╪═══════╡
│ 2022-01-01 ┆ 10 │
│ 2022-01-02 ┆ 30 │
│ 2022-01-03 ┆ 60 │
│ 2022-01-04 ┆ 90 │
│ 2022-01-05 ┆ 140 │
│ 2022-01-06 ┆ 140 │
│ 2022-01-07 ┆ 120 │
└────────────┴───────┘
Альтернативным решением было бы использовать соединение неравенства, но поляры в этом отношении не очень хороши (пока). Но в этом случае вы можете использовать интеграцию DuckDB с Polars.
duckdb.sql("""
select
d.date,
sum(df.value) as value
from df
inner join dates as d on
d.date between df."Initial Date" and df."Final Date"
group by
d.date
order by
d.date
""").pl()
┌─────────────────────┬───────────────┐
│ date ┆ value │
│ --- ┆ --- │
│ datetime[μs] ┆ decimal[38,0] │
╞═════════════════════╪═══════════════╡
│ 2022-01-01 00:00:00 ┆ 10 │
│ 2022-01-02 00:00:00 ┆ 30 │
│ 2022-01-03 00:00:00 ┆ 60 │
│ 2022-01-04 00:00:00 ┆ 90 │
│ 2022-01-05 00:00:00 ┆ 140 │
│ 2022-01-06 00:00:00 ┆ 140 │
│ 2022-01-07 00:00:00 ┆ 120 │
└─────────────────────┴───────────────┘