Ciaren

Customer Segmentation

Customer Segmentation

Group customers into spending tiers by combining two files: a customer list and an order history. This shows off Join, Group by + Aggregate, and Bin Column.

You'll use: two File Inputs → Group by + Aggregate → Rename → Join → Bin Column → Sort → File Output.

The key pattern here is a fork-join: two separate File Input nodes feed into a single Join node. The left branch aggregates orders first; the right branch is the raw customer list.

Left input
File Input
orders.csv
Group By + Aggregate
sum amount, count orders per customer
Rename Columns
amount→total_spent · order_id→num_orders
Right input
File Input
customers.csv
Join
on: customer_id · how: left
Bin Column
total_spent → tier (Bronze/Silver/Gold)
Sort Rows
total_spent desc
File Output
segments.csv

Sample data

customers.csv:

customer_id,name,country
1,Ada,UK
2,Grace,US
3,Linus,FI
4,Margaret,US

orders.csv:

order_id,customer_id,amount
5001,1,40.00
5002,1,60.00
5003,2,500.00
5004,3,15.00
5005,4,220.00
5006,4,30.00

Upload both on the Datasets page (📥 download customers.csv · orders.csv).

Build the flow

  1. File Input (orders) — File type CSV, select orders.csv.
  2. Group by + Aggregategroup_by: ["customer_id"], aggregations: { "amount": "sum", "order_id": "count" }. One row per customer with their total spend and order count.
  3. Rename Columnsmapping: { "amount": "total_spent", "order_id": "num_orders" }.
  4. File Input (customers) — File type CSV, select customers.csv.
  5. Join — connect the renamed aggregate to the left handle and the customers input to the right handle. Config: on: "customer_id", how: "left".
  6. Bin Columncolumn: "total_spent", new_column: "tier", bins: 3, method: "equalwidth", labels: ["Bronze", "Silver", "Gold"].
  7. Sort Rowscolumns: ["total_spent"], ascending: false.
  8. File Outputformat: csv (name segments).

Exported Python

import pandas as pd

df_orders = pd.read_csv('orders.csv')
df_customers = pd.read_csv('customers.csv')

df_orders = (
    df_orders.groupby('customer_id')
    .agg({'amount': 'sum', 'order_id': 'count'})
    .reset_index()
    .rename(columns={'amount': 'total_spent', 'order_id': 'num_orders'})
)

df_1 = df_orders.merge(df_customers, on='customer_id', how='left')

df_1 = (
    df_1.assign(tier=pd.cut(df_1['total_spent'], bins=3, labels=['Bronze', 'Silver', 'Gold']).astype('string'))
    .sort_values('total_spent', ascending=False)
)

df_1.to_csv('segments.csv', index=False)

Each input frame is named after its dataset; straight-line steps reuse one variable, while the join's two inputs keep their own (df_orders, df_customers) because both must still exist when pd.merge runs.

Result

Each customer now has their total spend, order count, and assigned tier.

Before
order_idcustomer_idamount
5001140
5002160
50032500
5004315
50054220
5006430
6 rows · 3 cols
Full flow
After
customer_idnamecountrytotal_spentnewnum_ordersnewtiernew
2GraceUS5001Gold
4MargaretUS2502Silver
1AdaUK1002Bronze
3LinusFI151Bronze
4 rows · 6 cols

Tips

  • Quantile vs. equal-width bins. quantile puts roughly equal counts of customers in each tier; equalwidth splits the value range evenly. Choose based on whether you care about ranking or absolute thresholds.
  • Key names differ? If the join columns aren't both named customer_id, use left_on and right_on on the Join node instead of on.

Next steps