Dataset Guide — E-commerce Analytics
Source
Dataset: Brazilian E-Commerce Public Dataset by Olist
URL: https://www.kaggle.com/datasets/olistbr/brazilian-ecommerce
Structure: 8 related CSV files (a real relational schema)
The Tables and How They Relate
┌─────────────────┐
│ customers │
│ customer_id (PK)│
└────────┬────────┘
│
┌────────▼────────┐ ┌──────────────────┐
│ orders │◄────────│ order_payments │
│ order_id (PK) │ │ order_id (FK) │
│ customer_id(FK) │ └──────────────────┘
└────────┬────────┘ ┌──────────────────┐
│ ◄─────│ order_reviews │
┌────────▼────────┐ │ order_id (FK) │
│ order_items │ └──────────────────┘
│ order_id (FK) │
│ product_id (FK) │
│ seller_id (FK) │
└───┬─────────┬───┘
│ │
┌───────▼──┐ ┌───▼──────┐
│ products │ │ sellers │
└──────────┘ └──────────┘
Key Tables
orders (~100k rows)
| Column |
Description |
order_id |
PK |
customer_id |
FK to customers |
order_status |
delivered, shipped, canceled, etc. |
order_purchase_timestamp |
When the order was placed |
order_delivered_customer_date |
When it arrived |
order_estimated_delivery_date |
Promised date |
order_items (~112k rows)
| Column |
Description |
order_id |
FK |
product_id |
FK |
seller_id |
FK |
price |
Item price |
freight_value |
Shipping cost |
customers (~99k rows)
| Column |
Description |
customer_id |
PK (unique per order!) |
customer_unique_id |
The actual person (use this for repeat analysis) |
customer_city / customer_state |
Location |
order_payments
| Column |
Description |
order_id |
FK |
payment_type |
credit_card, boleto, voucher, debit_card |
payment_installments |
Number of instalments |
payment_value |
Amount |
order_reviews
| Column |
Description |
order_id |
FK |
review_score |
1 to 5 |
review_comment_message |
Free text (Portuguese) |
products
| Column |
Description |
product_id |
PK |
product_category_name |
Category (Portuguese — join translation table) |
Critical Gotcha — customer_id vs customer_unique_id
The biggest trap in this dataset
customer_id is unique per order — a returning customer gets a NEW customer_id each time. To analyse repeat purchases or true customer LTV, you MUST use customer_unique_id, which identifies the actual person across orders. Using customer_id would make every customer look like a one-time buyer.
Other Notes
- Category names are in Portuguese — there's a
product_category_name_translation.csv to join for English names.
- Reviews are in Portuguese — for text analysis you'd need translation; for this project, the numeric
review_score is enough.
- Some orders have no delivery date — they were cancelled or not yet delivered.
- Data is genuinely clean — making it ideal for practising joins rather than fighting messiness.
Quick Exploration
import pandas as pd
orders = pd.read_csv("olist_orders_dataset.csv", parse_dates=[
"order_purchase_timestamp", "order_delivered_customer_date",
"order_estimated_delivery_date"])
items = pd.read_csv("olist_order_items_dataset.csv")
customers = pd.read_csv("olist_customers_dataset.csv")
reviews = pd.read_csv("olist_order_reviews_dataset.csv")
print(f"Orders: {len(orders)}, Items: {len(items)}, Reviews: {len(reviews)}")
print(f"Unique customers (by unique_id): {customers['customer_unique_id'].nunique()}")
print(f"Order rows (by customer_id): {customers['customer_id'].nunique()}")
# The two numbers differ — that gap is your repeat customers
← Business Problem · Next: Data Cleaning →