OC_P8 / scripts /seed_traffic_drifted.py
KLEB38's picture
Upload folder using huggingface_hub
f1ef656 verified
Raw
History Blame Contribute Delete
3.55 kB
"""Seed traffic with explicit income drift.
Variant of ``scripts/seed_traffic.py`` that multiplies ``AMT_INCOME_TOTAL``
by a configurable factor (default 1.3 = +30%) before each POST. Simulates
a population-level shift where the average demanding client suddenly has
significantly higher income — the kind of drift a real production
monitor must catch and alert on.
The API re-derives ratios (INCOME_CREDIT_PERC, ANNUITY_INCOME_PERC,
INCOME_PER_PERSON) server-side, so the shifted income propagates to
those derived features automatically.
Usage:
uv run python scripts/seed_traffic_drifted.py # 1.3x income
uv run python scripts/seed_traffic_drifted.py --income-factor 2.0
uv run python scripts/seed_traffic_drifted.py --known 100 --unknown 0
"""
from __future__ import annotations
import argparse
import logging
import random
import sys
from pathlib import Path
from typing import Any
import pandas as pd
from seed_traffic import (
APP_TRAIN_PATH,
DEFAULT_BASE_URL,
DEFAULT_DELAY_S,
DEFAULT_KNOWN,
DEFAULT_SEED,
DEFAULT_UNKNOWN,
UNKNOWN_ID_START,
_row_to_payload,
run,
)
logger = logging.getLogger("scripts.seed_traffic_drifted")
logging.basicConfig(level=logging.INFO, format="%(message)s")
DEFAULT_INCOME_FACTOR = 1.3
def build_payloads(
app_train_path: Path,
n_known: int,
n_unknown: int,
income_factor: float,
rng: random.Random,
) -> list[dict[str, Any]]:
if not app_train_path.exists():
raise SystemExit(
f"{app_train_path} not found. Place the Kaggle application_train.csv there."
)
logger.info("Loading %s ...", app_train_path)
df = pd.read_csv(app_train_path)
df = df[df["CODE_GENDER"] != "XNA"]
df = df[df["DAYS_BIRTH"].notna()]
logger.info("application_train clean rows: %d", len(df))
seed_state = rng.randint(0, 2**31 - 1)
sample = df.sample(n=n_known + n_unknown, random_state=seed_state)
payloads: list[dict[str, Any]] = []
for i, (_, row) in enumerate(sample.iterrows()):
payload = _row_to_payload(row)
if payload.get("AMT_INCOME_TOTAL") is not None:
payload["AMT_INCOME_TOTAL"] = float(payload["AMT_INCOME_TOTAL"]) * income_factor
if i >= n_known:
payload["SK_ID_CURR"] = UNKNOWN_ID_START + (i - n_known)
payloads.append(payload)
rng.shuffle(payloads)
logger.info(
"Built %d payloads with income x%.2f (%d known + %d unknown)",
len(payloads), income_factor, n_known, n_unknown,
)
return payloads
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--base-url", default=DEFAULT_BASE_URL)
parser.add_argument("--delay", type=float, default=DEFAULT_DELAY_S)
parser.add_argument("--seed", type=int, default=DEFAULT_SEED)
parser.add_argument("--app-train-path", type=Path, default=APP_TRAIN_PATH)
parser.add_argument("--known", type=int, default=DEFAULT_KNOWN)
parser.add_argument("--unknown", type=int, default=DEFAULT_UNKNOWN)
parser.add_argument(
"--income-factor",
type=float,
default=DEFAULT_INCOME_FACTOR,
help="Multiplier applied to AMT_INCOME_TOTAL (default %(default)s).",
)
args = parser.parse_args()
rng = random.Random(args.seed)
payloads = build_payloads(
args.app_train_path, args.known, args.unknown, args.income_factor, rng
)
return run(payloads, args.base_url, args.delay)
if __name__ == "__main__":
sys.exit(main())