typestar

pd_run_report.py in Python

A pandas report end to end: parse, clean, derive, group and rank.

from io import StringIO

import pandas as pd

RAW = """day,lang,chars,seconds,errors
2026-07-20,python,1820,60.0,4
2026-07-20,rust,1510,60.0,9
2026-07-21,python,1980,60.0,2
2026-07-21,sql,1240,60.0,1
2026-07-22,python,2050,60.0,3
2026-07-22,rust,1660,60.0,5
2026-07-28,css,980,45.0,7
2026-07-29,python,2110,60.0,1
"""


def load(text):
    """Read the export and give every column its real type."""
    return pd.read_csv(
        StringIO(text),
        parse_dates=["day"],
        dtype={"lang": "category", "chars": "int32", "errors": "int16"},
    )


def derive(frame):
    return frame.assign(
        wpm=lambda f: (f["chars"] / 5) / (f["seconds"] / 60),
        accuracy=lambda f: (1 - f["errors"] / f["chars"]) * 100,
        week=lambda f: f["day"].dt.isocalendar().week,
    )


def by_language(frame):
    return (frame
            .groupby("lang", observed=True)
            .agg(runs=("wpm", "size"),
                 best_wpm=("wpm", "max"),
                 mean_wpm=("wpm", "mean"),
                 accuracy=("accuracy", "mean"))
            .sort_values("mean_wpm", ascending=False)
            .round(1))


def main():
    runs = load(RAW).pipe(derive)

    print("runs per language")
    print(by_language(runs).to_string())

    print("\nweekly mean wpm")
    weekly = (runs.set_index("day")["wpm"]
              .resample("W")
              .mean()
              .round(1)
              .dropna())
    print(weekly.to_string())

    print("\nrolling three-run average, python only")
    python_only = runs[runs["lang"] == "python"].sort_values("day")
    rolling = python_only["wpm"].rolling(3, min_periods=1).mean().round(1)
    for day, value in zip(python_only["day"].dt.date, rolling):
        print(f"  {day}  {value}")

    best = runs.loc[runs["wpm"].idxmax()]
    print(f"\nbest run: {best['lang']} at {best['wpm']:.1f} wpm "
          f"on {best['day'].date()}")


if __name__ == "__main__":
    main()

How it works

  1. The whole transform is one chain, so no half-built frame escapes.
  2. Dates are parsed once, then the index does the time slicing.
  3. The output is a small table, not a dump of the frame.

Keywords and builtins used here

The run, in numbers

Lines
71
Characters to type
1638
Tokens
491
Three-star pace
115 tpm

At the three-star pace of 115 tokens a minute, this run takes about 256 seconds.

Type this snippet

Step 1 of 1 in Encore, step 26 of 26 in pandas.

← Previous