spb/wp5_uqo Public
UQO Working Paper No. 5 — Airbnb, residential rents and housing market pressure.
TeX 53.4%
Python 46.5%
1# Author: Simon-Pierre Boucher — contact@spboucher.ai2"""3Shared LaTeX table helpers for the regression scripts.45`significance_star` and `results_to_latex` reproduce byte-for-byte the table6format of the published tables (stargazer-style booktabs tables with HC17robust standard errors in parentheses).89Tables are written as *fragments* (no ``\\begin{table}`` wrapper): the paper10wraps each ``\\input`` in its own ``table`` environment with caption and label.11"""1213from pathlib import Path141516def significance_star(pval: float) -> str:17 """Return conventional significance stars for a p-value."""18 if pval < 0.01:19 return "***"20 elif pval < 0.05:21 return "**"22 elif pval < 0.10:23 return "*"24 return ""252627def results_to_latex(28 results_list: list,29 model_names: list[str],30 dep_var: str,31 display_vars: list[str] | None = None,32 out_path: Path | None = None,33 note: str = "",34) -> str:35 """36 Produce a stargazer-style LaTeX table from a list of OLS results.3738 Parameters39 ----------40 results_list : list of statsmodels RegressionResultsWrapper41 model_names : column headers for each model42 dep_var : dependent variable label for the table caption row43 display_vars : subset of variable names to display (None = all)44 out_path : file to write; None = no write45 note : optional footnote text46 """47 n_models = len(results_list)4849 # Collect the union of variable names across all models50 if display_vars is None:51 all_vars: list[str] = []52 for res in results_list:53 for v in res.params.index:54 if v not in all_vars:55 all_vars.append(v)56 display_vars = all_vars5758 # Build LaTeX59 col_spec = "l" + "c" * n_models60 lines: list[str] = []61 lines.append(r"\small")62 lines.append(r"\begin{tabular}{" + col_spec + "}")63 lines.append(r"\toprule")6465 # Header66 header = " & ".join([""] + [f"\\textbf{{{mn}}}" for mn in model_names]) + r" \\"67 lines.append(header)68 lines.append(69 " & ".join(["Dep.\\ var:"] + [f"\\textit{{{dep_var}}}" for _ in model_names])70 + r" \\"71 )72 lines.append(r"\midrule")7374 # Coefficients75 for var in display_vars:76 coef_cells = []77 se_cells = []78 for res in results_list:79 if var in res.params.index:80 b = res.params[var]81 se = res.bse[var]82 p = res.pvalues[var]83 star = significance_star(p)84 coef_cells.append(f"{b:.4f}{star}")85 se_cells.append(f"({se:.4f})")86 else:87 coef_cells.append("")88 se_cells.append("")89 # Pretty variable name90 vname = var.replace("_", r"\_")91 lines.append(" & ".join([vname] + coef_cells) + r" \\")92 lines.append(" & ".join([""] + se_cells) + r" \\[4pt]")9394 lines.append(r"\midrule")9596 # Fit statistics97 for label, accessor in [98 ("Observations", lambda r: f"{int(r.nobs)}"),99 ("R$^2$", lambda r: f"{r.rsquared:.4f}"),100 ("Adj.\\ R$^2$", lambda r: f"{r.rsquared_adj:.4f}"),101 ]:102 cells = [label]103 for res in results_list:104 try:105 cells.append(accessor(res))106 except Exception:107 cells.append("")108 lines.append(" & ".join(cells) + r" \\")109110 lines.append(r"\bottomrule")111 lines.append(r"\end{tabular}")112113 # Note114 if note:115 lines.append(r"\vspace{4pt}")116 lines.append(r"\parbox{\textwidth}{\footnotesize " + note + "}")117118 lines.append(119 r"\parbox{\textwidth}{\footnotesize Robust (HC1) standard errors in "120 r"parentheses. $^{***}p<0.01$; $^{**}p<0.05$; $^{*}p<0.10$.}"121 )122123 tex = "\n".join(lines) + "\n"124125 if out_path is not None:126 out_path.write_text(tex, encoding="utf-8")127 print(f" -> saved {out_path}")128129 return tex130