Skip to content
Aabha AI Academy
Skip to reading

Applied ML

Data

"""Deterministic fictional depot jobs. No real people or company records."""
from pathlib import Path
import hashlib
import numpy as np
import pandas as pd

ROOT = Path(__file__).resolve().parents[1]
SEED = 20261014
NUMERIC = ['distance_km', 'queued_jobs', 'item_count', 'weekday', 'promised_hours']
CATEGORICAL = ['priority', 'zone', 'depot_id']
FEATURES = NUMERIC + CATEGORICAL
FORBIDDEN = ['duration_hours', 'late', 'label_available_at', 'final_delay_reason', 'close_cost']
DATE_COLS = ['intake_at', 'label_available_at']

def generate(seed=SEED):
    """1500 rows, 6 jobs/day; targets available within 24 h of intake."""
    rng = np.random.default_rng(seed)
    n = 1500
    day = np.repeat(np.arange(250), 6)
    hour = np.tile(np.arange(8, 20, 2), 250)
    intake = pd.Timestamp('2025-01-01', tz='UTC') + pd.to_timedelta(day, unit='D') + pd.to_timedelta(hour, unit='h')
    depot_n = rng.integers(0, 12, n)
    distance = np.round(rng.uniform(2, 80, n), 2)
    queue = rng.poisson(6 + 2 * (day >= 190), n)
    items = rng.integers(1, 11, n)
    priority = rng.choice(['standard', 'express'], n, p=[0.75, 0.25])
    zone = rng.choice(['central', 'east', 'west'], n, p=[0.45, 0.3, 0.25])
    promised = np.where(priority == 'express', 6., 10.)
    depot_effect = np.array([-0.7, 0.4, 0.8, -0.2, 0.1, -0.5, 0.6, -0.4, 0.3, 0.5, -0.1, 0.2])[depot_n]
    # Queue congestion and a gradual mechanism change are deliberately synthetic.
    mechanism_shift = np.maximum(day - 180, 0) * 0.012
    duration = (1.5 + 0.06 * distance + 0.30 * queue + 0.17 * items
                + 0.10 * np.maximum(queue - 7, 0) ** 2
                + 0.8 * (zone == 'west') - 0.7 * (priority == 'express')
                + depot_effect + mechanism_shift + rng.normal(0, 1.0, n))
    duration = np.round(np.clip(duration, 0.5, 23.5), 3)
    frame = pd.DataFrame({
        'job_id': [f'J{i:05d}' for i in range(n)], 'day': day, 'intake_at': intake,
        'distance_km': distance, 'queued_jobs': queue, 'item_count': items,
        'priority': priority, 'zone': zone,
        'depot_id': [f'D{i:02d}' for i in depot_n],
        'weekday': intake.dayofweek, 'promised_hours': promised,
        'duration_hours': duration, 'late': (duration > promised).astype(int),
        'label_available_at': intake + pd.to_timedelta(duration, unit='h'),
        'final_delay_reason': np.where(duration > promised, 'late_confirmed', 'on_time_confirmed'),
        'close_cost': np.round(12 + 3 * duration + rng.normal(0, .3, n), 2)
    })
    # Missing inputs are introduced after the outcome mechanism has used true values.
    frame.loc[rng.random(n) < .05, 'distance_km'] = np.nan
    frame.loc[rng.random(n) < .03, 'queued_jobs'] = np.nan
    return frame

def parts(frame):
    return {
        'train': frame[frame.day < 149].copy(),
        'validation': frame[(frame.day >= 150) & (frame.day < 199)].copy(),
        'test': frame[frame.day >= 200].copy(),
        'embargo': frame[frame.day.isin([149, 199])].copy(),
    }

def write_data():
    folder = ROOT / 'data'
    folder.mkdir(exist_ok=True)
    for name, frame in parts(generate()).items():
        frame.to_csv(folder / f'{name}.csv', index=False, float_format='%.6f')
    return {k: len(v) for k, v in parts(generate()).items()}

def load_part(name):
    if name not in {'train', 'validation', 'test', 'embargo'}:
        raise ValueError('Unknown data partition')
    frame = pd.read_csv(ROOT / 'data' / f'{name}.csv')
    for column in DATE_COLS:
        frame[column] = pd.to_datetime(frame[column], format='mixed', utc=True, errors='raise')
    return frame

def validation_roles(validation):
    return (validation[validation.day < 174].copy(),
            validation[validation.day >= 175].copy())

def file_hash(path):
    return hashlib.sha256(Path(path).read_bytes()).hexdigest()

def assert_available(before, after):
    if not before.label_available_at.max() < after.intake_at.min():
        raise ValueError('A training/calibration label was unavailable at prediction time')

def audit(frame):
    assert frame.job_id.is_unique
    assert frame.intake_at.is_monotonic_increasing
    assert frame.late.isin([0, 1]).all()
    assert (frame.late == (frame.duration_hours > frame.promised_hours)).all()
    assert ((frame.label_available_at - frame.intake_at).dt.total_seconds() > 0).all()
    assert ((frame.label_available_at - frame.intake_at).dt.total_seconds() < 86400).all()
    assert frame[NUMERIC].notna().any().all()
    assert not set(FEATURES) & set(FORBIDDEN)
    return {'rows': len(frame), 'late_rate': float(frame.late.mean()),
            'missing_inputs': {c: int(frame[c].isna().sum()) for c in FEATURES}}

if __name__ == '__main__':
    print(write_data())

Download this source file