E-Commerce Sales Intelligence with DuckDB: Pareto, MoM Anomaly Detection & RFM Analysis
Last week I built an automated sales analysis system for a cross-border e-commerce friend using DuckDB. He used the monthly report directly in an investor pitch and paid me 3,000 RMB for the consulting work.
The core idea is simple: DuckDB + Python compresses 2 hours of Excel pivot table work into 30 seconds, while producing actionable insights that drive decisions.

1. Why DuckDB for E-Commerce Analysis?
The friend runs a DTC store with clothing and electronics lines. The data source is Shopify-exported order CSVs (~20K-50K rows per month). The pain points are universal:
- Monthly manual report creation (trends, category contribution, channel performance) takes over 2 hours
- When asked “Why did electronics drop this month?” — he can only guess
- Hiring a data analyst costs 15K+ RMB/month, which has poor ROI
DuckDB hits the sweet spot:
- SQL on CSV — most analysts already know SQL; no new language to learn
- Zero configuration —
pip install duckdband you’re done - 10x+ faster than Pandas — columnar storage + SIMD optimization, sub-second response on 50K rows
Excel chokes on 50K+ rows. Pandas requires verbose Python code. DuckDB lets you express complex analysis logic in familiar SQL while getting near-native performance.
2. The Zero-Copy Trick: con.register()
Before writing any analysis, here’s a critical technique: con.register().
import duckdb
import pandas as pd
df = pd.read_csv("shopify_orders.csv")
con = duckdb.connect(":memory:")
con.register("orders", df)
Many people write con.execute("CREATE TABLE orders AS SELECT * FROM df") instead. That’s unnecessary. register() is DuckDB’s patented feature — it maps a Pandas DataFrame as a virtual table with zero copy, zero delay. For monthly analysis workflows, this eliminates data import overhead so you focus purely on query logic.
3. Monthly Category Trends (Excel Pivot Table Replacement)
The most fundamental layer. The question every boss asks: “Which category performed best last month?”
trend_sql = """
SELECT
strftime(order_date, '%Y-%m') as month,
category,
SUM(revenue) as monthly_revenue,
SUM(quantity) as monthly_quantity,
AVG(revenue) as avg_order_value,
COUNT(DISTINCT customer_id) as unique_customers
FROM orders
WHERE order_date >= '2024-01-01'
GROUP BY month, category
ORDER BY month, monthly_revenue DESC
"""
monthly_trend = con.execute(trend_sql).fetchdf()
Key techniques in this query:
strftime(order_date, '%Y-%m')formats dates to year-month for monthly aggregationCOUNT(DISTINCT customer_id)measures category acquisition powerAVG(revenue)computes average order value for high-value category identification
4. Pareto Analysis: Finding the Vital Few
Pareto analysis (the 80/20 rule) answers one question: which 20% of categories drive 80% of revenue?
pareto_sql = """
SELECT
category,
SUM(revenue) as total_revenue,
ROUND(SUM(revenue) * 100.0 / SUM(SUM(revenue)) OVER (), 2) as revenue_pct,
ROUND(SUM(revenue) / NULLIF(SUM(quantity), 0), 2) as avg_unit_price,
SUM(quantity) as total_units
FROM orders
GROUP BY category
ORDER BY total_revenue DESC
"""
pareto_result = con.execute(pareto_sql).fetchdf()
A common pitfall here: SUM(SUM(revenue)) OVER (). The outer SUM() is a window function (sums the entire result set), while the inner SUM(revenue) is an aggregate (sums per category). This nested pattern is DuckDB’s standard approach for aggregate-window combinations.
NULLIF(SUM(quantity), 0) prevents division-by-zero errors. When quantity is 0, the expression returns NULL gracefully instead of crashing.
5. MoM Anomaly Detection: Automated Alerting
This is the most valuable part of the system. Bosses don’t need a monthly trend chart — they need: “Tell me what’s broken.”
anomaly_sql = """
WITH monthly AS (
SELECT
category,
strftime(order_date, '%Y-%m') as month,
SUM(revenue) as revenue
FROM orders
GROUP BY category, month
),
with_lag AS (
SELECT *,
LAG(revenue) OVER (PARTITION BY category ORDER BY month) as prev_revenue,
ROUND((revenue - LAG(revenue) OVER (PARTITION BY category ORDER BY month))
/ NULLIF(LAG(revenue) OVER (PARTITION BY category ORDER BY month), 0) * 100, 2) as mom_change
FROM monthly
),
filtered AS (
SELECT category, month, revenue, prev_revenue, mom_change
FROM with_lag
WHERE mom_change < -15
ORDER BY mom_change ASC
)
SELECT * FROM filtered
"""
anomalies = con.execute(anomaly_sql).fetchdf()
The query executes in three stages:
- CTE
monthly: Aggregate revenue by category and month, creating a monthly revenue matrix - CTE
with_lag: UseLAG()window function to fetch last month’s revenue, compute MoM change percentage - Final query: Filter records where MoM change is below -15%
LAG(revenue) OVER (PARTITION BY category ORDER BY month) is the key. It tells DuckDB: “For each category, ordered by month, grab the previous row’s revenue.” This is far more elegant than manually computing MoM in Python.
6. RFM High-Value Customer Identification (Top 10%)
RFM analysis is the foundation of customer segmentation. Here we use DuckDB’s PERCENTILE_CONT to automatically identify the top 10% high-value customers:
rfm_sql = """
SELECT
customer_id,
MAX(order_date) - MIN(order_date) as customer_lifespan_days,
COUNT(*) as total_orders,
SUM(revenue) as total_revenue,
AVG(revenue) as avg_order_value
FROM orders
GROUP BY customer_id
HAVING total_revenue > PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY total_revenue)
ORDER BY total_revenue DESC
LIMIT 50
"""
vip_customers = con.execute(rfm_sql).fetchdf()
PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY total_revenue) is DuckDB’s order-statistic function. It dynamically computes the 90th percentile of all customer revenues, then the HAVING clause filters to customers above that threshold. The benefit: regardless of customer count, you always identify the top 10%.
7. Complete Script: From Data to Insights
Combining all four analyses into one script:
import pandas as pd
import duckdb
from datetime import datetime
# Load data
df = pd.read_csv("shopify_orders.csv")
# Zero-copy registration
con = duckdb.connect(":memory:")
con.register("orders", df)
# 1. Monthly category trends
monthly_trend = con.execute(trend_sql).fetchdf()
# 2. Pareto analysis
pareto_result = con.execute(pareto_sql).fetchdf()
# 3. MoM anomaly detection
anomalies = con.execute(anomaly_sql).fetchdf()
# 4. RFM high-value customers
vip_customers = con.execute(rfm_sql).fetchdf()
con.close()
print(f"📊 Analysis complete: {len(df)} orders processed")
print(f"🔍 Found {len(anomalies)} anomalous category/month combinations")
print(f"💎 VIP customers (TOP 50) avg order value: {vip_customers['avg_order_value'].mean():.2f}")
8. Performance Optimization: CSV to Parquet
When data scales to millions of rows, convert CSV to Parquet:
# One-time conversion
df.to_parquet("orders.parquet", engine="pyarrow")
# DuckDB reads Parquet with automatic predicate pushdown
con = duckdb.connect(":memory:")
result = con.execute("SELECT * FROM 'orders.parquet' WHERE category = 'Electronics'").fetchdf()
DuckDB’s predicate pushdown on Parquet can improve query speed by 5-10x. Because Parquet is columnar, DuckDB reads only the needed columns and skips data blocks that don’t match the filter conditions.
9. Extensibility: Automation & Monetization
The real value lies in reusability. The same code works with any dataset:
- Weekly automated reports: Pair with cron jobs to run every Monday morning, push reports to Slack or WeChat
- BI tool integration: DuckDB connects directly to Superset, Metabase for real-time data sources
- API wrapping: Wrap with FastAPI to expose analysis endpoints, charge per request
10. Monetization Path Summary
The commercial value of this system rests on three pillars:
- Efficiency gain: 2 hours → 30 seconds, running automatically every month
- Decision quality: Anomaly detection alerts proactively, no longer relying on gut feeling
- Reusability: Same codebase serves the next client with a different dataset
If you’re a freelance data analyst or side-hustler, this “small but sharp” toolkit (DuckDB + SQL) is your most effective weapon — low cost, fast delivery, high client perceived value. The 3,000 RMB consultation fee isn’t the end goal; it’s the starting point for a standardized product.
📖 本文的代码模板和完整 CSV 数据文件已上传至 duckdblab.org,包含针对 5 种常见业务场景(电商、SaaS、内容平台、传统零售、跨境电商)的预置分析模板,直接替换数据即可运行。