Question: I am learning polars, having come from pandas. In pandas land, I frequently operate on 2 dataframes, each with a datetime index, and the same columns. Example: df1 = pd.DataFrame(data={ 'time': pd.date_range('2023-01-01', periods=n, freq='1 min'), 'foo': np.random.uniform(0,127, size=n).astype(np.float64), 'bar': np.random.uniform(1e3,32767, size=n).astype(np.float64), 'baz': np.random.uniform(1e6,2147483, size=n).astype(np.float64) }).set_index('time') df2 = pd.DataFrame(data={ 'time': pd.date_range('2023-01-01', periods=n, freq='1 min'), 'foo': np.random.uniform(0,127, size=n).astype(np.float64), 'bar': np.random.uniform(1e3,32767, size=n).astype(np.float64), 'baz': np.random.uniform(1e6,2147483, size=n).astype(np.float64) }).set_index('time')  To calculate the product of the columns I can do the following: df1 * df2   foo bar baz time 2023-01-01 00:00:00 8720.704791 1.632745e+08 2.276452e+12 2023-01-01 00:01:00 310.271257 3.375341e+08 2.195998e+12 2023-01-01 00:02:00 2936.646429 5.506997e+08 2.005228e+12 2023-01-01 00:03:00 12342.312737 3.383745e+08 3.779531e+12 2023-01-01 00:04:00 382.163185 1.371315e+08 1.529299e+12  The index remains the same, and each column in dataframe 1 is multiplied by its respective column in dataframe 2. I am now trying to do the same with polars LazyFrames. Here is the polars LazyFrame equivalent to my pandas dataframes above: df1 = pl.DataFrame(data={ 'time': pd.date_range('2023-01-01', periods=n, freq='1 min'), 'foo': np.random.uniform(0,127, size= n).astype(np.float64), 'bar': np.random.uniform(1e3,32767, size= n).astype(np.float64), 'baz': np.random.uniform(1e6,2147483, size= n).astype(np.float64) }).lazy() df2 = pl.DataFrame(data={ 'time': pd.date_range('2023-01-01', periods=n, freq='1 min'), 'foo': np.random.uniform(0,127, size= n).astype(np.float64), 'bar': np.random.uniform(1e3,32767, size= n).astype(np.float64), 'baz': np.random.uniform(1e6,2147483, size= n).astype(np.float64) }).lazy()  I believe the correct way to operate on these 2 LazyFrames is to concat, group_by and then apply some aggregation. However, whilst something like sum works as expected: pl.concat([df1, df2]).group_by('time').sum().sort('time').collect()  time foo bar baz datetime[ns] f64 f64 f64 2023-01-01 00:00:00 117.758176 35887.733953 3.4859e6 2023-01-01 00:01:00 83.828093 32037.128498 3.3425e6 2023-01-01 00:02:00 158.950876 51900.065898 2.1312e6 2023-01-01 00:03:00 90.781075 41924.70712 3.4727e6 2023-01-01 00:04:00 156.831011 34252.423581 3.0899e6  I do not know how to perform a product aggregation Things I have tried:  agg(col('*').mul(col'*'))  pl.concat([df1, df2]).group_by('time').agg(pl.col("*").mul(pl.col("*"))).sort('time').collect()  I'm not even sure what this is doing - it produces a list of values for each column time foo bar baz datetime[ns] list[f64] list[f64] list[f64] 2023-01-01 00:00:00 [12359.923484, 114.893701] [1.3056e8, 4.3358e8] [1.2441e12, 3.0416e12] 2023-01-01 00:01:00 [1212.065713, 15767.846044] [8.9478e8, 8.6531e8] [1.3674e12, 2.0145e12] 2023-01-01 00:02:00 [38.587401, 3658.818448] [7.2488e8, 2.1755e8] [3.6923e12, 1.6436e12] 2023-01-01 00:03:00 [298.835241, 1202.613949] [7.9310e8, 5.6334e8] [1.6880e12, 1.9158e12] 2023-01-01 00:04:00 [11931.488236, 697.035171] [7.1008e7, 1.0676e9] [2.1519e12, 3.2458e12]  How can I perform column-wise multiplication on my 2 dataframes, using time as the index?

