def make_source_note(n_obs: int, n_iter: int, n_workers: int) -> str:
return (
f"N = {int(n_obs):,}; {int(n_iter):,} bootstrap iterations; "
f"{int(n_workers)} workers for parallel computations."
)
def make_timing_table(ds: pl.DataFrame, estimation: str, source_note: str) -> GT:
return (
GT(ds.select("package", "computation", "seconds"))
.cols_label(package="Package", computation="Computation", seconds="Seconds")
.fmt_number(columns=["seconds"], decimals=1, use_seps=True)
.tab_header(title=md("**Speed Comparison**"), subtitle=estimation)
.tab_source_note(source_note)
)
def make_comparison_data(qs, series) -> pl.DataFrame:
"""Tidy estimate/SE data for a package-vs-package comparison.
``series`` maps a ``(package, computation)`` label to an ``(effects, ses)``
pair, each ordered as ``[QTE(q) for q in qs] + [ATT]``.
"""
n_qte = len(qs)
records = []
for (package, computation), (effects, ses) in series.items():
for i, q in enumerate(qs): # quantiles
records.append(
{
"effect": "QTE",
"quantile": f"{q:.2f}",
"package": package,
"computation": computation,
"estimate": float(effects[i]),
"se": float(ses[i]),
}
)
records.append(
{
"effect": "ATT",
"quantile": "",
"package": package,
"computation": computation,
"estimate": float(effects[n_qte]),
"se": float(ses[n_qte]),
}
)
return pl.DataFrame(records)
def make_estimate_comparison_table(data: pl.DataFrame, estimation: str, source_note: str) -> GT:
"""Render tidy comparison data (see ``make_comparison_data``).
Rows are grouped under ``QTE``/``ATT``; package names become the top-level
column spanners with the computation nested underneath. Estimate and
standard-error columns get distinct backgrounds, and packages are separated
by a vertical rule.
"""
pairs = data.select("package", "computation").unique(maintain_order=True).rows()
packages = list(dict.fromkeys(package for package, _ in pairs))
computations = list(dict.fromkeys(computation for _, computation in pairs))
def series(package, computation):
# filter preserves the QTE...ATT order produced by make_comparison_data
return data.filter((pl.col("package") == package) & (pl.col("computation") == computation))
base = series(*pairs[0])
frame = {"effect": base["effect"].to_list(), "quantile": base["quantile"].to_list()}
leaf_labels = {}
for package, computation in pairs:
prefix = f"{package}.{computation}"
sub = series(package, computation)
frame[f"{prefix}.est"] = sub["estimate"].to_list()
frame[f"{prefix}.se"] = sub["se"].to_list()
leaf_labels[f"{prefix}.est"] = "Estimate"
leaf_labels[f"{prefix}.se"] = md("Standard<br>Error")
table = pl.DataFrame(frame)
est_cols = [c for c in table.columns if c.endswith(".est")]
se_cols = [c for c in table.columns if c.endswith(".se")]
gt = (
GT(table, groupname_col="effect")
.row_group_order(["QTE", "ATT"])
.cols_label(quantile="Quantile", **leaf_labels)
.fmt_number(columns=est_cols + se_cols, decimals=1, use_seps=True)
.tab_header(title=md("**Results Comparison**"), subtitle=estimation)
.tab_source_note(source_note)
.tab_style(style=style.fill(color="#E8F1FA"), locations=loc.body(columns=est_cols))
.tab_style(style=style.fill(color="#FBF0E1"), locations=loc.body(columns=se_cols))
.tab_style(style=style.fill(color="#D3E4F5"), locations=loc.column_labels(columns=est_cols))
.tab_style(style=style.fill(color="#F6E0C4"), locations=loc.column_labels(columns=se_cols))
)
for package in packages:
# narrower spanners first so the package spanner sits on top
package_columns = []
for computation in computations:
est_col, se_col = f"{package}.{computation}.est", f"{package}.{computation}.se"
if est_col not in frame:
continue
gt = gt.tab_spanner(
computation, columns=[est_col, se_col], id=f"{package}|{computation}"
)
package_columns += [est_col, se_col]
gt = gt.tab_spanner(package, columns=package_columns, id=f"{package}|pkg")
if len(packages) > 1:
divider = "#8A8A8A"
second_package = packages[1]
first_computation = next(
computation for package, computation in pairs if package == second_package
)
first_of_second = f"{second_package}.{first_computation}.est"
gt = gt.tab_style(
style=style.borders(sides="left", color=divider, style="solid", weight=px(2)),
locations=[
loc.body(columns=first_of_second),
loc.column_labels(columns=first_of_second),
loc.spanner_labels(ids=[f"{second_package}|pkg"]),
loc.spanner_labels(ids=[f"{second_package}|{first_computation}"]),
],
)
return gt