Sales Data Analysis
Sales Data Analysis
A common first task: take a messy export of orders and turn it into a clean revenue summary by region. This walkthrough cleans the data, then groups and aggregates it.
You'll use: File Input → Drop Columns → Change Types → Drop Nulls → Filter Rows → Fill Nulls → Group by + Aggregate → Rename → Sort → File Output.
Sample data
Save this as sales.csv and upload it on the Datasets page
(📥 download sales.csv):
order_id,region,amount,ordered_at,internal_note
1001,North,120.50,2024-01-03,batch-a
1002,south,89.00,2024-01-03,batch-a
1003,North,,2024-01-04,batch-b
1004,South,-5.00,2024-01-04,refund
1005,,42.25,2024-01-05,batch-b
1006,north,210.00,2024-01-06,batch-c
Notice the problems: an internal column we don't want, mixed-case regions, a missing amount, a negative (refund) amount, and a missing region.
Build the flow
- File Input — File type CSV, select the
sales.csvdataset. - Drop Columns —
columns: ["internal_note"]. - Change Types —
casts: { "amount": "float", "ordered_at": "datetime" }. - Drop Nulls —
subset: ["amount"](drop rows with no amount). - Filter Rows —
column: "amount",operator: ">",value: 0(drop refunds). - Replace Values — tidy region casing, e.g.
column: "region",to_replace: "north",value: "North"(add a second node for"south" → "South"). - Fill Nulls —
strategy: "constant",value: "Unknown",columns: ["region"]. - Group by + Aggregate —
group_by: ["region"],aggregations: { "amount": "sum", "order_id": "count" }. - Rename Columns —
mapping: { "amount": "total_sales", "order_id": "num_orders" }. - Sort Rows —
columns: ["total_sales"],ascending: false. - File Output —
format: csv(namesales_summary).
Use the live preview after each node to watch the data take shape, then Run the flow.
Exported Python
Click Export → Python. The generated pandas script is standalone — the input frame is named after your dataset, and on a straight chain like this one, consecutive steps fuse into fluent method chains on that single variable:
import pandas as pd
df_sales = pd.read_csv('sales.csv')
df_sales = (
df_sales.drop(columns=['internal_note'])
.assign(amount=lambda _d: _d['amount'].astype('float64'), ordered_at=lambda _d: pd.to_datetime(_d['ordered_at']))
.dropna(subset='amount')
.loc[lambda _d: _d['amount'] > 0]
.assign(region=lambda _d: _d['region'].replace('north', 'North'))
.assign(region=lambda _d: _d['region'].replace('south', 'South'))
.fillna({'region': 'Unknown'})
.groupby('region')
.agg({'amount': 'sum', 'order_id': 'count'})
.reset_index()
.rename(columns={'amount': 'total_sales', 'order_id': 'num_orders'})
.sort_values('total_sales', ascending=False)
)
df_sales.to_csv('sales_summary.csv', index=False)
Ciaren also generates the polars equivalent — pick whichever you prefer.
Result
The flow transforms the raw messy CSV into a clean revenue summary.
| order_id | region | amount | ordered_at | internal_note |
|---|---|---|---|---|
| 1001 | North | 120.5 | 2024-01-03 | batch-a |
| 1002 | south | 89 | 2024-01-03 | batch-a |
| 1003 | North | null | 2024-01-04 | batch-b |
| 1004 | South | -5 | 2024-01-04 | refund |
| 1005 | null | 42.25 | 2024-01-05 | batch-b |
| 1006 | north | 210 | 2024-01-06 | batch-c |
| region | total_salesnew | num_ordersnew |
|---|---|---|
| North | 330.5 | 2 |
| South | 89 | 1 |
| Unknown | 42.25 | 1 |
The refund row (amount = -5) and the missing-amount row were filtered out; the
row with no region became Unknown.
Variations
- Want revenue per day? Add Extract Date Parts on
ordered_atand group by the newordered_at_daycolumn. - Want a recurring summary? Attach a schedule to run this flow every morning.