Answer: You can create a .struct containing the "non-index" columns. df1.select("time", cols=pl.struct(pl.exclude("time")))  shape: (5, 2) ┌─────────────────────┬───────────────────────────────────┐ │ time ┆ cols │ │ --- ┆ --- │ │ datetime[ns] ┆ struct[3] │ ╞═════════════════════╪═══════════════════════════════════╡ │ 2023-01-01 00:00:00 ┆ {124.263949,27108.741665,1.2177e… │ │ 2023-01-01 00:01:00 ┆ {82.583389,6365.59054,1.5726e6} │ │ 2023-01-01 00:02:00 ┆ {11.729725,14632.406993,1.3759e6… │ │ 2023-01-01 00:03:00 ┆ {84.397273,25237.331443,1.9678e6… │ │ 2023-01-01 00:04:00 ┆ {93.136133,13659.764971,1.9972e6… │ └─────────────────────┴───────────────────────────────────┘  And perform a left-join to align all the values: (df1.select("time", cols=pl.struct(pl.exclude("time"))) .join( df2.select("time", cols=pl.struct(pl.exclude("time"))), on = "time", how = "left" ) )  shape: (5, 3) ┌─────────────────────┬───────────────────────────────────┬───────────────────────────────────┐ │ time ┆ cols ┆ cols_right │ │ --- ┆ --- ┆ --- │ │ datetime[ns] ┆ struct[3] ┆ struct[3] │ ╞═════════════════════╪═══════════════════════════════════╪═══════════════════════════════════╡ │ 2023-01-01 00:00:00 ┆ {124.263949,27108.741665,1.2177e… ┆ {97.580405,5774.836603,1.6745e6} │ │ 2023-01-01 00:01:00 ┆ {82.583389,6365.59054,1.5726e6} ┆ {22.390398,16631.827323,1.4927e6… │ │ 2023-01-01 00:02:00 ┆ {11.729725,14632.406993,1.3759e6… ┆ {116.287397,29089.731203,1.6769e… │ │ 2023-01-01 00:03:00 ┆ {84.397273,25237.331443,1.9678e6… ┆ {70.481321,7588.344937,1.6139e6} │ │ 2023-01-01 00:04:00 ┆ {93.136133,13659.764971,1.9972e6… ┆ {13.712869,27637.512573,1.7183e6… │ └─────────────────────┴───────────────────────────────────┴───────────────────────────────────┘  You can then multiply the structs and .unnest() (df1.select("time", cols=pl.struct(pl.exclude("time"))) .join( df2.select("time", cols=pl.struct(pl.exclude("time"))), on = "time", how = "left" ) .select("time", pl.col("cols") * pl.col("cols_right")) .unnest("cols") )  shape: (5, 4) ┌─────────────────────┬─────────────┬──────────┬───────────┐ │ time ┆ foo ┆ bar ┆ baz │ │ --- ┆ --- ┆ --- ┆ --- │ │ datetime[ns] ┆ f64 ┆ f64 ┆ f64 │ ╞═════════════════════╪═════════════╪══════════╪═══════════╡ │ 2023-01-01 00:00:00 ┆ 12125.72637 ┆ 1.5655e8 ┆ 2.0389e12 │ │ 2023-01-01 00:01:00 ┆ 1849.074903 ┆ 1.0587e8 ┆ 2.3473e12 │ │ 2023-01-01 00:02:00 ┆ 1364.019211 ┆ 4.2565e8 ┆ 2.3072e12 │ │ 2023-01-01 00:03:00 ┆ 5948.43133 ┆ 1.9151e8 ┆ 3.1758e12 │ │ 2023-01-01 00:04:00 ┆ 1277.163612 ┆ 3.7752e8 ┆ 3.4318e12 │ └─────────────────────┴─────────────┴──────────┴───────────┘