DataMind-AI / datasets.py
samuelalex37's picture
V2 Release: Complete UI overhaul and new AI Analytics engine
6193995
Raw
History Blame Contribute Delete
10.2 kB
"""
DataMind AI — Simulated Dataset Generators
Produces two realistic, slightly messy 500-row datasets for demo purposes.
"""
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
def generate_retail_dataset() -> pd.DataFrame:
"""Generate a 500-row Retail Sales dataset with realistic, slightly messy data."""
np.random.seed(42)
n = 500
# Date range: 2 years of sales
start_date = datetime(2023, 1, 1)
dates = [start_date + timedelta(days=np.random.randint(0, 730)) for _ in range(n)]
products = [
"Laptop", "Wireless Mouse", "Keyboard", "Monitor", "USB Cable",
"Headphones", "Webcam", "Desk Lamp", "Phone Case", "Charger",
"Tablet", "Smartwatch", "Speaker", "Power Bank", "Router"
]
categories_map = {
"Laptop": "Electronics", "Wireless Mouse": "Accessories",
"Keyboard": "Accessories", "Monitor": "Electronics",
"USB Cable": "Accessories", "Headphones": "Audio",
"Webcam": "Electronics", "Desk Lamp": "Office",
"Phone Case": "Accessories", "Charger": "Accessories",
"Tablet": "Electronics", "Smartwatch": "Wearables",
"Speaker": "Audio", "Power Bank": "Accessories",
"Router": "Electronics"
}
regions = ["North", "South", "East", "West", "Central"]
genders = ["Male", "Female", "Other"]
product_choices = np.random.choice(products, n)
categories = [categories_map[p] for p in product_choices]
region_choices = np.random.choice(regions, n)
units = np.random.randint(1, 50, n)
# Realistic price ranges per product
price_map = {
"Laptop": (600, 1500), "Wireless Mouse": (15, 60),
"Keyboard": (25, 150), "Monitor": (200, 800),
"USB Cable": (5, 20), "Headphones": (30, 300),
"Webcam": (40, 150), "Desk Lamp": (20, 80),
"Phone Case": (8, 40), "Charger": (10, 50),
"Tablet": (200, 900), "Smartwatch": (100, 500),
"Speaker": (50, 250), "Power Bank": (15, 70),
"Router": (30, 200)
}
unit_prices = [round(np.random.uniform(*price_map[p]), 2) for p in product_choices]
revenue = [round(u * p, 2) for u, p in zip(units, unit_prices)]
customer_ids = [f"CUST-{np.random.randint(1000, 2000)}" for _ in range(n)]
customer_ages = np.random.randint(18, 72, n).astype(float)
customer_genders = np.random.choice(genders, n)
return_flags = np.random.choice([0, 1], n, p=[0.88, 0.12])
df = pd.DataFrame({
"Date": dates,
"Product": product_choices,
"Category": categories,
"Region": region_choices,
"Units_Sold": units,
"Unit_Price": unit_prices,
"Revenue": revenue,
"Customer_ID": customer_ids,
"Customer_Age": customer_ages,
"Customer_Gender": customer_genders,
"Return_Flag": return_flags
})
# --- Inject messiness ---
# 1. Nulls (~5%)
null_indices_age = np.random.choice(n, size=20, replace=False)
df.loc[null_indices_age, "Customer_Age"] = np.nan
null_indices_price = np.random.choice(n, size=10, replace=False)
df.loc[null_indices_price, "Unit_Price"] = np.nan
null_indices_region = np.random.choice(n, size=8, replace=False)
df.loc[null_indices_region, "Region"] = np.nan
null_indices_gender = np.random.choice(n, size=7, replace=False)
df.loc[null_indices_gender, "Customer_Gender"] = np.nan
null_indices_date = np.random.choice(n, size=5, replace=False)
df.loc[null_indices_date, "Date"] = pd.NaT
# 2. Duplicates (~2%)
dup_indices = np.random.choice(n, size=12, replace=False)
duplicates = df.iloc[dup_indices].copy()
df = pd.concat([df, duplicates], ignore_index=True)
# 3. Inconsistent capitalisation
messy_indices = np.random.choice(len(df), size=40, replace=False)
case_funcs = [str.upper, str.lower, str.swapcase]
for idx in messy_indices:
func = np.random.choice(case_funcs)
if pd.notna(df.at[idx, "Product"]):
df.at[idx, "Product"] = func(df.at[idx, "Product"])
if pd.notna(df.at[idx, "Region"]):
df.at[idx, "Region"] = func(df.at[idx, "Region"])
if pd.notna(df.at[idx, "Category"]):
df.at[idx, "Category"] = func(df.at[idx, "Category"])
# Shuffle rows
df = df.sample(frac=1, random_state=42).reset_index(drop=True)
return df
def generate_ecommerce_dataset() -> pd.DataFrame:
"""Generate a 500-row E-Commerce Orders dataset with realistic, slightly messy data."""
np.random.seed(99)
n = 500
start_date = datetime(2023, 1, 1)
order_dates = [start_date + timedelta(days=np.random.randint(0, 730)) for _ in range(n)]
ship_dates = [od + timedelta(days=np.random.randint(1, 10)) for od in order_dates]
segments = ["Consumer", "Corporate", "Home Office"]
countries = ["United States", "United Kingdom", "Canada", "Germany", "Australia"]
cities_map = {
"United States": ["New York", "Los Angeles", "Chicago", "Houston", "Seattle", "Miami"],
"United Kingdom": ["London", "Manchester", "Birmingham", "Leeds"],
"Canada": ["Toronto", "Vancouver", "Montreal", "Ottawa"],
"Germany": ["Berlin", "Munich", "Hamburg", "Frankfurt"],
"Australia": ["Sydney", "Melbourne", "Brisbane", "Perth"]
}
categories_structure = {
"Technology": {
"sub_categories": ["Phones", "Laptops", "Accessories", "Tablets"],
"products": {
"Phones": ["iPhone 15", "Galaxy S24", "Pixel 8", "OnePlus 12"],
"Laptops": ["MacBook Pro", "Dell XPS 15", "ThinkPad X1", "HP Spectre"],
"Accessories": ["AirPods Pro", "Magic Mouse", "USB-C Hub", "Laptop Stand"],
"Tablets": ["iPad Air", "Galaxy Tab S9", "Surface Pro", "Kindle Fire"]
},
"price_range": (50, 2000)
},
"Furniture": {
"sub_categories": ["Chairs", "Tables", "Bookcases", "Storage"],
"products": {
"Chairs": ["Ergonomic Office Chair", "Gaming Chair", "Mesh Task Chair", "Executive Chair"],
"Tables": ["Standing Desk", "Conference Table", "Corner Desk", "Folding Table"],
"Bookcases": ["5-Shelf Bookcase", "Floating Shelves", "Glass Bookcase", "Cube Organizer"],
"Storage": ["Filing Cabinet", "Storage Ottoman", "Drawer Unit", "Wardrobe"]
},
"price_range": (30, 1200)
},
"Office Supplies": {
"sub_categories": ["Paper", "Binders", "Art Supplies", "Envelopes"],
"products": {
"Paper": ["Copy Paper A4", "Cardstock", "Photo Paper", "Sticky Notes"],
"Binders": ["3-Ring Binder", "Report Cover", "Presentation Folder", "Clip Board"],
"Art Supplies": ["Marker Set", "Sketch Pad", "Colored Pencils", "Paint Set"],
"Envelopes": ["Manila Envelope", "Padded Mailer", "Window Envelope", "Bubble Wrap Roll"]
},
"price_range": (2, 80)
}
}
rows = []
for i in range(n):
order_id = f"ORD-{10000 + i}"
segment = np.random.choice(segments)
country = np.random.choice(countries)
city = np.random.choice(cities_map[country])
category = np.random.choice(list(categories_structure.keys()))
cat_info = categories_structure[category]
sub_cat = np.random.choice(cat_info["sub_categories"])
product_name = np.random.choice(cat_info["products"][sub_cat])
low, high = cat_info["price_range"]
quantity = np.random.randint(1, 12)
unit_sale = round(np.random.uniform(low, high), 2)
sales = round(unit_sale * quantity, 2)
discount = round(np.random.choice([0, 0, 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3]), 2)
profit = round(sales * np.random.uniform(-0.15, 0.45) * (1 - discount), 2)
shipping_cost = round(np.random.uniform(3, 50), 2)
cust_id = f"CID-{np.random.randint(100, 500)}"
rows.append({
"Order_ID": order_id,
"Order_Date": order_dates[i],
"Ship_Date": ship_dates[i],
"Customer_ID": cust_id,
"Segment": segment,
"Country": country,
"City": city,
"Category": category,
"Sub_Category": sub_cat,
"Product_Name": product_name,
"Sales": sales,
"Quantity": quantity,
"Discount": discount,
"Profit": profit,
"Shipping_Cost": shipping_cost
})
df = pd.DataFrame(rows)
# --- Inject messiness ---
# 1. Nulls (~5%)
null_sales = np.random.choice(n, size=15, replace=False)
df.loc[null_sales, "Sales"] = np.nan
null_profit = np.random.choice(n, size=12, replace=False)
df.loc[null_profit, "Profit"] = np.nan
null_ship = np.random.choice(n, size=10, replace=False)
df.loc[null_ship, "Ship_Date"] = pd.NaT
null_segment = np.random.choice(n, size=8, replace=False)
df.loc[null_segment, "Segment"] = np.nan
null_city = np.random.choice(n, size=7, replace=False)
df.loc[null_city, "City"] = np.nan
null_discount = np.random.choice(n, size=6, replace=False)
df.loc[null_discount, "Discount"] = np.nan
# 2. Duplicates
dup_indices = np.random.choice(n, size=10, replace=False)
duplicates = df.iloc[dup_indices].copy()
df = pd.concat([df, duplicates], ignore_index=True)
# 3. Inconsistent capitalisation
messy_indices = np.random.choice(len(df), size=35, replace=False)
case_funcs = [str.upper, str.lower, str.swapcase]
for idx in messy_indices:
func = np.random.choice(case_funcs)
if pd.notna(df.at[idx, "Segment"]):
df.at[idx, "Segment"] = func(df.at[idx, "Segment"])
if pd.notna(df.at[idx, "Category"]):
df.at[idx, "Category"] = func(df.at[idx, "Category"])
if pd.notna(df.at[idx, "City"]):
df.at[idx, "City"] = func(df.at[idx, "City"])
if pd.notna(df.at[idx, "Country"]):
df.at[idx, "Country"] = func(df.at[idx, "Country"])
# Shuffle
df = df.sample(frac=1, random_state=99).reset_index(drop=True)
return df