Source code · Python

data_layer.py

68 lines · Part of Credit risk lab · All code · Read only; the files run as published

"""SQL data layer: load the UCI credit card default data into SQLite and run theSQL in ./sql against it. The source copy (Yellowbrick's mirror of UCI dataset 350, checksum verified indata/SOURCE.md) labels the six monthly columns in reverse: its "apr_*" columnholds September 2005, matching UCI attribute X6. Columns are therefore read byposition and named in the UCI order here."""import csvimport gzipimport sqlite3from pathlib import Path import pandas as pd HERE = Path(__file__).resolve().parentDATA = HERE / "data" / "credit.csv.gz"SQL = HERE / "sql" MONTHS = ["sep", "aug", "jul", "jun", "may", "apr"]  # UCI order: X6 = SeptemberCOLUMNS = (    ["credit_limit", "sex", "education", "marital_status", "age"]    + [f"status_{m}" for m in MONTHS]    + [f"bill_{m}" for m in MONTHS]    + [f"paid_{m}" for m in MONTHS]    + ["default_next_month"])  def build_database(path: Path) -> sqlite3.Connection:    """Create the accounts table and load every row, in UCI column order."""    con = sqlite3.connect(path)    con.executescript((SQL / "01_schema.sql").read_text())    with gzip.open(DATA, "rt", newline="") as f:        reader = csv.reader(f)        header = next(reader)        if len(header) != len(COLUMNS):            raise ValueError(f"expected {len(COLUMNS)} columns, found {len(header)}")        rows = [[float(v) for v in row] for row in reader]    placeholders = ", ".join("?" * len(COLUMNS))    con.executemany(f"INSERT INTO accounts ({', '.join(COLUMNS)}) VALUES ({placeholders})", rows)    con.executescript((SQL / "03_features.sql").read_text())    con.commit()    return con  def query(con: sqlite3.Connection, name: str) -> pd.DataFrame:    """Run one of the .sql files and return its result as a DataFrame."""    return pd.read_sql_query((SQL / name).read_text(), con)  def load(path: Path):    """Build the database and return (connection, quality checks, segments, features)."""    con = build_database(path)    quality = query(con, "02_quality.sql")    segments = query(con, "04_segments.sql")    features = pd.read_sql_query("SELECT * FROM account_features ORDER BY account_id", con)    return con, quality, segments, features  if __name__ == "__main__":    db = HERE / "output" / "credit.db"    db.parent.mkdir(exist_ok=True)    db.unlink(missing_ok=True)    _, quality, segments, features = load(db)    print(quality.to_string(index=False))    print(segments.to_string(index=False))    print(features.describe().T[["mean", "min", "max"]].to_string())