v0.4.11 — Kuznets waves + convergence-clubs correctness fixes
This release supersedes the unreleased 0.4.10, so it brings both the new Kuznets-waves analysis and the convergence-clubs fixes to PyPI in one step.
Added — analyze_kuznets_waves (the extended Kuznets curve)
Tests the inequality–development relationship taken up to a quartic, gini = b₁g + b₂g² + b₃g³ + b₄g⁴ (g = log GDP per capita), under three panel estimators side by side: pooled OLS, the between estimator (the cross-country curve, a polynomial in the entity means) and the within estimator (two-way country + year fixed effects). Each is a cumulative-stepwise (csw) comparison table — linear, then quadratic, up to the full degree-order polynomial. Three figures tell the pooled → between → within story: a raw scatter with the pooled wave overlaid, and between/within Frisch–Waugh–Lovell partial-residual (component) plots that draw the fitted wave once optional controls (and the two-way fixed effects) are partialled out. The result exposes gt_pooled / gt_between / gt_within, the three figures, a per-estimator curvature summary (turning points, peak, top-order term), the fitted models, and .interpret() / .explain(). Ships with a learn_kuznets_waves() sandbox, a kuznets_waves concept explainer, a Streamlit Kuznets waves tab, and a Quarto → Colab notebook.
Fixed — analyze_convergence_clubs (Phillips-Sul clustering)
- The default
method="adjust"(Schnurbus et al. 2016) club refinement scored each candidate against the core group rather than the growing club and lacked a final joint-test fallback, so it could emit a group labelled a convergence "club" whose own log(t) t-statistic was below the threshold. It now scores against the accumulating club and falls back to the core when the refined club still fails (matching themethod="ps"branch). - A variable whose per-period cross-sectional mean is at/near zero (a demeaned, centered or growth series) made the relative transition
h = x/meanblow up toinfand silently corrupt every frame and figure — it now raises a clear error. - A constant / already-identical panel produced a non-finite global log(t) statistic that was silently reported as "divergent" (printing a literal
NaN) — it now raises a clear "not estimable" error. - The user-supplied
tcritthreshold is now threaded into the summary table'sconvergingcolumn, the table source-note and.interpret()(previously hardcoded to-1.65), and is exposed onConvergenceClubsResult.tcrit.
Full changelog: https://cmg777.github.io/expdpy/changelog.html