Используя поляры .rolling
и .agg
, как мне вернуть исходный столбец без необходимости соединения с исходным столбцом или без использования .over
?
Пример:
import polars as pl
dates = [
"2020-01-01 13:45:48",
"2020-01-01 16:42:13",
"2020-01-01 16:45:09",
"2020-01-02 18:12:48",
"2020-01-03 19:45:32",
"2020-01-08 23:16:43",
]
df = pl.DataFrame({"dt": dates, "a": [3, 7, 5, 9, 2, 1]}).with_columns(
pl.col("dt").str.strptime(pl.Datetime).set_sorted()
)
Предоставляет мне небольшой фрейм данных Polars:
Когда я применяю скользящие агрегаты, я получаю обратно новые столбцы, но не исходные:
out = df.rolling(index_column = "dt", period = "2d").agg(
[
pl.sum("a").alias("sum_a"),
pl.min("a").alias("min_a"),
pl.max("a").alias("max_a"),
pl.col('a')
]
)
который дает:
Как я могу получить исходный столбец. Я не хочу присоединяться и не хочу использовать .over, так как мне понадобится group_by для прокрутки позже, а .over не работает с .rolling
Редактировать. Я также не заинтересован в использовании следующего.
out = df.rolling(index_column = "dt", period = "2d").agg(
[
pl.sum("a").alias("sum_a"),
pl.min("a").alias("min_a"),
pl.max("a").alias("max_a"),
pl.col('a').last().alias('a')
]
)
Изменить 2. Почему Expr.rolling() невозможен и почему мне нужен group_by:
Приведем более подробный пример:
dates = [
"2020-01-01 13:45:48",
"2020-01-01 16:42:13",
"2020-01-01 16:45:09",
"2020-01-02 18:12:48",
"2020-01-03 19:45:32",
"2020-01-08 23:16:43",
]
df_a = pl.DataFrame({"dt": dates, "a": [3, 7, 5, 9, 2, 1],'cat':['one']*6}).with_columns(
pl.col("dt").str.strptime(pl.Datetime).set_sorted()
)
df_b = pl.DataFrame({"dt": dates, "a": [3, 7, 5, 9, 2, 1],'cat':['two']*6}).with_columns(
pl.col("dt").str.strptime(pl.Datetime).set_sorted()
)
df = pl.concat([df_a,df_b])
и код:
out = df.rolling(index_column = "dt", period = "2d",group_by='cat').agg(
[
pl.sum("a").alias("sum_a"),
pl.min("a").alias("min_a"),
pl.max("a").alias("max_a"),
pl.col('a')
]
)
Это не работает:
df.sort('dt').with_columns(sum=pl.sum("a").rolling(index_column = "dt", period = "2d").over(["cat"]))
Дает:
InvalidOperationError: rolling expression not allowed in aggregation
Мне кажется странным, что мне нужно сделать еще одну операцию (.last
), чтобы получить то, что у меня уже было вначале. Я предполагаю, что есть какой-то способ сделать pl.exclude()
или что-то в этом роде...
Тогда почему возникают проблемы с присоединением?
Вы можете использовать pl.exclude("cols", "to", "exclude").last()
, чтобы сохранить все неисключенные столбцы. Такое поведение соответствует pl.DataFrame.group_by().agg()
, поскольку сохраняются только индексные столбцы и столбцы, явно упомянутые в агрегировании.
@mozway Тот же аргумент: зачем мне добавлять что-то, что у меня было вначале? Например, если вы используете scikit-learn ColumnTransformer
, вы можете определить, через что следует пройти. Кажется нелогичным, что вы не можете просто пропустить исходный столбец через IMO.
Существуют специальные rolling_*_by
выражения, например. pl.col("a").rolling_sum_by("dt", "2d").alias("sum_a")
Ты можешь сделать
In [9]: df.with_columns(
...: a_min=pl.col('a').min().rolling('dt', period='2d'),
...: a_max=pl.col('a').max().rolling('dt', period='2d'),
...: a_sum=pl.col('a').sum().rolling('dt', period='2d'),
...: )
shape: (6, 5)
┌─────────────────────┬─────┬───────┬───────┬───────┐
│ dt ┆ a ┆ a_min ┆ a_max ┆ a_sum │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ datetime[μs] ┆ i64 ┆ i64 ┆ i64 ┆ i64 │
╞═════════════════════╪═════╪═══════╪═══════╪═══════╡
│ 2020-01-01 13:45:48 ┆ 3 ┆ 3 ┆ 3 ┆ 3 │
│ 2020-01-01 16:42:13 ┆ 7 ┆ 3 ┆ 7 ┆ 10 │
│ 2020-01-01 16:45:09 ┆ 5 ┆ 3 ┆ 7 ┆ 15 │
│ 2020-01-02 18:12:48 ┆ 9 ┆ 3 ┆ 9 ┆ 24 │
│ 2020-01-03 19:45:32 ┆ 2 ┆ 2 ┆ 9 ┆ 11 │
│ 2020-01-08 23:16:43 ┆ 1 ┆ 1 ┆ 1 ┆ 1 │
└─────────────────────┴─────┴───────┴───────┴───────┘
Альтернативно (и, вероятно, более эффективно):
In [16]: df.with_columns(
...: a_min=pl.col('a').rolling_min_by('dt', '2d'),
...: a_max=pl.col('a').rolling_max_by('dt', '2d'),
...: a_sum=pl.col('a').rolling_sum_by('dt', '2d'),
...: )
Out[16]:
shape: (6, 5)
┌─────────────────────┬─────┬───────┬───────┬───────┐
│ dt ┆ a ┆ a_min ┆ a_max ┆ a_sum │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ datetime[μs] ┆ i64 ┆ i64 ┆ i64 ┆ i64 │
╞═════════════════════╪═════╪═══════╪═══════╪═══════╡
│ 2020-01-01 13:45:48 ┆ 3 ┆ 3 ┆ 3 ┆ 3 │
│ 2020-01-01 16:42:13 ┆ 7 ┆ 3 ┆ 7 ┆ 10 │
│ 2020-01-01 16:45:09 ┆ 5 ┆ 3 ┆ 7 ┆ 15 │
│ 2020-01-02 18:12:48 ┆ 9 ┆ 3 ┆ 9 ┆ 24 │
│ 2020-01-03 19:45:32 ┆ 2 ┆ 2 ┆ 9 ┆ 11 │
│ 2020-01-08 23:16:43 ┆ 1 ┆ 1 ┆ 1 ┆ 1 │
└─────────────────────┴─────┴───────┴───────┴───────┘
здесь используется выражение .rolling
, в котором нет group_by
, который мне нужен (для реального кода, а не для этого простого примера).
Вместо этого вы можете использовать Expr.rolling():
aggs = [(pl.min, '_min'), (pl.max, '_max'), (pl.sum, '_sum')]
df.with_columns(
cfunc('a').rolling('dt', period='2d').name.suffix(csuf) for cfunc, csuf in aggs
)
┌─────────────────────┬─────┬───────┬───────┬───────┐
│ dt ┆ a ┆ a_min ┆ a_max ┆ a_sum │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ datetime[μs] ┆ i64 ┆ i64 ┆ i64 ┆ i64 │
╞═════════════════════╪═════╪═══════╪═══════╪═══════╡
│ 2020-01-01 13:45:48 ┆ 3 ┆ 3 ┆ 3 ┆ 3 │
│ 2020-01-01 16:42:13 ┆ 7 ┆ 3 ┆ 7 ┆ 10 │
│ 2020-01-01 16:45:09 ┆ 5 ┆ 3 ┆ 7 ┆ 15 │
│ 2020-01-02 18:12:48 ┆ 9 ┆ 3 ┆ 9 ┆ 24 │
│ 2020-01-03 19:45:32 ┆ 2 ┆ 2 ┆ 9 ┆ 11 │
│ 2020-01-08 23:16:43 ┆ 1 ┆ 1 ┆ 1 ┆ 1 │
└─────────────────────┴─────┴───────┴───────┴───────┘
Редактировать:
Я думаю, что вам нужно использовать rolling(...).over(...)
, но, к сожалению, он пока не поддерживается.
Однако на это есть открытый запрос.
Если вы можете жить с использованием last()
, я бы пока сделал это.
Мне нужен group_by
из Dataframe.rolling()
, так как .over
не работает с Expr.rolling()
Было бы проще, если бы вы расширили свой пример, чтобы показать, почему предложенные решения (и исходное) не работают.
Хорошо, я расширил пример.
Существуют специальные выражения rolling_*_by , которые можно использовать с .over()
df.with_columns(
pl.col("a").rolling_sum_by("dt", "2d").over("cat").name.prefix("sum_"),
pl.col("a").rolling_min_by("dt", "2d").over("cat").name.prefix("min_"),
pl.col("a").rolling_max_by("dt", "2d").over("cat").name.prefix("max_")
)
shape: (12, 6)
┌─────────────────────┬─────┬─────┬───────┬───────┬───────┐
│ dt ┆ a ┆ cat ┆ sum_a ┆ min_a ┆ max_a │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ datetime[μs] ┆ i64 ┆ str ┆ i64 ┆ i64 ┆ i64 │
╞═════════════════════╪═════╪═════╪═══════╪═══════╪═══════╡
│ 2020-01-01 13:45:48 ┆ 3 ┆ one ┆ 3 ┆ 3 ┆ 3 │
│ 2020-01-01 16:42:13 ┆ 7 ┆ one ┆ 10 ┆ 3 ┆ 7 │
│ 2020-01-01 16:45:09 ┆ 5 ┆ one ┆ 15 ┆ 3 ┆ 7 │
│ 2020-01-02 18:12:48 ┆ 9 ┆ one ┆ 24 ┆ 3 ┆ 9 │
│ 2020-01-03 19:45:32 ┆ 2 ┆ one ┆ 11 ┆ 2 ┆ 9 │
│ … ┆ … ┆ … ┆ … ┆ … ┆ … │
│ 2020-01-01 16:42:13 ┆ 7 ┆ two ┆ 10 ┆ 3 ┆ 7 │
│ 2020-01-01 16:45:09 ┆ 5 ┆ two ┆ 15 ┆ 3 ┆ 7 │
│ 2020-01-02 18:12:48 ┆ 9 ┆ two ┆ 24 ┆ 3 ┆ 9 │
│ 2020-01-03 19:45:32 ┆ 2 ┆ two ┆ 11 ┆ 2 ┆ 9 │
│ 2020-01-08 23:16:43 ┆ 1 ┆ two ┆ 1 ┆ 1 ┆ 1 │
└─────────────────────┴─────┴─────┴───────┴───────┴───────┘
Я использую Polar 20.23, и кажется, такого не существует. Какую версию вы используете?
@Olivier_s_j Я использую 0.20.31
@Olivier_s_j .rolling_sum("2d", by = "dt").over("cat") может работать на старых версиях - не совсем уверен.
Что говорит против использования
pl.col("a").last()
? Мне это кажется идиоматическим.