diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index 7c9b69d80836..eb2e872d666f 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -5379,7 +5379,6 @@ def group_by_dynamic( Examples -------- >>> from datetime import datetime - >>> # create an example dataframe >>> df = pl.DataFrame( ... { ... "time": pl.datetime_range( @@ -5409,129 +5408,107 @@ def group_by_dynamic( Group by windows of 1 hour starting at 2021-12-16 00:00:00. - >>> df.group_by_dynamic("time", every="1h", closed="right").agg( - ... [ - ... pl.col("time").min().alias("time_min"), - ... pl.col("time").max().alias("time_max"), - ... ] - ... ) - shape: (4, 3) - ┌─────────────────────┬─────────────────────┬─────────────────────┐ - │ time ┆ time_min ┆ time_max │ - │ --- ┆ --- ┆ --- │ - │ datetime[μs] ┆ datetime[μs] ┆ datetime[μs] │ - ╞═════════════════════╪═════════════════════╪═════════════════════╡ - │ 2021-12-15 23:00:00 ┆ 2021-12-16 00:00:00 ┆ 2021-12-16 00:00:00 │ - │ 2021-12-16 00:00:00 ┆ 2021-12-16 00:30:00 ┆ 2021-12-16 01:00:00 │ - │ 2021-12-16 01:00:00 ┆ 2021-12-16 01:30:00 ┆ 2021-12-16 02:00:00 │ - │ 2021-12-16 02:00:00 ┆ 2021-12-16 02:30:00 ┆ 2021-12-16 03:00:00 │ - └─────────────────────┴─────────────────────┴─────────────────────┘ + >>> df.group_by_dynamic("time", every="1h", closed="right").agg(pl.col("n")) + shape: (4, 2) + ┌─────────────────────┬───────────┐ + │ time ┆ n │ + │ --- ┆ --- │ + │ datetime[μs] ┆ list[i64] │ + ╞═════════════════════╪═══════════╡ + │ 2021-12-15 23:00:00 ┆ [0] │ + │ 2021-12-16 00:00:00 ┆ [1, 2] │ + │ 2021-12-16 01:00:00 ┆ [3, 4] │ + │ 2021-12-16 02:00:00 ┆ [5, 6] │ + └─────────────────────┴───────────┘ The window boundaries can also be added to the aggregation result >>> df.group_by_dynamic( ... "time", every="1h", include_boundaries=True, closed="right" - ... ).agg([pl.col("time").count().alias("time_count")]) + ... ).agg(pl.col("n").mean()) shape: (4, 4) - ┌─────────────────────┬─────────────────────┬─────────────────────┬────────────┐ - │ _lower_boundary ┆ _upper_boundary ┆ time ┆ time_count │ - │ --- ┆ --- ┆ --- ┆ --- │ - │ datetime[μs] ┆ datetime[μs] ┆ datetime[μs] ┆ u32 │ - ╞═════════════════════╪═════════════════════╪═════════════════════╪════════════╡ - │ 2021-12-15 23:00:00 ┆ 2021-12-16 00:00:00 ┆ 2021-12-15 23:00:00 ┆ 1 │ - │ 2021-12-16 00:00:00 ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 00:00:00 ┆ 2 │ - │ 2021-12-16 01:00:00 ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 01:00:00 ┆ 2 │ - │ 2021-12-16 02:00:00 ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 02:00:00 ┆ 2 │ - └─────────────────────┴─────────────────────┴─────────────────────┴────────────┘ - - When closed="left", should not include right end of interval + ┌─────────────────────┬─────────────────────┬─────────────────────┬─────┐ + │ _lower_boundary ┆ _upper_boundary ┆ time ┆ n │ + │ --- ┆ --- ┆ --- ┆ --- │ + │ datetime[μs] ┆ datetime[μs] ┆ datetime[μs] ┆ f64 │ + ╞═════════════════════╪═════════════════════╪═════════════════════╪═════╡ + │ 2021-12-15 23:00:00 ┆ 2021-12-16 00:00:00 ┆ 2021-12-15 23:00:00 ┆ 0.0 │ + │ 2021-12-16 00:00:00 ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 00:00:00 ┆ 1.5 │ + │ 2021-12-16 01:00:00 ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 01:00:00 ┆ 3.5 │ + │ 2021-12-16 02:00:00 ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 02:00:00 ┆ 5.5 │ + └─────────────────────┴─────────────────────┴─────────────────────┴─────┘ + + When closed="left", the window excludes the right end of interval: [lower_bound, upper_bound) - >>> df.group_by_dynamic("time", every="1h", closed="left").agg( - ... [ - ... pl.col("time").count().alias("time_count"), - ... pl.col("time").alias("time_agg_list"), - ... ] - ... ) - shape: (4, 3) - ┌─────────────────────┬────────────┬───────────────────────────────────┐ - │ time ┆ time_count ┆ time_agg_list │ - │ --- ┆ --- ┆ --- │ - │ datetime[μs] ┆ u32 ┆ list[datetime[μs]] │ - ╞═════════════════════╪════════════╪═══════════════════════════════════╡ - │ 2021-12-16 00:00:00 ┆ 2 ┆ [2021-12-16 00:00:00, 2021-12-16… │ - │ 2021-12-16 01:00:00 ┆ 2 ┆ [2021-12-16 01:00:00, 2021-12-16… │ - │ 2021-12-16 02:00:00 ┆ 2 ┆ [2021-12-16 02:00:00, 2021-12-16… │ - │ 2021-12-16 03:00:00 ┆ 1 ┆ [2021-12-16 03:00:00] │ - └─────────────────────┴────────────┴───────────────────────────────────┘ + >>> df.group_by_dynamic("time", every="1h", closed="left").agg(pl.col("n")) + shape: (4, 2) + ┌─────────────────────┬───────────┐ + │ time ┆ n │ + │ --- ┆ --- │ + │ datetime[μs] ┆ list[i64] │ + ╞═════════════════════╪═══════════╡ + │ 2021-12-16 00:00:00 ┆ [0, 1] │ + │ 2021-12-16 01:00:00 ┆ [2, 3] │ + │ 2021-12-16 02:00:00 ┆ [4, 5] │ + │ 2021-12-16 03:00:00 ┆ [6] │ + └─────────────────────┴───────────┘ When closed="both" the time values at the window boundaries belong to 2 groups. - >>> df.group_by_dynamic("time", every="1h", closed="both").agg( - ... [pl.col("time").count().alias("time_count")] - ... ) + >>> df.group_by_dynamic("time", every="1h", closed="both").agg(pl.col("n")) shape: (5, 2) - ┌─────────────────────┬────────────┐ - │ time ┆ time_count │ - │ --- ┆ --- │ - │ datetime[μs] ┆ u32 │ - ╞═════════════════════╪════════════╡ - │ 2021-12-15 23:00:00 ┆ 1 │ - │ 2021-12-16 00:00:00 ┆ 3 │ - │ 2021-12-16 01:00:00 ┆ 3 │ - │ 2021-12-16 02:00:00 ┆ 3 │ - │ 2021-12-16 03:00:00 ┆ 1 │ - └─────────────────────┴────────────┘ + ┌─────────────────────┬───────────┐ + │ time ┆ n │ + │ --- ┆ --- │ + │ datetime[μs] ┆ list[i64] │ + ╞═════════════════════╪═══════════╡ + │ 2021-12-15 23:00:00 ┆ [0] │ + │ 2021-12-16 00:00:00 ┆ [0, 1, 2] │ + │ 2021-12-16 01:00:00 ┆ [2, 3, 4] │ + │ 2021-12-16 02:00:00 ┆ [4, 5, 6] │ + │ 2021-12-16 03:00:00 ┆ [6] │ + └─────────────────────┴───────────┘ Dynamic group bys can also be combined with grouping on normal keys - >>> df = pl.DataFrame( - ... { - ... "time": pl.datetime_range( - ... start=datetime(2021, 12, 16), - ... end=datetime(2021, 12, 16, 3), - ... interval="30m", - ... eager=True, - ... ), - ... "groups": ["a", "a", "a", "b", "b", "a", "a"], - ... } - ... ) + >>> df = df.with_columns(groups=pl.Series(["a", "a", "a", "b", "b", "a", "a"])) >>> df - shape: (7, 2) - ┌─────────────────────┬────────┐ - │ time ┆ groups │ - │ --- ┆ --- │ - │ datetime[μs] ┆ str │ - ╞═════════════════════╪════════╡ - │ 2021-12-16 00:00:00 ┆ a │ - │ 2021-12-16 00:30:00 ┆ a │ - │ 2021-12-16 01:00:00 ┆ a │ - │ 2021-12-16 01:30:00 ┆ b │ - │ 2021-12-16 02:00:00 ┆ b │ - │ 2021-12-16 02:30:00 ┆ a │ - │ 2021-12-16 03:00:00 ┆ a │ - └─────────────────────┴────────┘ + shape: (7, 3) + ┌─────────────────────┬─────┬────────┐ + │ time ┆ n ┆ groups │ + │ --- ┆ --- ┆ --- │ + │ datetime[μs] ┆ i64 ┆ str │ + ╞═════════════════════╪═════╪════════╡ + │ 2021-12-16 00:00:00 ┆ 0 ┆ a │ + │ 2021-12-16 00:30:00 ┆ 1 ┆ a │ + │ 2021-12-16 01:00:00 ┆ 2 ┆ a │ + │ 2021-12-16 01:30:00 ┆ 3 ┆ b │ + │ 2021-12-16 02:00:00 ┆ 4 ┆ b │ + │ 2021-12-16 02:30:00 ┆ 5 ┆ a │ + │ 2021-12-16 03:00:00 ┆ 6 ┆ a │ + └─────────────────────┴─────┴────────┘ >>> df.group_by_dynamic( ... "time", ... every="1h", ... closed="both", ... by="groups", ... include_boundaries=True, - ... ).agg([pl.col("time").count().alias("time_count")]) + ... ).agg(pl.col("n")) shape: (7, 5) - ┌────────┬─────────────────────┬─────────────────────┬─────────────────────┬────────────┐ - │ groups ┆ _lower_boundary ┆ _upper_boundary ┆ time ┆ time_count │ - │ --- ┆ --- ┆ --- ┆ --- ┆ --- │ - │ str ┆ datetime[μs] ┆ datetime[μs] ┆ datetime[μs] ┆ u32 │ - ╞════════╪═════════════════════╪═════════════════════╪═════════════════════╪════════════╡ - │ a ┆ 2021-12-15 23:00:00 ┆ 2021-12-16 00:00:00 ┆ 2021-12-15 23:00:00 ┆ 1 │ - │ a ┆ 2021-12-16 00:00:00 ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 00:00:00 ┆ 3 │ - │ a ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 01:00:00 ┆ 1 │ - │ a ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 02:00:00 ┆ 2 │ - │ a ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 04:00:00 ┆ 2021-12-16 03:00:00 ┆ 1 │ - │ b ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 01:00:00 ┆ 2 │ - │ b ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 02:00:00 ┆ 1 │ - └────────┴─────────────────────┴─────────────────────┴─────────────────────┴────────────┘ + ┌────────┬─────────────────────┬─────────────────────┬─────────────────────┬───────────┐ + │ groups ┆ _lower_boundary ┆ _upper_boundary ┆ time ┆ n │ + │ --- ┆ --- ┆ --- ┆ --- ┆ --- │ + │ str ┆ datetime[μs] ┆ datetime[μs] ┆ datetime[μs] ┆ list[i64] │ + ╞════════╪═════════════════════╪═════════════════════╪═════════════════════╪═══════════╡ + │ a ┆ 2021-12-15 23:00:00 ┆ 2021-12-16 00:00:00 ┆ 2021-12-15 23:00:00 ┆ [0] │ + │ a ┆ 2021-12-16 00:00:00 ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 00:00:00 ┆ [0, 1, 2] │ + │ a ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 01:00:00 ┆ [2] │ + │ a ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 02:00:00 ┆ [5, 6] │ + │ a ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 04:00:00 ┆ 2021-12-16 03:00:00 ┆ [6] │ + │ b ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 01:00:00 ┆ [3, 4] │ + │ b ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 02:00:00 ┆ [4] │ + └────────┴─────────────────────┴─────────────────────┴─────────────────────┴───────────┘ Dynamic group by on an index column diff --git a/py-polars/polars/lazyframe/frame.py b/py-polars/polars/lazyframe/frame.py index 5b41e75827f2..acd4bcd2d266 100644 --- a/py-polars/polars/lazyframe/frame.py +++ b/py-polars/polars/lazyframe/frame.py @@ -3071,7 +3071,6 @@ def group_by_dynamic( Examples -------- >>> from datetime import datetime - >>> # create an example dataframe >>> lf = pl.LazyFrame( ... { ... "time": pl.datetime_range( @@ -3102,130 +3101,112 @@ def group_by_dynamic( Group by windows of 1 hour starting at 2021-12-16 00:00:00. >>> lf.group_by_dynamic("time", every="1h", closed="right").agg( - ... [ - ... pl.col("time").min().alias("time_min"), - ... pl.col("time").max().alias("time_max"), - ... ] + ... pl.col("n") ... ).collect() - shape: (4, 3) - ┌─────────────────────┬─────────────────────┬─────────────────────┐ - │ time ┆ time_min ┆ time_max │ - │ --- ┆ --- ┆ --- │ - │ datetime[μs] ┆ datetime[μs] ┆ datetime[μs] │ - ╞═════════════════════╪═════════════════════╪═════════════════════╡ - │ 2021-12-15 23:00:00 ┆ 2021-12-16 00:00:00 ┆ 2021-12-16 00:00:00 │ - │ 2021-12-16 00:00:00 ┆ 2021-12-16 00:30:00 ┆ 2021-12-16 01:00:00 │ - │ 2021-12-16 01:00:00 ┆ 2021-12-16 01:30:00 ┆ 2021-12-16 02:00:00 │ - │ 2021-12-16 02:00:00 ┆ 2021-12-16 02:30:00 ┆ 2021-12-16 03:00:00 │ - └─────────────────────┴─────────────────────┴─────────────────────┘ + shape: (4, 2) + ┌─────────────────────┬───────────┐ + │ time ┆ n │ + │ --- ┆ --- │ + │ datetime[μs] ┆ list[i64] │ + ╞═════════════════════╪═══════════╡ + │ 2021-12-15 23:00:00 ┆ [0] │ + │ 2021-12-16 00:00:00 ┆ [1, 2] │ + │ 2021-12-16 01:00:00 ┆ [3, 4] │ + │ 2021-12-16 02:00:00 ┆ [5, 6] │ + └─────────────────────┴───────────┘ The window boundaries can also be added to the aggregation result >>> lf.group_by_dynamic( ... "time", every="1h", include_boundaries=True, closed="right" - ... ).agg([pl.col("time").count().alias("time_count")]).collect() + ... ).agg(pl.col("n").mean()).collect() shape: (4, 4) - ┌─────────────────────┬─────────────────────┬─────────────────────┬────────────┐ - │ _lower_boundary ┆ _upper_boundary ┆ time ┆ time_count │ - │ --- ┆ --- ┆ --- ┆ --- │ - │ datetime[μs] ┆ datetime[μs] ┆ datetime[μs] ┆ u32 │ - ╞═════════════════════╪═════════════════════╪═════════════════════╪════════════╡ - │ 2021-12-15 23:00:00 ┆ 2021-12-16 00:00:00 ┆ 2021-12-15 23:00:00 ┆ 1 │ - │ 2021-12-16 00:00:00 ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 00:00:00 ┆ 2 │ - │ 2021-12-16 01:00:00 ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 01:00:00 ┆ 2 │ - │ 2021-12-16 02:00:00 ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 02:00:00 ┆ 2 │ - └─────────────────────┴─────────────────────┴─────────────────────┴────────────┘ - - When closed="left", should not include right end of interval + ┌─────────────────────┬─────────────────────┬─────────────────────┬─────┐ + │ _lower_boundary ┆ _upper_boundary ┆ time ┆ n │ + │ --- ┆ --- ┆ --- ┆ --- │ + │ datetime[μs] ┆ datetime[μs] ┆ datetime[μs] ┆ f64 │ + ╞═════════════════════╪═════════════════════╪═════════════════════╪═════╡ + │ 2021-12-15 23:00:00 ┆ 2021-12-16 00:00:00 ┆ 2021-12-15 23:00:00 ┆ 0.0 │ + │ 2021-12-16 00:00:00 ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 00:00:00 ┆ 1.5 │ + │ 2021-12-16 01:00:00 ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 01:00:00 ┆ 3.5 │ + │ 2021-12-16 02:00:00 ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 02:00:00 ┆ 5.5 │ + └─────────────────────┴─────────────────────┴─────────────────────┴─────┘ + + When closed="left", the window excludes the right end of interval: [lower_bound, upper_bound) >>> lf.group_by_dynamic("time", every="1h", closed="left").agg( - ... [ - ... pl.col("time").count().alias("time_count"), - ... pl.col("time").alias("time_agg_list"), - ... ] + ... pl.col("n") ... ).collect() - shape: (4, 3) - ┌─────────────────────┬────────────┬───────────────────────────────────┐ - │ time ┆ time_count ┆ time_agg_list │ - │ --- ┆ --- ┆ --- │ - │ datetime[μs] ┆ u32 ┆ list[datetime[μs]] │ - ╞═════════════════════╪════════════╪═══════════════════════════════════╡ - │ 2021-12-16 00:00:00 ┆ 2 ┆ [2021-12-16 00:00:00, 2021-12-16… │ - │ 2021-12-16 01:00:00 ┆ 2 ┆ [2021-12-16 01:00:00, 2021-12-16… │ - │ 2021-12-16 02:00:00 ┆ 2 ┆ [2021-12-16 02:00:00, 2021-12-16… │ - │ 2021-12-16 03:00:00 ┆ 1 ┆ [2021-12-16 03:00:00] │ - └─────────────────────┴────────────┴───────────────────────────────────┘ + shape: (4, 2) + ┌─────────────────────┬───────────┐ + │ time ┆ n │ + │ --- ┆ --- │ + │ datetime[μs] ┆ list[i64] │ + ╞═════════════════════╪═══════════╡ + │ 2021-12-16 00:00:00 ┆ [0, 1] │ + │ 2021-12-16 01:00:00 ┆ [2, 3] │ + │ 2021-12-16 02:00:00 ┆ [4, 5] │ + │ 2021-12-16 03:00:00 ┆ [6] │ + └─────────────────────┴───────────┘ When closed="both" the time values at the window boundaries belong to 2 groups. >>> lf.group_by_dynamic("time", every="1h", closed="both").agg( - ... pl.col("time").count().alias("time_count") + ... pl.col("n") ... ).collect() shape: (5, 2) - ┌─────────────────────┬────────────┐ - │ time ┆ time_count │ - │ --- ┆ --- │ - │ datetime[μs] ┆ u32 │ - ╞═════════════════════╪════════════╡ - │ 2021-12-15 23:00:00 ┆ 1 │ - │ 2021-12-16 00:00:00 ┆ 3 │ - │ 2021-12-16 01:00:00 ┆ 3 │ - │ 2021-12-16 02:00:00 ┆ 3 │ - │ 2021-12-16 03:00:00 ┆ 1 │ - └─────────────────────┴────────────┘ + ┌─────────────────────┬───────────┐ + │ time ┆ n │ + │ --- ┆ --- │ + │ datetime[μs] ┆ list[i64] │ + ╞═════════════════════╪═══════════╡ + │ 2021-12-15 23:00:00 ┆ [0] │ + │ 2021-12-16 00:00:00 ┆ [0, 1, 2] │ + │ 2021-12-16 01:00:00 ┆ [2, 3, 4] │ + │ 2021-12-16 02:00:00 ┆ [4, 5, 6] │ + │ 2021-12-16 03:00:00 ┆ [6] │ + └─────────────────────┴───────────┘ Dynamic group bys can also be combined with grouping on normal keys - >>> lf = pl.LazyFrame( - ... { - ... "time": pl.datetime_range( - ... start=datetime(2021, 12, 16), - ... end=datetime(2021, 12, 16, 3), - ... interval="30m", - ... eager=True, - ... ), - ... "groups": ["a", "a", "a", "b", "b", "a", "a"], - ... } - ... ) + >>> lf = lf.with_columns(groups=pl.Series(["a", "a", "a", "b", "b", "a", "a"])) >>> lf.collect() - shape: (7, 2) - ┌─────────────────────┬────────┐ - │ time ┆ groups │ - │ --- ┆ --- │ - │ datetime[μs] ┆ str │ - ╞═════════════════════╪════════╡ - │ 2021-12-16 00:00:00 ┆ a │ - │ 2021-12-16 00:30:00 ┆ a │ - │ 2021-12-16 01:00:00 ┆ a │ - │ 2021-12-16 01:30:00 ┆ b │ - │ 2021-12-16 02:00:00 ┆ b │ - │ 2021-12-16 02:30:00 ┆ a │ - │ 2021-12-16 03:00:00 ┆ a │ - └─────────────────────┴────────┘ - >>> ( - ... lf.group_by_dynamic( - ... "time", - ... every="1h", - ... closed="both", - ... by="groups", - ... include_boundaries=True, - ... ) - ... ).agg([pl.col("time").count().alias("time_count")]).collect() + shape: (7, 3) + ┌─────────────────────┬─────┬────────┐ + │ time ┆ n ┆ groups │ + │ --- ┆ --- ┆ --- │ + │ datetime[μs] ┆ i64 ┆ str │ + ╞═════════════════════╪═════╪════════╡ + │ 2021-12-16 00:00:00 ┆ 0 ┆ a │ + │ 2021-12-16 00:30:00 ┆ 1 ┆ a │ + │ 2021-12-16 01:00:00 ┆ 2 ┆ a │ + │ 2021-12-16 01:30:00 ┆ 3 ┆ b │ + │ 2021-12-16 02:00:00 ┆ 4 ┆ b │ + │ 2021-12-16 02:30:00 ┆ 5 ┆ a │ + │ 2021-12-16 03:00:00 ┆ 6 ┆ a │ + └─────────────────────┴─────┴────────┘ + >>> lf.group_by_dynamic( + ... "time", + ... every="1h", + ... closed="both", + ... by="groups", + ... include_boundaries=True, + ... ).agg(pl.col("n")).collect() shape: (7, 5) - ┌────────┬─────────────────────┬─────────────────────┬─────────────────────┬────────────┐ - │ groups ┆ _lower_boundary ┆ _upper_boundary ┆ time ┆ time_count │ - │ --- ┆ --- ┆ --- ┆ --- ┆ --- │ - │ str ┆ datetime[μs] ┆ datetime[μs] ┆ datetime[μs] ┆ u32 │ - ╞════════╪═════════════════════╪═════════════════════╪═════════════════════╪════════════╡ - │ a ┆ 2021-12-15 23:00:00 ┆ 2021-12-16 00:00:00 ┆ 2021-12-15 23:00:00 ┆ 1 │ - │ a ┆ 2021-12-16 00:00:00 ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 00:00:00 ┆ 3 │ - │ a ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 01:00:00 ┆ 1 │ - │ a ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 02:00:00 ┆ 2 │ - │ a ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 04:00:00 ┆ 2021-12-16 03:00:00 ┆ 1 │ - │ b ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 01:00:00 ┆ 2 │ - │ b ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 02:00:00 ┆ 1 │ - └────────┴─────────────────────┴─────────────────────┴─────────────────────┴────────────┘ + ┌────────┬─────────────────────┬─────────────────────┬─────────────────────┬───────────┐ + │ groups ┆ _lower_boundary ┆ _upper_boundary ┆ time ┆ n │ + │ --- ┆ --- ┆ --- ┆ --- ┆ --- │ + │ str ┆ datetime[μs] ┆ datetime[μs] ┆ datetime[μs] ┆ list[i64] │ + ╞════════╪═════════════════════╪═════════════════════╪═════════════════════╪═══════════╡ + │ a ┆ 2021-12-15 23:00:00 ┆ 2021-12-16 00:00:00 ┆ 2021-12-15 23:00:00 ┆ [0] │ + │ a ┆ 2021-12-16 00:00:00 ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 00:00:00 ┆ [0, 1, 2] │ + │ a ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 01:00:00 ┆ [2] │ + │ a ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 02:00:00 ┆ [5, 6] │ + │ a ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 04:00:00 ┆ 2021-12-16 03:00:00 ┆ [6] │ + │ b ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 01:00:00 ┆ [3, 4] │ + │ b ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 02:00:00 ┆ [4] │ + └────────┴─────────────────────┴─────────────────────┴─────────────────────┴───────────┘ Dynamic group by on an index column