

0 / 2 embers
0 / 3000 xp
click for more info
Complete a lesson to start your streak
click for more info
Difficulty: 6
click for more info
Not enough gems
Cost: 6 gems
1: Polars
incomplete
2: Basic Operations
incomplete
3: Polars vs. Pandas
incomplete
4: Expression-Based Operations
incomplete
5: Lazy vs. Eager Execution
incomplete
6: No Index
incomplete
7: Filtering With No Index
incomplete
8: Index Alternatives
incomplete
9: Sorting
incomplete
10: Sorting Footguns
incomplete
11: Time-Based Operations
incomplete
12: Parquet
incomplete
13: Parquet With Polars
incomplete
Back
ctrl+,
Next
ctrl+.
This lesson's interactive features are locked, please to keep using them
Time-based operations require a datetime-type column in both Pandas and Polars. In Pandas, we often make that column the index, i.e., a DatetimeIndex:
sales = pd.DataFrame(
{
"date": ["2024-05-01 14:30", "2024-05-02 09:00", "2024-05-02 16:45"],
"sku": ["TSH-BLU-MED", "AP-AN001-SM", "TSH-BLU-MED"],
"quantity": [2, 1, 4],
"unit_price": [19.99, 29.99, 19.99],
}
)
# Add a column calculating total revenue for each sale
sales["line_total"] = sales["quantity"] * sales["unit_price"]
# Convert the date column to datetime, and set it as the index for resampling
sales["date"] = pd.to_datetime(sales["date"])
sales = sales.set_index("date")
# Resample to group rows by day, and sum line_total for daily revenue
daily_revenue = sales.resample("D")["line_total"].sum()
print(daily_revenue)
# date
# 2024-05-01 39.98
# 2024-05-02 109.95
In Polars, you can use time-based operations directly on a datetime-type column. No need to muck with indexes:
incidents = pl.DataFrame(
{
"opened_at": ["2024-05-01 14:30", "2024-05-02 09:00", "2024-05-02 16:45"],
"ticket_id": ["T-1", "T-2", "T-3"],
"response_minutes": [45, 30, 90],
}
)
# Convert the opened_at column to datetime
incidents = incidents.with_columns(
pl.col("opened_at").str.strptime(pl.Datetime, "%Y-%m-%d %H:%M")
)
# Group by date (truncated to day), and average response_minutes
daily_response = incidents.group_by(pl.col("opened_at").dt.truncate("1d")).agg(
pl.col("response_minutes").mean().alias("avg_response_minutes")
)
print(daily_response)
# shape: (2, 2)
# ┌─────────────────────┬──────────────────────┐
# │ opened_at ┆ avg_response_minutes │
# │ --- ┆ --- │
# │ datetime[μs] ┆ f64 │
# ╞═════════════════════╪══════════════════════╡
# │ 2024-05-01 00:00:00 ┆ 45.0 │
# │ 2024-05-02 00:00:00 ┆ 60.0 │
# └─────────────────────┴──────────────────────┘
The result has one row per day and an average response time for that day. The important Polars-specific pieces are:
.group_by() groups rows by a column or expression.dt accesses datetime-specific methods on a datetime column.dt.truncate() truncates a datetime to a time unit, like "1d" for "day".agg() aggregates grouped rows with expressions like sum() or mean()SnackStack's appliances send energy readings throughout the day. The analytics team needs a daily total so they can spot usage spikes.
Complete the build_daily_energy_report function. It accepts a Polars DataFrame of device energy readings and returns a new report DataFrame.