Question: I am trying to do calculate a dot product between a window and a static array for all windows in my polars DataFrame and I am struggling to figure out the right way to do this. Anyone here have any hints for me? Here is a quick working example: import polars as pl import numpy as np dummy_data = { "id_": [1, 2, 3, 4, 5, 6, 7, 8], "value": [1, 1, 2, 2, 3, 3, 4, 4] } const = np.array([.5, .5]) df_ = pl.DataFrame(dummy_data) df_ = df_.set_sorted("id_") # This panics: Cannot apply operation on arrays of different lengths df_.rolling("id_", period="2i").agg(pl.col("value").dot(pl.lit(const))) expected = { "id_": [1, 2, 3, 4, 5, 6, 7, 8], "value": [None, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0] }  What I expect is for the following calculations to happen given my example above: np.dot([1.0, 1.0], const) np.dot([1.0, 2.0], const) np.dot([2.0, 2.0], const) etc.  Presumably this doesn't work because the first window only has 1 value instead of 2? At least that is what it seems like to me. Anyone have a better way to do this?

Answer: After receiving a few answers, and finding one of my own, I wanted to share some benchmarks. Here are 3 potential solutions to the problem (adjusted slightly to provide a more comprehensive look at the questions by adding a group column): Data: groups = [] for i in range(n): for j in range(m): groups.append(i) dummy_data = { "id_": list(range(0, m)) * n, "group": groups, "value": [random.randint(1, 50) / 100 for _ in range(n*m)] } vec = np.array([random.randint(1, 100) / 100 for _ in range(x)]) df_ = pl.DataFrame(dummy_data) df_ = df_.sort("id_")  rolling_map courteous of ranc on the polars discord: df_.with_columns( pl.col("value").cast(pl.Float32).rolling_map( lambda x: sum([x[i]*vec[i] for i in range(len(x))]) , window_size=len(vec) ).over("group") )  rolling courteous of @DeanMacGregor: ( df_.lazy() .drop('value') .join( df_.lazy() .rolling("id_", by="group", period=f"{len(vec)}i") .agg(pl.col("value")) .filter(pl.col('value').list.len()==len(vec)) .with_row_count('i') .with_columns(const=pl.Series(vec).implode()) .explode('value', 'const') .group_by('i') .agg( id_=pl.col('id_').first(), group=pl.col("group").first(), value=(pl.col('value').cast(pl.Float64)).dot(pl.col('const')) ) .drop('i'), on=['id_', "group"], how='left' ) ).collect()  shift which is the solution I came up with: df_.lazy().with_columns( res = pl.sum_horizontal([pl.col("value").shift(i).over("group") * vec[i] for i in range(len(vec))]) ).select( "id_", pl.when(pl.col("id_") < len(vec)) .then(None) .otherwise(pl.col("res")) .alias("res") ).collect()  Each provide the exact same answers. Here are the compute times for each on several different sizes of dataset: ################### n=10 m=10 x=2 rolling_map: 826 µs ± 96.6 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each) rolling: 387 µs ± 46.1 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each) shift: 160 µs ± 6.37 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each) ################### n=10000 m=10 x=10 rolling_map: 119 ms ± 2.18 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) rolling: 8.22 ms ± 170 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) shift: 24.3 ms ± 1.26 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) ################### n=10 m=10000 x=10 rolling_map: 1.01 s ± 7.18 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) rolling: 25.5 ms ± 318 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) shift: 5.3 ms ± 119 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) ################### n=1000 m=1000 x=100 rolling_map: > 60 seconds rolling: 2.34 s ± 225 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) shift: 731 ms ± 28.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) ###################  Hopefully these numbers are useful if others need to run some computation similar to this. The correct choice depends on the data being used and the perceived readability of the code.