Python Polars Cheatsheet (based on our O'Reilly book)
🚀 Python Polars: The Definitive Cheatsheet
Derived from the O'Reilly publication

Polars is a high-performance library designed for the transformation, analysis, and visualization of data, utilizing a fast and highly expressive DataFrame API.
🛠️ Getting Started
Before diving in, ensure your environment is configured:
- Install Polars with all optional features:
uv pip install "polars[all]" - Initialize the library and verify your environment:
import polars as pl pl.show_versions()
🔄 The Polars Workflow
A typical Polars operation follows a linear pipeline: Read Transform Write. Most queries are constructed as a single, fluid chain of method calls.
# Example: A complete chain
fruit = (
pl.read_parquet("input.parquet")
.filter(pl.col("sales") > 100)
.write_parquet("fruit.parquet")
)
Notation Guide:
df: A standardDataFramelf: ALazyFrameo: A secondaryDataFramefor joins/combinationse: A Polars expression (e.g.,e.abs()refers topl.col("x").abs())
🏗️ Data Structures
Polars organizes data into two primary structures: Series and DataFrames.
Unlike pandas, Polars does not use row indices. It prioritizes immutability and method chaining over modifying data in-place.
Creation
- Series: A named sequence of values.
series = pl.Series("sales", [150.00, 300.00, 250.00]) - DataFrame: Created from a dictionary of sequences or via
pl.read_*()functions.df = pl.DataFrame({"sales": series, "id": [41, 42, 43]}) - Adding Indices: Since there is no implicit index, create one manually:
df.with_row_index("id")
⚡ Eager vs. Lazy APIs
Polars offers two modes of execution. The Eager API runs commands immediately, while the Lazy API constructs an optimized query plan before execution.
The Optimizer enhances performance via:
- Predicate Pushdown: Filtering rows as early as possible.
- Projection Pushdown: Removing unused columns early.
Lazy Operations
- Execution: Use
.collect()to turn aLazyFrameback into aDataFrame. - Big Data: Use
lf.collect(engine="streaming")to process datasets that exceed available RAM. - Debugging:
lf.show_graph(): Visualizes the optimized query plan.lf.profile(): Returns timing data for each node in the plan.
🧮 Data Types
Polars adheres to the Apache Arrow memory specification for efficient columnar storage.
| Group | Type | Notes/Range |
|---|---|---|
| Numeric | Decimal | 128-bit precision and scale |
Float32 | ||
Float64 | ||
Int8 to Int128 | From to | |
UInt8 to UInt64 | From to | |
| Temporal | Date | Days since Unix epoch |
Datetime | Microseconds since epoch | |
Duration | Time delta/duration | |
Time | Time of day | |
| Nested | Array | Fixed-length sequence |
List | Variable-length sequence | |
Struct | Named multiple fields | |
| Strings | String | UTF-8 variable length |
Categorical | Dictionary of strings | |
Enum | Fixed dictionary of strings | |
| Other | Boolean | True / False |
Binary | Raw bytes | |
Null | Represents None |
Type Inspection & Casting
- Inspection:
df.dtypes: Returns a list/dictionary of types.df.glimpse(): A vertical summary of columns (ideal for wide data).df.describe(): Summary statistics and null counts.df.estimated_size("mb"): Memory footprint in specified units.
- Casting:
# Strict cast (errors on failure) df.with_columns(pl.col("x").cast(pl.Int8)) # Non-strict cast (overflows become null) df.with_columns(pl.col("x").cast(pl.Int8, strict=False))
💾 Reading and Writing Data
Polars provides four distinct I/O patterns depending on the execution mode:
read_*()Eager (returns DataFrame)scan_*()Lazy (returns LazyFrame)write_*()Eager (writes to disk)sink_*()Streaming (writes without loading all into RAM)
Format Support Matrix
| Format | read | scan | write | sink |
|---|---|---|---|---|
| Avro | ✓ | ✓ | ||
| Clipboard | ✓ | ✓ | ||
| CSV | ✓ | ✓ | ✓ | ✓ |
| Database | ✓ | ✓ | ||
| Delta Lake | ✓ | ✓ | ✓ | |
| Excel / ODS | ✓ | ✓ | ||
| Iceberg | ✓ | ✓ | ✓ | |
| IPC / Feather | ✓ | ✓ | ✓ | ✓ |
| JSON | ✓ | ✓ | ||
| NDJSON | ✓ | ✓ | ✓ | ✓ |
| Parquet | ✓ | ✓ | ✓ | ✓ |
| PyArrow Dataset | ✓ |
Pro Tips:
- Cloud Storage: Use URIs with globs and
storage_optionsfor S3/Azure/GCP.pl.scan_parquet("s3://bucket/*.parquet", storage_options={"aws_region": "us-east-2"}) - Partitioning: Stream results to a partitioned dataset using
lf.PartitionBy("out/", key="x").
🛠️ Transforming Data
Selecting Columns
You can isolate columns by name, position, or data type using .select().
- Basic Selection:
df.select("a", "b") - Expression Selection: Use expressions to modify data during selection.
# Multiply column 'x' by 2 df.select(pl.col("x") * 2) - Aliasing: Use keyword arguments to name the result of an expression.