-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgenerate_sample_data.py
More file actions
100 lines (85 loc) · 3 KB
/
Copy pathgenerate_sample_data.py
File metadata and controls
100 lines (85 loc) · 3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
"""
Generates synthetic order data for RFM analysis.
Produces data/sample_orders.csv with ~1,000 customers and ~8,000 orders.
"""
import pandas as pd
import numpy as np
from pathlib import Path
np.random.seed(42)
N_CUSTOMERS = 1_000
N_ORDERS = 8_000
DATE_START = pd.Timestamp("2022-01-01")
DATE_END = pd.Timestamp("2024-12-31")
# Customer segments (simulate real-world skew)
SEGMENT_WEIGHTS = {
"champion": 0.10,
"loyal": 0.20,
"at_risk": 0.25,
"hibernating":0.25,
"lost": 0.20,
}
def make_customers(n: int) -> pd.DataFrame:
segments = np.random.choice(
list(SEGMENT_WEIGHTS.keys()),
size=n,
p=list(SEGMENT_WEIGHTS.values())
)
return pd.DataFrame({
"customer_id": [f"C{str(i).zfill(5)}" for i in range(1, n + 1)],
"segment": segments,
})
def make_orders(customers: pd.DataFrame, n: int) -> pd.DataFrame:
# Champions and loyals get more orders, recency bias toward recent
freq_map = {
"champion": (12, 30),
"loyal": (6, 15),
"at_risk": (2, 6),
"hibernating": (1, 3),
"lost": (1, 2),
}
monetary_map = {
"champion": (200, 800),
"loyal": (80, 300),
"at_risk": (40, 150),
"hibernating": (20, 80),
"lost": (10, 50),
}
recency_bias = {
"champion": 0.85, # mostly recent
"loyal": 0.70,
"at_risk": 0.40,
"hibernating": 0.20,
"lost": 0.05, # mostly old
}
rows = []
total_days = (DATE_END - DATE_START).days
for _, cust in customers.iterrows():
seg = cust["segment"]
lo, hi = freq_map[seg]
n_orders = np.random.randint(lo, hi + 1)
bias = recency_bias[seg]
for _ in range(n_orders):
# Weighted random date (bias toward recent or old)
u = np.random.beta(bias * 3 + 0.5, (1 - bias) * 3 + 0.5)
order_date = DATE_START + pd.Timedelta(days=int(u * total_days))
mlo, mhi = monetary_map[seg]
amount = round(np.random.uniform(mlo, mhi), 2)
rows.append({
"customer_id": cust["customer_id"],
"order_date": order_date.date(),
"grand_total": amount,
})
return pd.DataFrame(rows)
if __name__ == "__main__":
print("Generating customers...")
customers = make_customers(N_CUSTOMERS)
print("Generating orders...")
orders = make_orders(customers, N_ORDERS)
orders = orders.sort_values("order_date").reset_index(drop=True)
out = Path(__file__).parent / "data" / "sample_orders.csv"
out.parent.mkdir(parents=True, exist_ok=True)
orders.to_csv(out, index=False)
print(f"\nSaved {len(orders):,} orders for {orders['customer_id'].nunique():,} customers")
print(f"Date range: {orders['order_date'].min()} → {orders['order_date'].max()}")
print(f"Revenue: ${orders['grand_total'].sum():,.2f}")
print(f"Output: {out}")