Last modified: May 10, 2026 By Alexander Williams

Polars Chaining Expressions Guide

Polars is built for speed and clarity. One of its best features is chaining expressions. You can transform data step by step without messy code. This guide shows you how to use with_columns and select effectively.

Chaining means you apply multiple operations in a single flow. It makes your code easy to read and maintain. Instead of creating many temporary DataFrames, you build a pipeline.

Let's start with a simple example. We create a DataFrame with sales data.


import polars as pl

# Sample sales data
df = pl.DataFrame({
    "product": ["A", "B", "C", "D"],
    "price": [100, 200, 150, 300],
    "quantity": [2, 3, 1, 4]
})

print(df)

shape: (4, 3)
┌─────────┬───────┬──────────┐
│ product ┆ price ┆ quantity │
│ ---     ┆ ---   ┆ ---      │
│ str     ┆ i64   ┆ i64      │
╞═════════╪═══════╪══════════╡
│ A       ┆ 100   ┆ 2        │
│ B       ┆ 200   ┆ 3        │
│ C       ┆ 150   ┆ 1        │
│ D       ┆ 300   ┆ 4        │
└─────────┴───────┴──────────┘

Now we want to add a column for total revenue. We use with_columns.


df_with_revenue = df.with_columns(
    (pl.col("price") * pl.col("quantity")).alias("revenue")
)
print(df_with_revenue)

shape: (4, 4)
┌─────────┬───────┬──────────┬─────────┐
│ product ┆ price ┆ quantity ┆ revenue │
│ ---     ┆ ---   ┆ ---      ┆ ---     │
│ str     ┆ i64   ┆ i64      ┆ i64     │
╞═════════╪═══════╪══════════╪═════════╡
│ A       ┆ 100   ┆ 2        ┆ 200     │
│ B       ┆ 200   ┆ 3        ┆ 600     │
│ C       ┆ 150   ┆ 1        ┆ 150     │
│ D       ┆ 300   ┆ 4        ┆ 1200    │
└─────────┴───────┴──────────┴─────────┘

with_columns keeps all original columns and adds new ones. It is perfect for feature engineering.

Selecting Columns with select

The select method is different. It returns only the columns you specify. Use it to focus on specific data.


selected = df.select(
    pl.col("product"),
    (pl.col("price") * pl.col("quantity")).alias("revenue")
)
print(selected)

shape: (4, 2)
┌─────────┬─────────┐
│ product ┆ revenue │
│ ---     ┆ ---     │
│ str     ┆ i64     │
╞═════════╪═════════╡
│ A       ┆ 200     │
│ B       ┆ 600     │
│ C       ┆ 150     │
│ D       ┆ 1200    │
└─────────┴─────────┘

Notice that price and quantity are gone. select is great for final output or data export.

Chaining Multiple Expressions

You can chain several expressions inside one with_columns or select. This is where Polars shines.

Let's add a discount column and a final price column.


df_chain = df.with_columns(
    (pl.col("price") * 0.1).alias("discount"),
    (pl.col("price") - (pl.col("price") * 0.1)).alias("final_price")
)
print(df_chain)

shape: (4, 5)
┌─────────┬───────┬──────────┬──────────┬─────────────┐
│ product ┆ price ┆ quantity ┆ discount ┆ final_price │
│ ---     ┆ ---   ┆ ---      ┆ ---      ┆ ---         │
│ str     ┆ i64   ┆ i64      ┆ f64      ┆ f64         │
╞═════════╪═══════╪══════════╪══════════╪═════════════╡
│ A       ┆ 100   ┆ 2        ┆ 10.0     ┆ 90.0        │
│ B       ┆ 200   ┆ 3        ┆ 20.0     ┆ 180.0       │
│ C       ┆ 150   ┆ 1        ┆ 15.0     ┆ 135.0       │
│ D       ┆ 300   ┆ 4        ┆ 30.0     ┆ 270.0       │
└─────────┴───────┴──────────┴──────────┴─────────────┘

You can also reference columns created earlier in the same chain. This is not possible in many libraries.


df_chain2 = df.with_columns(
    revenue = pl.col("price") * pl.col("quantity"),
    revenue_with_tax = pl.col("revenue") * 1.2
)
print(df_chain2)

This works because Polars evaluates expressions lazily. It understands dependencies and orders them automatically.

Using select for Aggregations

You can combine select with aggregation functions. This is useful for summary statistics.


summary = df.select(
    pl.sum("price").alias("total_price"),
    pl.mean("quantity").alias("avg_quantity"),
    pl.count("product").alias("product_count")
)
print(summary)

shape: (1, 3)
┌─────────────┬──────────────┬───────────────┐
│ total_price ┆ avg_quantity ┆ product_count │
│ ---         ┆ ---          ┆ ---           │
│ i64         ┆ f64          ┆ u32           │
╞═════════════╪══════════════╪═══════════════╡
│ 750         ┆ 2.5          ┆ 4             │
└─────────────┴──────────────┴───────────────┘

This pattern is common in data reporting. You can chain multiple aggregations in one clean call.

Chaining Methods Together

You can chain with_columns and select with other methods like filter, sort, or group_by. This creates a full data pipeline.


result = (
    df
    .with_columns(
        (pl.col("price") * pl.col("quantity")).alias("revenue")
    )
    .filter(pl.col("revenue") > 300)
    .select(["product", "revenue"])
    .sort("revenue", descending=True)
)
print(result)

shape: (2, 2)
┌─────────┬─────────┐
│ product ┆ revenue │
│ ---     ┆ ---     │
│ str     ┆ i64     │
╞═════════╪═════════╡
│ D       ┆ 1200    │
│ B       ┆ 600     │
└─────────┴─────────┘

Notice the parentheses around the chain. This is a common pattern in Polars. It makes the code read like a story: add revenue, filter, select, sort.

For more complex reshaping, see our guide on Reshape Data in Polars: Pivot, Melt & Transpose.

Performance Tips for Chaining

Polars optimizes chained expressions automatically. It combines operations to reduce memory usage. But you can help it.

Use column references instead of strings when possible. For example, use pl.col("price") instead of "price". This enables better optimization.

Keep your chains focused. Do not mix too many different transformations in one with_columns. Split them logically.

Use select early to drop unnecessary columns. This reduces data size and speeds up later operations.

For joining DataFrames, check our Polars DataFrame Joins & Merges Guide.

Common Mistakes to Avoid

New users often forget that with_columns keeps all columns. If you only want new columns, use select.

Another mistake is using Python loops inside expressions. Avoid apply or list comprehensions. Use native Polars expressions for speed.

Do not reuse column names incorrectly. If you create a column named "price" inside with_columns, it overwrites the old one. Use alias for new names.

For handling missing data, see Handling Null & Missing Values in Polars.

Conclusion

Chaining expressions with with_columns and select is a core skill in Polars. It makes your code clean, fast, and readable. You add columns, transform data, and filter results in a single flow.

Practice with your own data. Start with small chains. Then combine them with other methods. You will see how powerful and elegant Polars can be.

Remember: use with_columns to add columns, use select to choose columns, and chain them for smooth pipelines. Happy coding!