🇬🇧 English · 🇪🇸 Español
Avisos de corrección
Se emite un aviso de corrección cuando una versión publicada de puremacro devolvió un número equivocado — no un fallo, no una función ausente, sino una respuesta bien formada y falsa. La distinción importa porque un fallo se denuncia solo y un número equivocado no: acaba en un cuadro, en una figura, en un dictamen.
Cada aviso nombra las versiones afectadas, la condición exacta bajo la cual el error se anula (para que pueda descartar su propia estimación sin volver a correrla) y qué hacer.
2026-10-02 — Grados de libertad de la posterior de Σ en minnesota_gibbs, versiones 0.92.0 a 4.4.0
Corregido después de 4.4.0 (véase la sección Unreleased de CHANGELOG.md).
Bańbura, Giannone y Reichlin (2010; ECB WP 966, p. 12, ec. 7) añaden la
previa impropia |Ψ|^-(n+3)/2 a las observaciones ficticias, lo que da
Ψ | Y ~ iW(Σ̃, T_d + 2 + T - k). minnesota_gibbs usaba T_d + T - k. La
media posterior de Σ, Σ̃ / (ν - n - 1), era por tanto demasiado grande en el
factor (ν - n + 1)/(ν - n - 1): 5.3% en un VAR(1) de 3 variables con 39
observaciones, 1.0% con 3 variables, 4 rezagos y 200 trimestres. Los
coeficientes simulados heredan la escala a través de Σ ⊗ (X*'X*)⁻¹, así que
su dispersión posterior era demasiado amplia en cerca de la mitad de ese
porcentaje. La media posterior de los coeficientes (A_mean,
intercept_mean), minnesota_posterior y la verosimilitud marginal de
minnesota_optimal_lambda no se ven afectadas.
| Superficie | Condición afectada | No afectada cuando | Recomendación |
|---|---|---|---|
Sigma_draws, nu_post y bandas posteriores de A_draws/intercept_draws de minnesota_gibbs |
siempre | estimaciones puntuales de A_mean/intercept_mean |
Vuelva a correr; el efecto decrece como 2/(T + T_d - k - n). |
¿Le afecta?
T, n = Y.shape # sus datos y el orden de rezagos p
nu_old = (T - p) + (n * p + n + 1) - (n * p + 1) # T + T_d - k que usaba 4.4.0
(nu_old - n + 1) / (nu_old - n - 1) - 1 # sobreestimación relativa de E[Σ | Y]
Qué hay que volver a correr
- Bandas de credibilidad de respuestas al impulso, pronósticos y
descomposiciones de varianza calculadas con simulaciones de
minnesota_gibbs, sobre todo con muestras cortas o sistemas grandes.
2026-10-02 — Los solvers de splines y Smolyak ignoraban gamma y resolvían utilidad logarítmica en sus métodos de Bellman, versiones 3.3.0 a 4.4.0
Corregido después de 4.4.0 (véase la sección Unreleased de CHANGELOG.md).
Tres errores relacionados en el modelo de crecimiento incorporado de
puremacro.vfi.splines y puremacro.vfi.smolyak, verificados con la ecuación
de Euler del modelo CRRA escrita a mano:
- Ambos leían solo
params["sigma"].params={"gamma": 2}(la grafía deCollocationProblem,FEMProblemy los motores discretos) resolvía en silencio utilidad logarítmica: residuo de Euler 0.151 (splines) y 0.0345 (Smolyak, 2 capitales) en la política devuelta, que informabaconverged=True. - El solver de Bellman con splines (
method="bellman") usaba utilidad logarítmica con cualquier curvatura: residuo 0.151 consigma=2. solve_smolyak(method="bellman")iteraba sobre la política cerradak'_m = alpha_m beta Yde utilidad logarítmica con depreciación total y la devolvía conconverged=Truepara cualquiersigma,gamma,deltaoreturn_fn(residuo 0.0345 consigma=2). Ahora lanzaNotImplementedErrorfuera de ese caso.
| Superficie | Condición afectada | No afectada cuando | Recomendación |
|---|---|---|---|
splines y Smolyak con method="euler" |
params tiene gamma y no sigma |
se da sigma, o curvatura 1 |
Vuelva a correr con la versión corregida, o pase sigma. |
splines con method="bellman" |
sigma (o gamma) ≠ 1 |
utilidad logarítmica | Vuelva a correr con la versión corregida. |
solve_smolyak(method="bellman") |
sigma/gamma ≠ 1, delta ≠ 1 o un return_fn |
utilidad logarítmica con depreciación total | Use method="euler". |
¿Le afecta?
p = problem.params
curv = p.get("sigma", p.get("gamma", 1.0))
("gamma" in p and "sigma" not in p and curv != 1.0) \
or (problem.method == "bellman" and (curv != 1.0 or p.get("delta", 1.0) != 1.0)) # True → vuelva a correr
Qué hay que volver a correr
- Políticas, funciones de valor, valores marginales y gradientes IFT de estos solvers con utilidad no logarítmica (y, para Bellman con Smolyak, depreciación parcial).
2026-10-02 — vif con datos en niveles y constante, versiones 2.6.0 a 4.3.0
Corregido en 4.4.0. inference.collinearity.vif reproducía
variance_inflation_factor de statsmodels operación por operación, incluidas
sus regresiones auxiliares sobre los niveles sin centrar. Cuando la media de
los regresores es grande respecto a su dispersión, esas regresiones sufren una
cancelación catastrófica y el VIF pierde dígitos, o todos. Con una columna
constante explícita el VIF es exactamente invariante a desplazar cualquier
columna, así que las columnas no constantes se calculan ahora con datos
centrados; el resultado coincide con la aritmética racional exacta hasta
0.33 * eps * max VIF en diseños de prueba con medias de hasta 1e9.
Medido en 4.3.0 (statsmodels devuelve los mismos números): tres regresores
normales estándar desplazados a media 1e7 daban 1.007122 frente a un exacto
de 1.007165 (4e-5 relativo); una tasa de interés junto a un PIB en yenes
(escala 2e15) daba 0.053, imposible porque todo VIF es al menos 1 (exacto:
1.005); y diseños aleatorios desplazados erraban hasta en 99%.
| Superficie | Condición afectada | No afectada cuando | Recomendación |
|---|---|---|---|
vif |
exog tiene una columna constante explícita y regresores cuya media es grande respecto a su desviación estándar (datos en niveles) |
los regresores tienen media cercana a cero o se centran antes de la llamada; el VIF de la propia columna constante; diseños sin columna constante | Vuelva a correr con 4.4.0. En los diseños afectados los valores ahora difieren de statsmodels, que conserva el error. |
¿Le afecta?
X # su diseño, con una columna constante
abs(X[:, 1:].mean(axis=0) / X[:, 1:].std(axis=0)).max() # por encima de ~1e5 → vuelva a correr
El error de 4.3.0 crece con esa razón: por debajo de 4e-12 relativo hasta
1e5, 3e-8 en 1e6, 1e-4 en 1e7, y más cuando los regresores además
son casi colineales o tienen tendencia (el ejemplo del PIB arriba).
Qué hay que volver a correr
- Cualquier diagnóstico de colinealidad con datos en niveles (PIB, índices
de precios, población) calculado con
vify un intercepto. Los datos centrados o en tasas de crecimiento no se vieron afectados.
2026-09-30 — choques de margen de Smets-Wouters (2007), datos incluidos y objetivos de replicación, versiones 0.92.0 a 4.3.0
Corregido después de 4.3.0 (véase la sección Unreleased de CHANGELOG.md).
Lo encontró la revisión de cuadernos del 30 de septiembre, como todas las
entradas fechadas el 2026-09-30. En la evidencia de Smets-Wouters (2007)
coincidían tres errores distintos.
- En el modelo programado a mano (
dsge.smets_wouters), los procesos de margen de precios y salarios eranspinf_t = crhopinf*spinf_{t-1} + epinf_{t-1}y lo mismo parasw/ew: sin término MA y con un trimestre de retraso. SW07 (ECB WP 722, pp. 14-15) y el.modde Pfeifer incluido tienen+ epinf_t - cmap*epinf_{t-1}. Por esocmapycmawnunca entraban en el modelo,estimate_sw07devolvía su distribución a priori como posterior, y las respuestas aepinf/eweran erróneas incluso concmap = cmaw = 0. Con la calibración del.mod, la respuesta de la inflación a un choque unitarioepinfen los trimestres 0-2 era 0.932, 1.416, 0.255; es 1.177, 0.307, -0.060. Los otros cinco choques eran correctos. - El
_sw07_data.csvincluido medía las horas comolog(HOANBS/pop), 1/100 del100*log(horas medias NFB x empleo / pob)de SW07, y el consumo y la inversión como PCE encadenado e inversión con existencias, en lugar de PCE nominal e inversión fija deflactados por el deflactor del PIB (correlación con las series del propio SW: horas 0.950, crecimiento de la inversión 0.624). Toda verosimilitud sobre los datos incluidos está afectada, tanto con el modelo nativo como consw07_pfeifer.mod. - Los objetivos de replicación -1673.72, -1686.09 y -2524.36 (log posterior y
verosimilitudes marginales de Laplace y de media armónica) eran salidas de
puremacro citadas como cuadros 1 y 2 de SW07, y el caso de la "moda"
comparaba la mejor de 200 extracciones MCMC con las medias a posteriori
del cuadro 1a. Además, los casos leían su fixture de
tests/fixtures, así que fallaban en una rueda instalada (desde 2.6.0).
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
solve_sw07, smets_wouters._shock_irf y todo lo construido sobre ellos |
Respuestas, FEVD o descomposiciones con epinf o ew |
Los otros cinco choques (ea, eb, eg, eqs, em) |
Volver a correr. Las respuestas de los siete choques coinciden ahora con la solución del .mod hasta 1e-12. |
estimate_sw07, sw07_observation.make_state_space |
Siempre: cambiaron el modelo y los datos | Nunca | Volver a estimar. No compare log posteriores ni verosimilitudes marginales antiguas con las nuevas. |
_sw07_data.csv con sw07_pfeifer.mod (cuadernos 41 y 42) |
Cualquier estimación, suavizado, descomposición de choques o verosimilitud marginal sobre los datos incluidos | Sus propios datos | Volver a correr con el archivo reconstruido. |
Casos de replicación dsge_estimation (2.6.0 a 4.3.0) |
Siempre | Nunca | Los objetivos se etiquetan ahora como valores de regresión de puremacro (-822.04, -902.83, -908.03); el caso de la moda compara una moda optimizada con la columna Mode del cuadro 1 (13 parámetros, todos a menos de 6.2%). |
¿Le afecta?
import pandas as pd
from importlib.resources import files
d = pd.read_csv(files("puremacro.dsge") / "_sw07_data.csv", comment="#")
d["log_hours"].std() # cerca de 0.046: los datos de 4.3.0; cerca de 2.9: los reconstruidos
Cualquier número de SW07 calculado con los datos de 4.3.0, y cualquier respuesta de SW07 a un choque de margen del modelo nativo, está afectado.
Qué hay que volver a correr
- Cualquier estimación, verosimilitud marginal, suavizado o descomposición de
choques de SW07 sobre los datos incluidos, nativa o con el
.mod. - Cualquier respuesta, FEVD o descomposición de
solve_sw07conepinfoew. - Cualquier cita de -1673.72, -1686.09 o -2524.36 como resultados de SW07.
Con las correcciones, la moda a posteriori optimizada sobre los datos
incluidos tiene log posterior -822.04 y log densidad marginal de Laplace
-902.83. El -905.8 del propio SW07 (cuadro 2) se calcula sobre 1966-2004 con
1956:1-1965:4 como muestra de entrenamiento; desde 4.6.0
sw07_laplace_mddreproduce ese cálculo sobre los datos de los autores (presample e inicialización difusa) y da -932.3, y Dynare 8 sobre los archivos públicos de replicación y la moda de los autores da -923.1 con las opciones del archivo (puremacro en el mismo punto: -922.4). Ninguno reproduce el -905.8 impreso, que sigue sin ser un objetivo comparable (véasedocs/replication.md). - En este repositorio: los cuadernos 41 y 42 (inglés y español),
docs/replication.mdy el borrador para JOSS citan los números afectados.
2026-09-30 — variables locales de modelo de .mod congeladas en la calibración, versiones 2.0.0 a 4.3.0
Corregido después de 4.3.0. Una variable local de modelo de un .mod
definida sólo con parámetros (#cbeta = 1/(1+constebeta/100);) se evaluaba
una vez, con la calibración del archivo, y el número se insertaba en las
ecuaciones (desde 2.7.0; el lector por expresiones regulares, el único de
2.0.0 a 2.6.0 y una alternativa de reserva desde entonces, la guardaba como un
parámetro ficticio). Dynare sustituye la expresión. Todo
cálculo que vuelve a resolver el modelo con otros valores de los parámetros
usaba por tanto un modelo híbrido: se movían los parámetros que aparecen
directamente en las ecuaciones, pero no las variables locales construidas con
ellos.
En sw07_pfeifer.mod, constebeta entra en el modelo sólo a través de
variables locales, así que su verosimilitud era exactamente plana y su
posterior igual a su a priori; csigma, ctrend, constepinf, calfa, cg,
ctou y clandaw entraban sólo en parte. Volver a resolver con
csigma = 2.5 daba sd(y) = 30.1307 en lugar de 29.9343 (una carga nueva). Con
los datos incluidos actuales, la log-verosimilitud en los valores iniciales de
estimated_params es -1766.35, no -1776.93, y constebeta en 0.5 / 1.0 / 1.5
da -1749.77 / -1794.92 / -1881.05, donde los tres daban -1776.93.
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
load_mod(..., params=), osr y búsquedas de política óptima, widgets de parámetros, SMC, gradientes analíticos y NUTS, identification(), LinearModel.estimate() / estimate_dsge sobre un modelo .mod |
El modelo tiene una variable local # cuyo lado derecho sólo contiene parámetros y números, y el cálculo movió uno de esos parámetros |
Resultados con la propia calibración del archivo; variables locales con variables endógenas; modelos escritos como funciones de residuos en Python; estimate_sw07 programado a mano |
Volver a correr con la versión corregida. |
load_mod(..., params=) con un bloque steady_state_model o initval |
El bloque depende de un parámetro modificado | Sin esa dependencia | Lanzaba SteadyStateError; ahora reevalúa el bloque con los nuevos valores. |
Nombres de parámetros o variables que son palabras clave de Python (lambda, yield) |
Siempre | Otros nombres | Lanzaban SyntaxError o ValueError; ahora se analizan. |
¿Le afecta?
Busque en el bloque model; una línea que empiece con # y cuyo lado derecho
sólo contenga parámetros y números. Si la hay, y corrió algún cálculo de la
primera fila con valores de los parámetros distintos de la calibración del
archivo, le afecta.
Qué hay que volver a correr
- Cualquier estimación, análisis de identificación, búsqueda
osr, gradiente o resultado de estática comparativa obtenido de un.modasí. - En este repositorio: los cuadernos 41 y 42 y la lección T02_E del curso
(
sw07_pfeifer.mod).
2026-09-30 — identification() evaluada en una mezcla de la calibración y el punto pedido, versiones 2.6.0 a 4.3.0
Corregido después de 4.3.0. dsge.identification y
LinearModel.identification calculaban todas las cantidades reportadas
(rangos, is_identified, valores singulares, números de condición,
combinaciones del espacio nulo, colinealidad, fuerza de Ratto) a partir de una
mezcla de la calibración y el punto que pedía el usuario. Cada columna
estructural movía sólo su propio parámetro fuera de la calibración; las
columnas de choques y de errores de medida usaban la solución calibrada, con
SE_/CORR_ dados sólo por nombre tomados en 1 y 0 en lugar de los valores
declarados; y la diferencia unilateral de reserva restaba la solución
calibrada (en un AR(1) devolvía -78,594.7 donde el valor verdadero es 1.78).
prior_mc perturbaba los valores base en un 5% en lugar de extraer de las
distribuciones a priori. Además, build_dynare detecta numéricamente las
variables predeterminadas en la calibración, así que un rezago calibrado en 0
desaparecía de toda nueva resolución y toda derivada respecto de su
coeficiente valía exactamente cero.
Parámetros realmente no identificados podían reportarse como identificados (un
par k1*k2 en un .mod cuyas medias a priori difieren de la calibración
mostraba rangos 2/2/2/2 en lugar de 1/1/1/1), y parámetros identificados como
no identificados: crhoms, crhopinf, crhow, cmap y cmaw de SW07,
calibrados en 0, tenían sensibilidad exactamente 0, con rangos 29/31/29/29 de
36 en la llamada por defecto en lugar de 34/36/34/34.
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
identification() con params={...}, p_dict, EstimatedParams o una lista de nombres sobre un .mod con estimated_params |
El punto analizado (valores, INITVAL o medias a priori) difiere de la calibración | El punto es la calibración y no se aplica ninguna de las filas siguientes | Volver a correr. |
La llamada por defecto sobre un .mod con estimated_params |
Los INITVAL o las medias a priori difieren de la calibración | Coinciden con ella | Volver a correr. |
prior_mc > 0 |
Siempre | Nunca | Volver a correr; las tasas de identificación no se basaban en las a priori. |
| Un parámetro en una cota declarada, o a menos de un paso de diferencias finitas de ella | Siempre | Lejos de las cotas | Volver a correr. |
Modelos build(..., linearize="level") |
Un estado estacionario positivo, incluso en la calibración | Modelos log-linealizados o con estado estacionario cero | Volver a correr. |
SE_<shock>, CORR_<s1>_<s2> o ME_<obs> dados por nombre |
La covarianza declarada de los choques no es la identidad, o hay error de medida declarado, incluso en la calibración | Covarianza identidad, sin error de medida | Volver a correr; los SE_/ME_ por nombre usan ahora los valores declarados. |
Modelos build_dynare / load_mod |
Un coeficiente de rezago vale 0 en la calibración y un parámetro analizado, o el punto pedido, lo vuelve distinto de cero | Ningún rezago calibrado en 0 | Volver a correr. |
LinearModel.estimate(check_identification=True/"raise") |
Cualquiera de las condiciones anteriores en el punto de partida de la estimación | Como arriba | La comprobación previa podía dejar pasar un modelo no identificado o fallar sin motivo. |
¿Le afecta?
Sólo eran correctos los resultados calculados en la calibración, sin
prior_mc, lejos de las cotas y sobre un modelo no cubierto por las cuatro
últimas filas del cuadro. En otro caso, vuelva a correrlos con la versión
corregida. Tenga en cuenta que un punto pedido sin solución estable única
lanza ahora ValueError.
Qué hay que volver a correr
- Cualquier análisis de identificación en los casos anteriores, incluidos los rangos y las ordenaciones por fuerza reportados para Smets-Wouters (2007).
- En este repositorio: el cuaderno 45 llama a
identification()en la calibración, donde el defecto no actúa; sus números no cambian.
2026-09-30 — HANK de dos activos en el espacio de secuencias, versiones 3.1.0 a 4.3.0
Corregido después de 4.3.0. Los resultados del solver de dos activos
anteriores a esta corrección no son válidos. La iteración de los hogares nunca
convergía: se quedaba en un ciclo de periodo 2 (cambio en norma del supremo
0.39) mientras converged valía siempre True. Con la calibración por defecto,
β(1+r_a) = 1.0146 > 1, así que toda la riqueza ilíquida se acumulaba en el
techo de la malla a_max = 30. Los jacobianos Fake-News no tenían términos de
anticipación (su triángulo superior estricto era cero) ni el desplazamiento ex
ante de fecha para r_b, y se perdía riqueza donde se recortaba b' > b_max. La
respuesta de equilibrio general a un choque monetario dependía por tanto del
horizonte: tras un recorte de 25 pb, el consumo en el impacto era -0.0038 con
T = 16, +0.0014 con T = 20, -0.0045 con T = 30 y -0.0027 con T = 40, y las
respuestas no se amortiguaban.
Con la corrección, las mismas llamadas dan +0.0031 en todo horizonte de 16 a
300 y las respuestas se amortiguan; el estado estacionario tiene A = 4.59,
B = 0.61 y una proporción de hogares que viven al día de 0.39, sin masa en
a_max. Cambian los valores por defecto (β de 0.985 a 0.98, r_b_ss de 0.01 a
0.005, r_a_ss de 0.03 a 0.0125, chi_0 de 0.25 a 1.0, a_max de 30 a 40,
b_max de 15 a 10, nuevo a_bar = 0.25), steady_state["Y"] es C + CHI, y
los jacobianos son los del sector hogares cerrado con la regla de ingreso
z_t N = Y_t - r^b_t B_{t-1} - r^a_t A_{t-1}, con la que la riqueza total A + B
es constante en equilibrio.
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
solve_two_asset_hank_sequence_space |
Siempre | Nunca | Volver a correr con la versión corregida; su calibración es otra, así que compare formas, no niveles. |
solve_hank_bridge sobre hank_two_asset.mod, HANKModel con assets = 2 |
Siempre | Nunca | Volver a correr. |
Solver de un activo (solve_hank_sequence_space, hank_ssj.mod) |
— | Siempre: sus resultados son idénticos bit a bit | Nada que hacer. |
¿Le afecta?
Cualquier número de las tres superficies de dos activos de arriba en
3.1.0-4.3.0. Un estado estacionario de riqueza ilíquida igual a a_max, o una
respuesta cuyo signo cambia con el horizonte T, es la señal.
Qué hay que volver a correr
- Cualquier respuesta, jacobiano o estado estacionario del HANK de dos activos.
- En este repositorio: el cuaderno 46 (inglés y español) imprimía un consumo en el impacto de -0.0038 mientras su texto dice que sube; la llamada da ahora +0.0031. El solver corregido es un modelo docente estilizado, contrastado con jacobianos por fuerza bruta, identidades presupuestarias e invariancia al horizonte, no con resultados publicados de dos activos.
2026-09-30 — estimación de VAR con cambio de régimen de Markov, versiones 0.92.0 a 4.3.0
Corregido después de 4.3.0. El paso M del EM de var.regime.ms_var_fit
actualizaba la matriz AR común por MCO sin ponderar, ignorando las covarianzas
de cada régimen. Cuando las varianzas de los regímenes difieren, ese paso no
maximiza el objetivo del EM: la log-verosimilitud podía bajar de una iteración
a otra y el ajuste se detenía por debajo del estimador de máxima verosimilitud
mientras reportaba converged=True. Una cresta absoluta de 1e-8 sobre cada
covarianza de régimen hacía además que las estimaciones dependieran de las
unidades de los datos. El docstring afirmaba que la función reproduce Hamilton
(1989); estima otro modelo, con intercepto y varianza cambiantes (MSIH) y una
matriz AR común.
Con los datos de crecimiento del PNB de Hamilton (K = 2, p = 4), la llamada por defecto devolvía loglik -180.48, sin converger; su régimen de intercepto bajo tenía un intercepto positivo (0.31), P(permanecer) = 0.87 y cubría 66 de 131 trimestres. El ajuste corregido da loglik -179.16, interceptos 1.21 y -0.06, P(permanecer en el bajo) = 0.79 y 35 trimestres de media baja. Con una variable en unidades 1e-4 veces menores, el ajuste antiguo perdía 173 puntos de log-verosimilitud.
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
Estimaciones de ms_var_fit, probabilidades filtradas y suavizadas, y girf construido sobre ellas |
Varianzas de régimen distintas, o una variable con varianza absoluta pequeña (por ejemplo tasas en decimales) | Varianzas de régimen casi iguales y variables de escala unitaria (el ejemplo de ciclo económico incluido cambia poco: acierto de 98.0% a 97.2%) | Volver a estimar; revise loglik_path, converged y sigma_at_floor. |
Afirmaciones de que ms_var_fit reproduce Hamilton (1989) |
Siempre | — | Para el cuadro I de Hamilton use MarkovAutoregression(k_regimes=2, order=4, switching_ar=False) de statsmodels. |
¿Le afecta?
Vuelva a ajustar con la versión corregida y compare loglik: un valor mayor
significa que la estimación antigua no era el máximo. En la versión antigua,
un resultado con converged=False, o con n_iter igual al tope (100 por
defecto), indica que se detuvo antes de tiempo.
Qué hay que volver a correr
- Cualquier datación de regímenes, matriz de transición o respuesta
dependiente del régimen de
ms_var_fit. - En este repositorio: el cuaderno 16 y el ejemplo
ms_var_business_cycle.
2026-09-30 — errores estándar de Windmeijer en dos etapas para paneles dinámicos, versiones 0.92.0 a 4.3.0
Corregido después de 4.3.0. dynpanel.ab_gmm y dynpanel.bb_gmm con los
valores por defecto two_step=True, windmeijer=True calculaban sus errores
estándar con la derivada de la matriz de pesos evaluada en los residuos de la
segunda etapa. Windmeijer (2005) y Stata usan los residuos de la primera etapa.
Los coeficientes no estaban afectados. Aparte, collapse=False, que es la
disposición por defecto de Stata, lanzaba LinAlgError ("step1 weight Z'HZ:
matrix is not positive definite") en todo modelo con dos o más rezagos de la
variable dependiente o con regresores exógenos rezagados, porque se conservaba
una columna de instrumentos toda en cero.
Con cualquier valor de collapse, una matriz de pesos singular por cualquier
otro motivo (por ejemplo, una columna de instrumentos que es combinación lineal
de otras, como producen collapse=False en paneles no balanceados y las
variables dicotómicas de año en el GMM de sistema) se invierte ahora con la inversa generalizada de Moore-Penrose, como hace
xtabond2, y las notes del resultado registran su rango (un RuntimeWarning
lo repite). En ese caso n_instruments informa el rango de la matriz de pesos
de la primera etapa (el e(j) de xtabond2) en lugar del número de columnas de
Z. Los resultados en dos etapas con una matriz de la segunda etapa singular
dependen de la inversa generalizada y pueden diferir de xtabond2; una matriz de
la segunda etapa singular no reduce n_instruments ni los grados de libertad
de la J de Hansen.
En el ejemplo abdata de Stata ([XT] xtabond, ejemplo 4), quitando a mano la
columna muerta, los errores estándar antiguos eran entre 1.4% y 68% demasiado
grandes (w: 0.2602 frente a 0.1546), así que ahí la inferencia era demasiado
conservadora. Con la disposición colapsada por defecto el error suele quedar
por debajo del 2% y va en cualquier dirección (antiguo frente a corregido:
0.554759 frente a 0.564362 para ab_gmm y 0.084758 frente a 0.082478 para
bb_gmm en paneles simulados; hasta cerca de 4% en abdata). El ab_gmm
corregido reproduce todos los coeficientes y errores estándar publicados de los
ejemplos 1, 2 y 4 de xtabond.
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
Errores estándar, estadísticos z, valores-p e intervalos de ab_gmm, bb_gmm |
two_step=True y windmeijer=True (los valores por defecto) |
two_step=False, o windmeijer=False; los coeficientes estimados en todos los casos |
Volver a correr y sustituir los errores estándar reportados. |
diagnostics.windmeijer_correction llamado directamente |
Sin el nuevo residuals_step1= |
Con él | Pase los residuos de la primera etapa; la llamada antigua advierte. |
collapse=False |
lag_dep_var >= 2, regresores exógenos rezagados o huecos |
Otras disposiciones | Lanzaba un error; ahora poda las columnas muertas, como Stata. |
Una matriz de pesos singular (cualquier collapse) |
Columnas de instrumentos linealmente dependientes | Matrices de pesos de rango completo | Inversa generalizada de Moore-Penrose; las notes registran el rango y n_instruments lo informa. Los resultados en dos etapas con una matriz de la segunda etapa singular pueden diferir de xtabond2. |
¿Le afecta?
Toda estimación en dos etapas con la corrección de Windmeijer, es decir, toda llamada con los valores por defecto. Sólo cambian los errores estándar y lo que se construye sobre ellos.
Qué hay que volver a correr
- Estimaciones de panel dinámico en dos etapas: sustituya sus errores
estándar. Para coincidir con
xtabondde Stata, usecollapse=False(ytwo_step=False, robust=Falsepara su VCE homocedástica de una etapa).
2026-09-30 — a priori de Minnesota mal centrada con λ₂ ≠ 1, versiones 0.92.0 a 4.3.0
Corregido después de 4.3.0. En var.bvar._build_minnesota_dummies, las
observaciones ficticias que usan minnesota_gibbs, su verosimilitud marginal
y minnesota_optimal_lambda escribían cada celda (rezago, variable) una vez
por ecuación, y ganaba la última ecuación. Con el valor por defecto λ₂ = 0.5,
el primer rezago propio de toda variable salvo la última de la lista se
centraba en 0.5 en lugar de 1 (el paseo aleatorio), con desviación típica a
priori λ₁λ₂ en lugar de λ₁; la última variable ignoraba λ₂ en las ecuaciones
cruzadas; y los resultados dependían del orden de las columnas. En el límite de
a priori muy ajustada (λ₁ = 1e-4), minnesota_gibbs devolvía
A1 = diag(0.5, 0.5, 1.0) en lugar de I. La a priori conjugada normal-Wishart
inversa no puede representar λ₂ ≠ 1: Bańbura, Giannone y Reichlin (2010) lo
imponen "bajo la condición θ = 1". El caso de validación estaba fijado en
λ₂ = 1, el único valor en que el error no puede verse.
El bloque es ahora la ec. (5) de BGR; las rutas NIW usan λ₂ = 1 por defecto y cualquier otro valor advierte y usa 1. En un VAR(1) de 3 variables con T = 200 y los valores por defecto, la media posterior de Gibbs de A1[0,0] pasa de 0.501 a 0.545.
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
minnesota_gibbs, minnesota_optimal_lambda y su verosimilitud marginal |
λ₂ ≠ 1, lo que incluye el antiguo valor por defecto 0.5 | λ₂ = 1 | Volver a correr. Para una media posterior con λ₂ < 1 use minnesota_posterior; no existe posterior NIW con λ₂ < 1. |
minnesota_posterior, bvar_sv |
— | Siempre | Nada que hacer. |
¿Le afecta?
res = minnesota_gibbs(...) # su llamada en 4.3.0 o antes
res["lambda2"] # cualquier valor distinto de 1.0 (0.5 por defecto) → le afecta
Qué hay que volver a correr
- Cualquier análisis construido sobre
minnesota_gibbsominnesota_optimal_lambda. - En este repositorio: los ejemplos
bvar_fan_chart(la banda del 80% en h = 4 pasa de [-0.876, +0.692] a [-0.947, +0.707]),posterior_predictive_fan,mcmc_diagnostics(la media de la cadena de A1[0,0] pasa de 0.51 a 0.56),gk_robust_from_gibbsyglp_lambda_search(el λ₁ elegido pasa de 0.2 a 0.3).
2026-09-30 — intervalos de DiD sintético, y DiD silencioso con resultados en unidades grandes, versiones 0.92.0 a 4.3.0
Corregido después de 4.3.0. Dos defectos de did.synthetic_did, y de
sdid_multi_cohort a través de sus estimaciones puntuales.
- Intervalos con cobertura insuficiente.
se,loyhisalían de un bootstrap que remuestreaba sólo las unidades donantes y dejaba fijas las tratadas, con un intervalo por percentiles, de modo que se omitía el ruido propio de las unidades tratadas. Con una unidad tratada, un intervalo nominal del 90% cubría el valor verdadero entre el 50% y el 67% de las veces en Monte Carlo, y elsereportado era cerca de la mitad de la desviación típica verdadera (diseño del cuaderno 29: media 0.13-0.14 frente a 0.23-0.24). En el ejemplo de la documentación, con 8 unidades tratadas, elseera 0.019 frente a una desviación típica verdadera de cerca de 0.057. - Colapso silencioso a diferencias en diferencias. Cuando SLSQP reportaba que no había tenido éxito, los pesos volvían a ser uniformes (1/N_co para ω, 1/T_pre para λ) sin advertencia, así que τ̂ era la estimación DiD simple. La tolerancia de SLSQP es absoluta, por lo que esto ocurría sobre todo con resultados en unidades grandes (los datos del cuaderno 29 multiplicados por 10 o más, niveles en los cientos). Con los datos de la Proposición 99 de California del artículo, puremacro devolvía -27.35, el valor DiD, en lugar del SDID -15.6.
El nivel de ruido σ̂ se centraba además periodo a periodo en lugar de como en la ec. (2.2) del artículo; las estimaciones puntuales se mueven cerca de 1e-2 (cuaderno 29: de -4.0940 a -4.0827).
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
se, lo, hi de synthetic_did |
Siempre | n_boot=0 (sin inferencia) |
Volver a correr. El valor por defecto es ahora el estimador placebo (algoritmo 4) para una o dos unidades tratadas y el bootstrap de unidades (algoritmo 2) en otro caso; reporte el se placebo con una o dos unidades tratadas. |
Estimaciones puntuales de synthetic_did y sdid_multi_cohort |
Falló la resolución de los pesos: pesos uniformes | Los pesos no son uniformes | Volver a correr; el solver corregido no depende de la escala y advierte si no converge. |
| Todas las estimaciones puntuales | Siempre, en cerca de 1e-2, por σ̂ | — | Volver a correr si importa el segundo decimal. |
¿Le afecta?
import numpy as np
res = synthetic_did(...) # su llamada en 4.3.0 o antes
np.allclose(res.omega.values, 1 / len(res.omega)) # True → el "SDID" reportado era DiD
Todo error estándar o intervalo de SDID reportado está afectado.
Qué hay que volver a correr
- Todo análisis SDID: las estimaciones puntuales con resultados en unidades grandes y todos los intervalos.
- En este repositorio: el cuaderno 29 (inglés y español; su intervalo del
90% guardado excluye el efecto verdadero),
docs/did.mdy el ejemplosynthetic_did_california_prop99, que usa datos simulados pese a su nombre.
2026-09-30 — agregación de Callaway-Sant'Anna, versiones 0.92.0 a 4.3.0
Corregido después de 4.3.0; cambia el valor por defecto.
did.callaway_santanna calculaba bien sus efectos por grupo y periodo
ATT(g, t), pero los agregaba con pesos iguales por cohorte y presentaba el
resultado como el estimador de Callaway-Sant'Anna. El artículo pondera todo
agregado por el tamaño de la cohorte (arXiv:1803.09015v4: estudio de eventos,
ec. 3.4; resúmenes globales, ecs. 3.10-3.12). att_overall era la media simple
de las celdas ATT(g, t) posteriores al tratamiento, que no coincide con ninguno
de los parámetros globales del artículo. La documentación declaraba la regla
sin ponderar pero la atribuía a CS, y el material docente tenía la comparación
al revés: el propio sun_abraham de puremacro devolvía exactamente las ecs.
3.4 y 3.10 de CS.
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
att_event_study |
Dos o más cohortes identifican un tiempo de evento y difieren en tamaño | Todas las cohortes de ese tiempo de evento tienen el mismo tamaño, o el mismo ATT(g, g+e) | Volver a correr. Ejemplo sin ruido: 2.0 frente a 2.6 en e = 0 con cohortes de 10 y 40 unidades. |
att_overall, y el overall_att del diccionario heredado |
Cualquier heterogeneidad en ATT(g, t) | Todos los ATT(g, t) son iguales (entonces coinciden todos los resúmenes globales) | Ahora es θ^O_sel (ec. 3.11); aggregation= elige los demás. Cuaderno 10: de 1.1292 a 1.1379; curso T05_C: de 7.890 a 6.391 (ahí aggregation="simple" conserva 7.890 y es el estimando de media por celda). |
¿Le afecta?
Con la versión corregida, callaway_santanna(..., aggregation="unweighted")
reproduce exactamente los números antiguos. Córralo junto al valor por
defecto: donde ambos difieran, su resultado antiguo no era el estimando de
Callaway-Sant'Anna.
Qué hay que volver a correr
- Cualquier estudio de eventos o ATT global de Callaway-Sant'Anna sobre un panel cuyas cohortes difieren en tamaño y cuyos efectos difieren entre cohortes o en el tiempo.
- En este repositorio: los cuadernos 10 y 15, las lecciones T05_C y T05_D
del curso,
docs/did.md, el ejemplodid_callaway_santanna_demo(de 1.0142 a 1.0278) y el recorrido de 2.000_whats_new_in_puremacro_2_0(en inglés y en español; ATT global de 1.1876 a 1.0904; su estudio de eventos no cambia porque sus dos cohortes tienen el mismo tamaño).
2026-09-30 — errores estándar de Sun-Abraham, versiones 0.92.0 a 4.3.0
Corregido después de 4.3.0. did.sun_abraham agregaba los errores
estándar por cohorte como si las cohortes fueran independientes,
sqrt(Σ w_g² se_g²). La comparación 2×2 de cada cohorte resta las mismas
unidades de control, así que las estimaciones por cohorte están
correlacionadas. Desde 1.10.0 las bandas lo/hi se construyen con este se
(antes de 1.10.0 tenían el error distinto descrito en la entrada del
2026-09-03), así que lo heredaban. El error va en cualquier dirección: con
errores autocorrelacionados o con tendencia, el se era 0.74 veces la
desviación típica de Monte Carlo en nuestras corridas (0.62 en la
verificación), y las bandas del 90% cubrían el 77%; con errores iid en
cohortes adyacentes era hasta 1.40 veces demasiado grande. Las estimaciones
puntuales se sostienen.
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
se del estudio de eventos (0.92.0 a 4.3.0), lo/hi (1.10.0 a 4.3.0) |
Dos o más cohortes contribuyen a un tiempo de evento | Una cohorte por tiempo de evento | Volver a correr; el se es ahora la desviación típica bootstrap del agregado sobre extracciones conjuntas por unidad (SA 2021, prop. 6). |
att_overall |
No se reportaba error estándar | — | Ahora att_overall_se/_lo/_hi. |
honest_did alimentado con un estudio de eventos de Sun-Abraham |
Como en la primera fila | Como en la primera fila | Volver a correr; pase event_study_vcov a honest_did(sigma=). |
¿Le afecta?
Cualquier tiempo de evento con más de una cohorte. En un panel con tendencia
por unidad, el se en e = 0 pasa de 0.111 a 0.174 (forma cerrada 0.170).
Qué hay que volver a correr
- Cualquier
seo banda del estudio de eventos de Sun-Abraham en un tiempo de evento con más de una cohorte, y cualquier corrida dehonest_didconstruida sobre uno. - En este repositorio: los cuadernos 10 y 15 y la lección T05_C del curso.
2026-09-30 — proyecciones locales con rezagos aumentados, versiones 0.92.0 a 4.3.0
Corregido después de 4.3.0; cambia el valor por defecto. lp.la_lp (y
lp.la_lp_iv, desde 4.0.0) añadía extra_lags = max(horizons) rezagos en
todos los horizontes y daba a los controles sólo n_lags rezagos; el método se
atribuía a Plagborg-Møller y Wolf (2021), con una regla "p_aug = p + h" sin
fuente. La proyección local con rezagos aumentados de Montiel Olea y
Plagborg-Møller (2021, Econometrica 89(4)) añade un solo rezago. El antiguo
valor por defecto sigue siendo válido asintóticamente, pero su cobertura en
muestras finitas es peor y sus bandas más anchas: con T = 228 cubría entre 0.79
y 0.84 frente a 0.84-0.87 con un rezago extra (nominal 0.90). Además, la
estimación en un h dado dependía del mayor horizonte pedido, y
horizons=[0] no tenía aumento.
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
Estimaciones puntuales y bandas HC0 de la_lp, la_lp_iv |
extra_lags no se pasó, o cualquier llamada con controls= |
Un extra_lags explícito, sin controles |
Volver a correr. PL de impuestos de Romer-Romer (T = 228, H = 20): la respuesta a 2 años pasa de -3.15 a -2.86, y el pico se mueve de -3.15 en h = 8 a -2.87 en h = 10. |
¿Le afecta?
res = la_lp(df, y, x, horizons=H, n_lags=p) # su llamada en 4.3.0 o antes
res["p_aug"].iloc[0] > p + 1 # True → el aumento antiguo por defecto
Cualquier llamada con controls= también está afectada. Para reproducir
exactamente un número antiguo con la versión corregida, pase
extra_lags=max(horizons), control_lags=n_lags.
Qué hay que volver a correr
- Cualquier resultado de
la_lp/la_lp_ivobtenido con elextra_lagspor defecto o concontrols. - En este repositorio: los cuadernos 14 y 50, las lecciones T04_A y T05_B
de
curso/, la lección 06 denotebooks/course,docs/lp.mdy el ejemplola_lp_pmw_demo(la mediana de la curva de especificación del cuaderno 14 pasa de -2.30 a -2.64).
2026-09-30 — valores críticos de b fijo, versiones 0.92.0 a 4.3.0
Corregido después de 4.3.0. La tabla de b fijo con núcleo de Bartlett
escrita en el código de inference.llsw_critical_value y de la clave
llsw_cv_90 de inference.hac_fixed_b no coincidía con Kiefer y Vogelsang
(2005, cuadro I). Su comentario citaba el cuadro 2 de Lazarus, Lewis, Stock y
Watson (2018), que contiene constantes de ancho de banda, no valores críticos,
y sus valores bilaterales al 1% no venían de ninguna tabla publicada. A partir
de b = 0.1, aproximadamente, los valores eran demasiado pequeños, y el déficit
crece con b. El código antiguo interpolaba linealmente entre sus filas
erróneas de b = 0.1 y b = 0.2, así que todo b intermedio está afectado: el
valor bilateral al 5% quedaba un 1% por debajo del correcto con b = 0.10, un 3%
con b = 0.12, un 5% con b = 0.15 (2.265 en lugar de 2.386), un 9% con b = 0.2 y
entre un 14% y un 20% desde b = 0.3 (3.96 en lugar de 4.771 con b = 1). Por eso
las pruebas rechazaban de más y los intervalos eran demasiado estrechos. Los
valores bilaterales al 1% eran demasiado pequeños para todo b desde 0.05. Con
b por debajo de 0.1 al nivel del 10%, y hasta b = 0.08 al nivel del 5%, los
valores eran demasiado grandes, hasta un 8% con b = 0.02, así que esas pruebas
eran conservadoras (una prueba al 10% nominal rechazaba el 8.6% de las veces
con b = 0.05).
| b | Rechazo al 5% nominal | Rechazo al 10% nominal | Rechazo al 1% nominal |
|---|---|---|---|
| 0.05 | 4.5% | 8.6% | 1.1% |
| 0.10 | 5.4% | 9.9% | 1.5% |
| 0.12 | 5.7% | 10.3% | 1.6% |
| 0.15 | 6.2% | 11.0% | 1.8% |
| 0.2 | 7.0% | 12.1% | 2.1% |
| 0.5 | 9.3% | 15.4% | 2.9% |
| 1 | 8.8% | 16.3% | 1.8% |
(tasas de rechazo bajo la nula del estadístico t de hac_fixed_b frente al
antiguo llsw_critical_value(b, alpha), datos iid N(0,1), T = 200, promediadas
sobre 200,000 extracciones de la estimación de la varianza. Con los valores
corregidos las mismas pruebas rechazan el 4.8-5.0%, el 9.5-10.1% y el 1.0%.)
Lazarus, Lewis, Stock y Watson recomiendan el ancho de banda de Newey-West S = 1.3√T, es decir b = 1.3/√T. Ese b está entre 0.1 y 0.2 para T entre aproximadamente 42 y 169.
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
llsw_critical_value, hac_fixed_b(...)["llsw_cv_90"] |
b mayor que 0.1 a cualquier nivel (al 5%, desde b = 0.1), con un déficit que crece de aproximadamente un 1% con b = 0.1 a un 9% con b = 0.2 (bilateral al 5%) y más por encima; alpha = 0.01 desde b = 0.05; con b por debajo de 0.1 al 10% y hasta b = 0.08 al 5%, valores demasiado grandes (conservadores) | El b = 0.10 por defecto con alpha = 0.10: el antiguo 1.86 frente a 1.861. hac_fixed_b busca ahora su valor en b_eff = (floor(bT) + 1)/T, que da 1.871 con T = 200 y 1.902 con T = 50; ahí la antigua prueba al 10% rechazaba el 9.9% y el 10.4% de las veces. |
Volver a correr la prueba o el intervalo. Valores bilaterales antiguos y nuevos con b = 1: 3.05/3.96/6.29 pasan a 3.764/4.771/7.083 al 10/5/1%. |
Errores estándar, estadísticos t y vcov de hac_fixed_b |
— | Siempre, salvo una corrección de redondeo de un rezago para b·T como 0.29·100 | Nada que hacer. |
| Un alpha fuera de {0.2, 0.1, 0.05, 0.02, 0.01}, o un b fuera de (0, 1] | Se sustituía o recortaba en silencio | — | Ahora lanza ValueError. |
¿Le afecta?
from puremacro.inference import llsw_critical_value
llsw_critical_value(0.15, 0.05) # 2.265 en 4.3.0 y antes; 2.386 corregido
llsw_critical_value(1.0, 0.05) # 3.96 en 4.3.0 y antes; 4.771 corregido
Si su b era mayor que 0.1, o su nivel el 1%, vuelva a correr. Con b = 0.10 y el nivel del 5%, la prueba antigua rechazaba el 5.4% de las veces con T = 200 y el 5.8% con T = 50; decida si ese margen importa para su resultado.
Qué hay que volver a correr
- Cualquier prueba o intervalo construido con
llsw_critical_valueollsw_cv_90con b mayor que 0.1, o con alpha = 0.01. Esto incluye la regla de LLSW b = 1.3/√T para muestras de aproximadamente 42 a 169 observaciones. Ningún cuaderno ni ejemplo de este repositorio los usa.
2026-09-30 — error estándar AKM de shift-share, versiones 2.4.0 a 4.3.0
Corregido después de 4.3.0. El se_akm de bartik.shift_share_iv, y con
él el se por defecto, el estadístico t, el valor-p y el intervalo, no
implementaba Adão, Kolesár y Morales (2019) cuando la regresión tenía controles
a nivel de unidad además del intercepto, o participaciones de exposición que
no suman uno. El código residualizaba los choques sectoriales brutos sobre una
constante ponderada por las participaciones; AKM usan X̂, la regresión del
instrumento parcializado por los controles sobre las participaciones
(observación 5, ecs. 28 y 39). Tampoco había forma de agrupar sectores (ec.
40). El error va en cualquier dirección: con los datos ADH de la viñeta de
ShiftShareSE el error estándar era 0.1816 en lugar de 0.2101 (13.5% demasiado
pequeño); en un caso sintético con un control regional era 0.4117 en lugar de
0.2120.
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
Error estándar AKM e inferencia de shift_share_iv |
Controles además del intercepto, o participaciones que no suman uno | Sólo intercepto y participaciones completas (por ejemplo el ejemplo de docs/spatial.md) |
Volver a correr. Pase sector_clusters= cuando los choques puedan estar correlacionados dentro de grupos de sectores (los grupos SIC de 3 dígitos reproducen el 0.2403730 de la viñeta). akm_shocks="residualized" da el número antiguo. |
¿Le afecta?
import numpy as np
np.allclose(shares.sum(axis=1), 1.0) # False → le afecta
# también le afecta si pasó controles además del intercepto
Qué hay que volver a correr
- Cualquier error estándar, prueba o intervalo AKM de una regresión con controles o participaciones incompletas. Ningún cuaderno de este repositorio los usa.
2026-09-30 — diagnósticos MCMC: estadísticos z de Geweke y tamaño muestral efectivo, versiones 0.92.0 a 4.3.0
Corregido después de 4.3.0. mcmc.geweke_z estimaba la varianza de largo
plazo de cada segmento con una ventana de Bartlett de sólo 5-7 rezagos en los
segmentos por defecto, demasiado corta para salidas MCMC autocorrelacionadas.
Con cadenas de autocorrelación positiva (Metropolis de paseo aleatorio y Gibbs,
las únicas que le pasa estimate_dsge_bayesian) la varianza se subestimaba,
así que cadenas estacionarias se declaraban no convergidas mucho más a menudo
que el 5% nominal: con 5,000 extracciones AR(1) estacionarias, el 9% de las
veces con φ = 0.5, el 29-33% con 0.9, el 46-49% con 0.95 y el 76% con 0.99,
frente a 6%, 7%, 9% y 19% ahora (7% con 0.99 y 50,000 extracciones). Eran
falsas alarmas, no aprobados falsos. Con cadenas antitéticas el estimador
antiguo era algo conservador.
mcmc.effective_sample_size sumaba pares de autocorrelaciones desde el rezago
1 sin paso monótono. Nunca podía superar n, y devolvía exactamente n siempre
que la suma de las autocorrelaciones de orden 1 y 2 era negativa, el caso
típico de las cadenas antitéticas (ESS verdadero cercano a 3n con φ = -0.5).
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
geweke_z, geweke_z_<param> y geweke_z_max de estimate_dsge_bayesian (desde 2.1.0), trace_summary |
Cadenas persistentes: el valor absoluto de z estaba inflado | Cadenas con autocorrelación despreciable | Volver a correr los diagnósticos. geweke_z(..., spectrum="bartlett") reproduce los números antiguos. |
effective_sample_size, ESS bulk y tail de NUTS |
Cadenas antitéticas; más ruidoso con autocorrelación positiva | — | Volver a correr; el ESS de NUTS cambia unos pocos puntos porcentuales (cuaderno 43: de 87.2 a 90.6). |
gelman_rubin |
— | Siempre: es el estadístico clásico, sin cambios | Use el nuevo split=True, o trace_summary()["R_hat_split"], para detectar derivas dentro de una cadena. |
¿Le afecta?
Un |z| entre 2 y cerca de 5 en una cadena de Metropolis de paseo aleatorio
larga y bien mezclada, reportado por 4.3.0 o antes, era probablemente una
falsa alarma. En el modelo bayesiano AR(1) sintético de las pruebas,
geweke_z_max pasa de 1.19 a 0.78.
Qué hay que volver a correr
- Diagnósticos de convergencia de la estimación bayesiana de DSGE y de
cualquier cadena pasada a
geweke_zoeffective_sample_size. - En este repositorio: el ejemplo
mcmc_diagnosticsy el cuadro de ESS del cuaderno 43.
2026-09-30 — las reproducciones de nowcasts en tiempo real usaban añadas posteriores, versiones 4.1.0 a 4.3.0
Corregido después de 4.3.0. Con as_of anterior a la última añada del
panel, realtime_nowcast calculaba su descomposición de noticias
(forecast_old, revision, news_table, revision_table), vintage_history
y news_vs_noise_test frente a añadas publicadas después de as_of: la
referencia por defecto era la penúltima añada del panel. Cuando as_of era
esa añada, la descomposición era idénticamente cero, y summary() podía
imprimir "Analytical Identity Error ... (< 1e-10)" con un error cercano a
1e-2. En un ejemplo con cinco añadas mensuales y as_of en la segunda, la
descomposición pasa de forecast_old -0.0828 / revision +0.0270 (error 2.7e-2,
referencia la cuarta añada) a +0.1002 / -0.1560 (error 5.6e-17, referencia la
primera).
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
news_decomposition, vintage_history, news_vs_noise_test |
as_of anterior a la última añada del panel |
Sin as_of |
Volver a correr la reproducción. |
El nowcast puntual, forecast_sd, factores y cargas |
— | Siempre: ya eran en tiempo real | Nada que hacer. |
Código que lee vintage_history["nowcast"] |
Siempre | — | Lea vintage_history["last_observed_value"]: la columna siempre contuvo el último dato observado, nunca un nowcast del modelo. |
¿Le afecta?
Cualquier reproducción en pseudo tiempo real que pasó as_of. Las llamadas
sin as_of sólo cambian en las columnas renombradas de vintage_history.
Qué hay que volver a correr
- Cualquier descomposición de noticias o prueba de noticias frente a ruido en
pseudo tiempo real hecha con
as_of. El cuaderno 59 usa la última añada, así que sus números no cambian; sólo cambia el bloque de resumen impreso.
2026-09-30 — unidades de Gertler-Karadi (2.3.0 a 4.3.0) y signo de las sorpresas con precios de futuros (0.92.0 a 4.3.0)
Corregido después de 4.3.0. Dos convenciones que la documentación no declaraba llevaban a números erróneos.
GertlerKaradiResult.irf/to_frame()siempre ha contenido desviaciones en niveles x_t - x_ss, porque el modelo se linealiza en niveles. Multiplicarlas por 100 y llamar "%" al resultado es incorrecto para toda variable cuyo estado estacionario no sea 1. Con la solución por defecto (OccBin, choque de calidad del capital de -5%), los valores en el impacto en porcentaje son: capital -5.06 (no -28.66; mínimo -13.49, no -76.38), patrimonio neto -49.15 (no -67.88), inversión -7.10 (no -1.01), producto -1.60 (no -1.35), consumo -0.65 (no -0.35). Q no está afectado porque Q_ss = 1.hfi.gk2015_surprisedevuelvepost - pre, escalado, y su docstring aceptaba un precio de futuros o una tasa implícita. Con precios (cotizados como 100 - tasa) la sorpresa salía con el signo invertido: un endurecimiento de 25 pb daba -0.5 en lugar de +0.5. Eso invierte las respuestas de un SVAR con proxy (proxy_svarno normaliza el signo por defecto) e intercambia los choques monetarios y de información de Jarociński-Karadi.
aggregate_to_period además suma las sorpresas dentro del mes calendario,
mientras que Gertler y Karadi (2015, nota 11) usan un promedio del periodo; los
resultados que afirman replicar su instrumento mensual deben usar el nuevo
method="gk2015".
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
Resultados de solve_gertler_karadi reportados en porcentaje |
Las desviaciones en niveles se multiplicaron por 100 | Desviaciones en niveles reportadas como tales; Q | Use to_frame(units="pct"). |
gk2015_surprise y lo construido sobre ella |
Se pasaron precios de futuros | Se pasaron tasas implícitas | Volver a correr con quote="price", o pasar tasas implícitas. |
¿Le afecta?
res = solve_gertler_karadi()
res.to_frame()["K"].iloc[0] # -0.2866: desviación en niveles (K_ss = 5.66), es decir -5.06%, no -28.66%
Para la sorpresa: si sus datos de entrada eran precios cercanos a 95 y no tasas cercanas a 5, sus sorpresas tienen el signo equivocado.
Qué hay que volver a correr
- Cualquier respuesta de Gertler-Karadi reportada en porcentaje, y cualquier SVAR con proxy o descomposición de choques de información construida con sorpresas cotizadas en precios.
- En este repositorio: la lección T02_F del curso (inglés y español)
imprimía los números mal escalados, y el ejemplo
hfi_gertler_karadiusaba un instrumento de puro ruido cotizado en precios.
2026-09-30 — respuestas de Blanchard-Quah de variables en niveles, todas las versiones (comportamiento documentado, ahora seleccionable)
Cambiado después de 4.3.0; el valor por defecto no cambia.
var.identify.bq_svar acumula la respuesta de todas las variables, lo cual
sólo es correcto cuando todas las columnas de Y están diferenciadas, y el
docstring de su resultado llamaba a la salida "respuesta en niveles de cada
variable". En el sistema canónico de Blanchard-Quah (Δlog PNB, tasa de
desempleo en niveles), la respuesta del desempleo salía como una suma
acumulada que converge a una constante distinta de cero en lugar de volver a
cero, y lo mismo sus bandas; en una comprobación con proceso generador
conocido daba +0.687 en h = 40 frente a un valor verdadero de 0.000. El
comportamiento estaba documentado, así que no es un error en el sentido de las
reglas de abajo, pero confundió al material docente.
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
Respuestas y bandas de bq_svar |
Una columna de Y en niveles |
Todas las columnas diferenciadas | Pase cumulate=[índices de las columnas diferenciadas], por ejemplo cumulate=[0]; la elección se aplica a la estimación puntual y a cada extracción bootstrap. |
¿Le afecta?
Si alguna variable de su VAR de Blanchard-Quah entró en niveles y leyó su
respuesta de bq_svar como respuesta en niveles, le afecta. Diferenciar la
respuesta después (np.diff) recupera la estimación puntual pero no las
bandas.
Qué hay que volver a correr
- Respuestas de Blanchard-Quah de variables en niveles, y sus bandas.
- En este repositorio:
teaching.bq_canonical.bq_gdp_urate, la lección T02_B decurso/(que acumulaba por segunda vez), las lecciones 02 y 05 denotebooks/course, el ejemplogali_1999_hoursy el cuaderno 35 (horas en niveles).
2026-09-30 — Aiyagari continuo: política de los hogares, vaciado del mercado y converged, versiones 3.3.0 a 4.3.0
Corregido después de 4.3.0. solve_aiyagari_continuous detenía en
silencio el EGM de los hogares tras 500 iteraciones, devolvía
converged=True incondicionalmente e ignoraba solver y los argumentos
desconocidos; sus envoltorios AiyagariContinuousModel.solve y
AiyagariContinuousEquilibrium.solve usaban por defecto una tolerancia de
Brent xtol=1e-6, demasiado laxa para la tolerancia documentada de vaciado de
1e-4. Donde β(1+r*) está cerca de uno, la política devuelta no era el punto
fijo, y el error de vaciado reportado, calculado con esa política, subestimaba
el exceso de demanda verdadero: 1.6e-2 verdadero frente a -2.5e-6 reportado en
el ejemplo documentado, 1.67e-2 frente a 5.95e-4 para
AiyagariContinuousModel(n_z=3).solve(N_k=150), -2.9e-3 frente a 1.4e-9 con
β = 0.995. El error en r* es pequeño en todos los casos comprobados, como mucho
0.0006 puntos porcentuales (ejemplo documentado: de 0.039421 a 0.039416), con
K* moviéndose cerca de 4.5e-4 y el Gini cerca de 5e-4.
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
solve_aiyagari_continuous y los envoltorios |
Calibraciones con n_z = 3 y ρ_z = 0.9 (el ejemplo documentado y el estado estacionario del documento de transiciones), β trimestral ≥ 0.99, a_max grande, o el antiguo xtol de los envoltorios |
La calibración por defecto (n_z = 5): r dentro de 1e-9; cuaderno 52 (r a 1e-9, K a 1e-7); cuaderno 67 (r a 1e-10) | Volver a correr; revise eq.converged, eq.metadata["egm_iterations"] y eq.metadata["clearing_ok"]. |
solve_aiyagari_continuous con solver="collocation" o "fem" |
Siempre: el resultado era el de EGM | — | Ahora lanza ValueError. |
solve_continuous_transition con un choque permanente |
Su estado estacionario terminal tenía el mismo tope y la misma tolerancia | Choques transitorios | Volver a correr las transiciones con choques permanentes; el estado estacionario terminal usa ahora el mismo bucle y las mismas tolerancias. |
¿Le afecta?
Vuelva a resolver con la versión corregida: si eq.metadata["egm_iterations"]
supera 500, el resultado antiguo se calculó con una política de los hogares
sin converger.
Qué hay que volver a correr
- Estados estacionarios calculados con n_z = 3, con β ≥ 0.99, o con los envoltorios y su antiguo valor por defecto, y las transiciones construidas sobre ellos.
2026-09-30 — steady() devolvía en silencio estados estacionarios estructuralmente singulares, versiones 2.6.0 a 4.3.0
Corregido después de 4.3.0. dsge.steady(solve_algo="block") es la ruta
por defecto de build(), build_dynare() y load_mod(). Cuando el sistema
estático no tenía un emparejamiento completo entre ecuaciones y variables pero
una resolución hybr del sistema completo convergía, devolvía ese punto sin
advertencia. Ese punto es un miembro arbitrario de un continuo de estados
estacionarios y depende del valor inicial: en {x-1, 2x-2, x+y} con z en
ninguna ecuación, z volvía como el valor inicial más 0.769133 (1.0 daba
1.769133, 7.5 daba 8.269133); un paseo aleatorio y' = y + eps con c = 2y
devolvía (1.5, 3.0) desde (4, 3) y (0, 0) desde (1, 0).
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
steady(), build(), build_dynare(), load_mod() |
Ecuaciones estructuralmente duplicadas (un subconjunto de ecuaciones con menos variables que ecuaciones), o una variable ausente del sistema de estado estacionario | Todo modelo con emparejamiento completo: sus resultados no cambian | Ahora lanzan StructuralSingularityError; los niveles reportados los fijaba el valor inicial. |
| Lo mismo, estructura de raíz unitaria (toda ecuación sobredeterminada se reduce a 0 = 0) | Siempre | — | La misma respuesta, ahora con una StructuralSingularityWarning que avisa de que el nivel está libre. |
Las ecuaciones numéricamente colineales con incidencia completa (x + y = 2 y
2x + 2y = 4) siguen sin detectarse: la comprobación es estructural.
¿Le afecta?
Vuelva a calcular el estado estacionario con la versión corregida. Una
StructuralSingularityError o StructuralSingularityWarning significa que el
estado estacionario antiguo era un punto arbitrario de un continuo. Para
recuperar el punto antiguo, con el aviso, pase allow_singular=True a
steady(), build(), build_dynare() o load_mod(), o envuelva la llamada en
with allow_structural_singularity():
(from puremacro.dsge.steady import allow_structural_singularity). Un modelo
construido guarda el informe del solver en model.steady_state_info.
Qué hay que volver a correr
- Cualquier modelo que produjo un estado estacionario y tiene alguna de las estructuras anteriores, y todo lo calculado a partir de él.
2026-09-30 — solvers de política óptima: sesgo cero silencioso, pérdidas de relleno y un parámetro inerte, versiones 2.6.0 a 4.3.0
Corregido después de 4.3.0.
- Sesgo cero silencioso (3.1.0 a 4.3.0).
DiscretionaryPolicyResult.stabilization_biasvalía exactamente 0.0, sin advertencia, siempre que la resolución interna delq_commitmentfallaba o la pérdida de compromiso elegida era NaN, ysummary()omitía la línea. Un sesgo reportado de exactamente 0.0 puede ser por tanto una comparación fallida. Los valores en calibraciones bien planteadas no cambian (1.513166984879534 en la base del cuaderno 66). - Pérdida incondicional sin sentido. En un modelo cuya transición en lazo
cerrado tiene una raíz unitaria, la
lossde compromiso podía ser un número finito sin significado (4.9e15 con un choque de costos con raíz unitaria). Ahora es NaN. - Valores de relleno en
osr.loss_initialtomaba el valor del argumentopenalty(1e6) cuando fallaban los momentos de referencia, con sólo una UserWarning;loss_optera en silencio el último objetivo del optimizador (quizá una penalización de 1e8) cuando el modelo no podía volver a resolverse con los coeficientes devueltos; yvariance_reduction_pctvalía 0.0 donde faltaba una varianza, de modo quesummary()imprimía "Loss reduction: 0.00%". Los tres son ahora NaN con unaRuntimeWarning. - El parámetro
timelessno hacía nada.lq_commitmentyramsey_modeldevolvían siempre la ley de movimiento común al plan de Ramsey y a la regla intemporal, respuestas yconditional_lossdesde el estado estacionario, donde ambos coinciden, ylosspromediada sobre la distribución estacionaria. El código que pasabatimeless=Falseesperando otra condición inicial obtenía el mismo resultado. - Precisión de
osr. Con las tolerancias de Nelder-Mead por defecto de SciPy,osrencontraba la asignación de la regla óptima sólo hasta cerca de 1e-5 cuando el óptimo estaba en una cota (hasta 2.7e-5 en calibraciones aleatorias de Clarida-Galí-Gertler). Las pérdidas eran exactas a 2.5e-10, y los coeficientes reportados con cuatro decimales no están afectados. - Cita. La documentación y los docstrings atribuían a Jensen y McCallum (2002) la inversión con β bajo de la ordenación incondicional; es de Sauer (2010, prop. 2).
¿Le afecta?
res.stabilization_bias == 0.0 # en 4.3.0: quizá una comparación fallida; vuelva a correr
osr_res.loss_initial == 1e6 # el valor de relleno de penalty, no una pérdida
Cualquier variance_reduction_pct de exactamente 0.0, y cualquier código que
dependiera de timeless=False, están afectados como se describe.
Qué hay que volver a correr
- Sesgos de estabilización de exactamente 0.0, resultados de
osrcon pérdidas de relleno, y asignaciones deosrcitadas con más de cinco cifras significativas. - En este repositorio: los números del cuaderno 66 no cambian; sólo cambia su cita de la inversión con β bajo.
2026-09-30 — el "estado estacionario estocástico" de una solución podada es la media ergódica, versiones 2.0.0 a 4.3.0
Aclarado después de 4.3.0; no cambia ningún número.
stochastic_steady_state() de PrunedDSGESolution (desde 2.0.0) y
Order3PrunedSolution (desde 2.8.0) devuelve E[x] y E[y] de la solución
podada. Su nombre y su docstring ("estado estacionario ajustado por riesgo")
sugerían el estado estacionario con riesgo sin choques. La media ergódica es
el término de riesgo precautorio ½ g_σσ σ² más curvatura por dispersión
(½ g_xx vec Ω + ½ g_uu vec σ²Σ_u), un efecto de Jensen presente incluso cuando
g_σσ = 0. Los números siempre fueron correctos como medias ergódicas.
Leerlos como el estado estacionario con riesgo, o como desplazamientos
precautorios, es incorrecto. En el modelo RBC de
tests/fixtures/dynare_live/rbc.mod, la media ergódica del capital es +0.0785%
de su estado estacionario, mientras que el estado estacionario con riesgo y el
término de riesgo son -0.0045% (el propio ghs2 de Dynare para el capital es
-9.76e-5). En el recorrido de la 2.0 sólo 1.79e-5 del desplazamiento de
6.77e-4 del log del capital es el término de riesgo.
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
stochastic_steady_state() |
Su salida descrita como estado estacionario con riesgo o como efecto precautorio | Descrita como la media ergódica (incondicional) | Use ergodic_mean() para la media, risky_steady_state() para el punto fijo sin choques y risk_decomposition() para ver qué término mueve el desplazamiento. |
¿Le afecta?
Sólo si interpretó la salida como el estado estacionario con riesgo o como un
efecto precautorio; risk_decomposition() en la versión corregida muestra qué
parte del desplazamiento es riesgo y qué parte curvatura.
Qué hay que volver a correr
- Nada numérico. Reformule cualquier afirmación "precautoria" basada en él.
- En este repositorio: el cuaderno 68 §4, la lección T02_B del curso
("Precautionary Premium" del capital +0.07711%, cuyo estado estacionario con
riesgo es -0.02807%), el recorrido de la 2.0 §7 y
docs/dsge_build.mdusan esa etiqueta.
2026-09-23 — momentos teóricos de tercer orden, versiones 2.8.0 a 4.3.0
Corregido después de 4.3.0 (véase la sección Unreleased de CHANGELOG.md).
Order3PrunedSolution.theoretical_moments(), y el theoretical_moments que
devuelve stoch_simul(order=3), reportaban la covarianza, las correlaciones y
las autocorrelaciones de primer orden de una solución de tercer orden. Las
columnas Skewness y Kurtosis valían 0 y 3 para todas las variables. El docstring
decía que los momentos coincidían con el stoch_simul de Dynare en orden 3, y
docs/es/dsge_higher_order.md describía una asimetría y una curtosis exactas en
forma cerrada. La columna Mean era correcta: incluye la corrección por riesgo de
segundo orden, que es la media exacta de la solución podada de tercer orden con
choques gaussianos.
El error es de orden sigma^4 frente a una varianza de orden sigma^2, así que es
pequeño cuando los choques son pequeños y dominan los términos de primer orden.
En el modelo RBC de tests/fixtures/dynare_live, las varianzas del producto, el
consumo y el capital son 0.15%, 0.10% y 0.17% mayores que las de primer orden.
Una variable sin respuesta de primer orden se reportaba con varianza cero y
autocorrelaciones indefinidas. En correlated_cubic.mod, y tiene varianza
0.788 y autocorrelación de orden 1 de 0.475; en quadratic_feedback.mod, 0.0283
y 0.742.
| Superficie | Condición afectada | No afectada cuando | Qué hacer |
|---|---|---|---|
theoretical_moments() de una solución de orden 3: covarianza, correlación, autocorrelaciones (2.8.0 a 4.3.0) |
Cualquier coeficiente de segundo o tercer orden distinto de cero | La columna Mean; una solución con todos los coeficientes de orden superior nulos | Volver a correr con la versión corregida, que devuelve los momentos exactos del espacio de estados podado. |
| Sus columnas Skewness y Kurtosis | Siempre: eran valores de relleno | Nunca | La versión corregida reporta NaN. Use ergodic_moments(), que estima ambas con una simulación podada. |
stoch_simul(order=3) |
Su bloque theoretical_moments, como arriba |
Momentos simulados (periods > 0), respuestas al impulso y reglas de decisión |
Como arriba. |
ergodic_moments() lanzaba KeyError: 'Std.Dev' en las mismas versiones, así
que no devolvía números. Los momentos calculados con simulate() no se ven
afectados.
Qué volver a correr
- Cualquier varianza, desviación típica, correlación o autocorrelación
reportada con
theoretical_moments()de una solución de tercer orden, incluidas las tablas destoch_simul(order=3). - Cualquier asimetría o curtosis tomada de esas tablas: eran valores de relleno, no estimaciones.
La versión corregida coincide con precisión de máquina con las medias y
varianzas podadas de Dynare 8 en seis modelos. No coincide con las
autocorrelaciones de orden 3 de Dynare, que omiten un término de correlación;
una forma cerrada y las propias simulaciones largas de Dynare coinciden con
puremacro (véase docs/es/dsge_higher_order.md §2.3).
2026-09-23 — curvatura de la colocación ignorada o mezclada, versiones 3.3.0 a 4.3.0
Corregido después de 4.3.0 (véase la sección Unreleased de CHANGELOG.md).
CollocationProblem(method="bellman") resolvía el modelo de crecimiento con
utilidad logarítmica fuera cual fuera params["sigma"] o params["gamma"].
CollocationProblem con params={"gamma": g} (sin la clave "sigma")
resolvía la política de utilidad logarítmica, y 4.3.0 además valoraba esa
política logarítmica con CRRA(g) en value_coefficients/value(). Las
sensibilidades TFI calculadas sobre ese problema (compute_ift_gradients,
equilibrium_parameter_jacobian, gmm_objective_and_gradient) eran las del
problema logarítmico, con una columna de gamma nula.
| Superficie | Condición afectada | No afectado cuando | Qué hacer |
|---|---|---|---|
CollocationProblem(method="bellman") |
sigma o gamma distinto de 1 |
Utilidad logarítmica (sigma o gamma igual a 1 o ausente) |
Vuelva a resolver con la versión corregida. |
Políticas y valores auxiliares de CollocationProblem |
Curvatura escrita como params={"gamma": g} sin la clave "sigma", g != 1 |
method="euler" con la curvatura escrita como "sigma" |
Vuelva a resolver y a calcular los valores derivados. |
| Gradientes TFI sobre esos problemas | Cualquier resolución afectada, y la columna de gamma en todos los casos |
Utilidad logarítmica respecto de parámetros distintos de gamma |
Vuelva a calcular los gradientes; la columna de gamma era idénticamente nula. |
En la versión corregida una sola curvatura CRRA (sigma, si no el alias
gamma, si no 1) entra en el residuo de Euler, el arranque de Coleman, el
objetivo de Bellman y los coeficientes de valor auxiliares; la utilidad
logarítmica es idéntica bit a bit a 4.3.0.
2026-09-20 — modelos estructurales, APIs afectadas en 4.2.0 y anteriores
Corregidas o restringidas explícitamente en 4.3.0. La revisión reprodujo resultados numéricos y señales de éxito incorrectos en VFI, DSGE/Dynare y comercio sobre el código de 4.2.0 (los hallazgos de comercio salieron de puremacro con el motor de comercio); la primera versión afectada depende de cada API.
- DSGE de tercer orden: recalcular reglas y simulaciones, momentos o verosimilitudes que dependen de pendientes de riesgo en modelos estocásticos no lineales. Las reglas de primero y segundo orden no contienen esas pendientes.
- Paridad con Dynare: repetir comparaciones de segundo orden con todos los tensores y etiquetas. La puntuación anterior podía omitir términos o aceptar referencias incompletas; no acreditaba paridad completa.
- Proyecciones VFI: exigir el residuo final solicitado, no solo la terminación del optimizador. Regenerar valores auxiliares con productividad distinta de uno o utilidad distinta de logaritmo. La exactitud fuera de la malla sigue pendiente.
- Deep Macro: repetir el entrenamiento y comprobar residuos fuera de la muestra; se corrigió la caché de activaciones usada en el gradiente.
- DSGE con cambios de régimen: no interpretar impactos, estabilidad o momentos de soluciones fallidas; ahora se reportan como no disponibles.
Véase el alcance y las referencias. Estas referencias delimitan qué resultados se han validado y qué extensiones siguen pendientes.
2026-09-16 — tres estimadores, versiones hasta 4.0.1 inclusive
Corregido en 4.0.2. Se encontraron cuando un sitio de curso volvió a derivar los números de puremacro por su cuenta: un filtro HP aplicado en el dominio del tiempo, un MC2E en forma matricial y una cadena de Markov resuelta con 80 dígitos.
| Estimador | Qué estaba mal | No afectado cuando | Dirección del error |
|---|---|---|---|
theoretical_moments(hp_filter=...) vía dsge._moments.spectral_moments (2.9.0–4.0.1) |
Ponderaba la densidad espectral con la función de transferencia H(w) del filtro HP en lugar de su cuadrado |
Momentos teóricos sin filtrar o con filtro pasa-banda, y momentos simulados de stoch_simul(hp_filter=...), que filtran en el dominio del tiempo |
Varianzas y autocovarianzas filtradas sobreestimadas: +22% de varianza (+10.5% de desviación estándar) para un AR(1) con rho = 0.9 y lambda = 1600; las volatilidades relativas y las correlaciones se movieron con ellas |
lp.lp_iv (0.92.0–4.0.1), lp.lp_state_dep_iv (2.0.0–4.0.1), lp.la_lp_iv (4.0.0–4.0.1) |
La varianza de la segunda etapa usaba el residuo y - X_hat beta (regresor ajustado) en lugar de y - X beta |
Nunca para se, lo, hi; las estimaciones puntuales, la F de primera etapa, la F de Montiel Olea–Pflueger y los conjuntos de Anderson–Rubin eran correctos |
En cualquier sentido, en 2 beta cov(u, v) + beta^2 var(v): las bandas nominales de 90% cubrieron el valor verdadero 100% de las veces con beta = 1, cov(u, v) = 0.8, y 69% con beta = -1 |
vfi.markov_stationary (0.92.0–4.0.1), dsge.markov_switching.markov_stationary (3.1.0–4.0.1) |
Tomaba el eigenvector de P' del eigenvalor más cercano a 1 |
Los estados se comunican con probabilidades muy por encima de ~1e-12, como en las mallas usuales de Tauchen y Rouwenhorst | Una mezcla arbitraria cuando varios eigenvalores redondean a 1: error de 6e-5 en una cadena de dos estados con probabilidad de cambio de 1e-13, una probabilidad de -0.23 en tauchen(7, 0.995, 0.1, m=5); la copia de dsge regresaba una distribución uniforme sin avisar |
Qué hay que volver a correr
- Cualquier cuadro de momentos teóricos con filtro HP, por ejemplo una comparación à la Kydland–Prescott de un modelo DSGE con los datos. Los momentos simulados eran correctos, así que un cuadro que mezclaba ambos comparaba cosas distintas.
- Cualquier banda o estadístico t de
lp_iv,la_lp_ivolp_state_dep_iv. Que fuera demasiado ancha o demasiado angosta depende del signo debeta cov(u, v), así que no se corrige reescalando: hay que volver a estimar. - Distribuciones estacionarias de discretizaciones muy persistentes (Tauchen con rho de alrededor de 0.95 o más y malla amplia) o de modelos con cambio de régimen markoviano con regímenes casi absorbentes.
2026-09-03 — doce más, versiones hasta 1.9.0 inclusive
Corregido en 1.10.0. Una auditoría posterior preguntó, de cada fixture de estimador del paquete, ¿qué condición elimina este fixture? — la pregunta sobre la que giraban los siete defectos de arriba. Encontró doce más, cada uno reproducido contra una verdad conocida antes de tocar nada.
| Estimador | Qué estaba mal | No afectado cuando | Dirección del error |
|---|---|---|---|
cointegration_modern.dols |
Omitía el término contemporáneo dX_t, que es el que elimina el sesgo. El estimador era MCO con regresores extra. |
dX_t no está correlacionado con u_t |
El sesgo seguía al de MCO en todos los tamaños: +0.036 frente a +0.030 en T=100, donde el DOLS correcto da −0.0005 |
cointegration_modern.dols |
Conservaba una fila cuyo rezago de dX faltante se rellenaba con ceros, fabricando un valor de regresor |
lags = 0 |
Una observación de más, construida con un valor nunca medido |
cointegration_modern.fm_ols |
Construía la corrección de Phillips–Hansen sólo con Lambda, omitiendo el bloque Sigma de rezago 0 |
Omega es proporcional a Sigma |
Sobre-corregía. ECM peor que MCO en T=200, 800 y 3200 |
var.irf.gfevd → connectedness.spillover_index |
Dividía por un piso absoluto de 1e-12, rompiendo una invarianza de escala que el estimando tiene por construcción |
Ninguna varianza residual cae cerca del piso | La conectividad total pasó de 13.43 a 39.48 en un mismo VAR al reescalar una variable |
dsge.gensys |
Impact omitía el término Pi N: resolvía como si los errores de expectativas no respondieran a los choques |
Pi N = 0 |
En y_t = a E_t y_{t+1} + eps_t (verdad y_t = eps_t) devolvía [0, -2]: la variable no respondía a su propio choque |
dsge.gensys |
Lanzaba excepción con cualquier modelo sin raíces inestables; la prueba de unicidad era vacua | El modelo tiene al menos una raíz inestable | x_t = rho x_{t-1} + eps no podía resolverse |
did.sun_abraham |
lo/hi promediaban los extremos por cohorte en vez de usar el se agregado |
Una sola cohorte por tiempo de evento | Bandas sqrt(K) veces más anchas — 1.73 con K=3, 1.37 con K=2 — e inconsistentes con el se de su propia fila |
inference.weak_iv.kleibergen_paap_f |
El sándwich HC0 dividía entre n dos veces mientras el pan invertía el producto cruzado crudo Z'Z, que ya lleva ambos factores |
Nunca — toda llamada estaba afectada | Devolvía exactamente n^2 veces el estadístico correcto: 235,470 frente a una verdad de 5.89 con n=200. Los umbrales de Stock-Yogo rondan 10, así que reportaba "instrumentos fortísimos" para todo conjunto de datos y jamás podía diagnosticar un instrumento débil |
inference.weak_iv.kleibergen_paap_f |
La función de influencia usaba kron(Z_t, V_t) donde el vec por columnas y el pan exigen kron(V_t, Z_t) |
k = 1 (un regresor endógeno) — ahí coinciden |
Varianza robusta incorrecta con dos o más regresores endógenos |
inference.weak_iv.anderson_rubin_band |
Comparaba un estadístico F contra chi2.ppf(ci, df), pero es df*F lo que es chi2(df) |
df = 1 — el valor por defecto y el único ejercitado |
Corte df veces mayor. La banda nominal del 90% tenía 100.0% de cobertura con df=2 y df=4 |
lp.panel_lp_dk (vía _focal_dk_se) |
El ancho de banda de Bartlett salía del número de filas N*T, pero el núcleo corre sobre la suma transversal de longitud T |
N = 1 |
Ancho inflado por N^(2/9): 7 -> 10 -> 13 con T=100 fijo al pasar N de 10 a 50 a 200. Agregar países cambiaba la autocorrelación supuesta |
lp.mean_group_panel_lp |
No ordenaba su entrada, mientras lp_hac construye rezagos con .shift() posicional |
Quien llama ya pasaba un marco ordenado | En un panel cuya respuesta verdadera en h=1 es 0.8: 0.765 ordenado, 0.055 con las mismas filas barajadas. Silencioso, y atenuado hacia cero |
| 25 sitios de valor-p en 16 módulos | 1 - cdf en vez de la función de supervivencia |
El valor-p supera ~1e-16 | Devolvían exactamente 0.0 en la cola. Normal bilateral en |z| = 9 es 2.3e-19; chi-cuadrada 200 con 5 gl es 2.8e-41 |
Un hallazgo más, en un modelo que ya no forma parte de puremacro, ya no figura aquí.
Qué hay que volver a correr
- Cualquier estimación de
dolsofm_ols. Ambas estaban sesgadas sistemáticamente sobre los datos para los que existen.fm_olsquedaba más lejos de la verdad que MCO. - Cualquier índice de conectividad de Diebold–Yilmaz calculado con el
identification="gfevd"por defecto sobre datos cuyas varianzas residuales sean pequeñas en las unidades empleadas. - Cualquier IRF de
gensys. La matriz de impacto era incorrecta para todo modelo con comportamiento prospectivo, que son todos los que gensys atiende. - Cualquier banda de estudio de eventos de Sun–Abraham en un tiempo de
evento con más de una cohorte. Las estimaciones puntuales y el
sese sostienen; los intervalos eran demasiado anchos. Corrección (2026-09-30): elseno se sostenía; trataba como independientes cohortes que comparten unidades de control (véase la entrada del 2026-09-30 sobre los errores estándar de Sun-Abraham). Las estimaciones puntuales sí. - Cualquier valor-p reportado como exactamente 0.0. Nunca fue cero.
Una nota sobre las pruebas
Cuatro artefactos distintos afirmaban el defecto de gensys en vez de
detectarlo: tres pruebas en tests/test_dsge_gensys_coverage.py y el caso de
validación dsge.gensys_shock_impact_identity, cuya propia cita enunciaba el
modelo sin su término Pi eta_t — álgebra correcta a partir de una premisa
truncada. La banda de sun_abraham contradecía el error estándar impreso a su
lado en la misma fila, así que ésa no requería referencia externa alguna.
2026-09-02 — siete estimadores, versiones 0.92.0 a 1.8.0
Corregido en 1.9.0. Siete estimadores públicos devolvieron números equivocados en todas las versiones desde 0.92.0 hasta 1.8.0 inclusive. Los siete fallos comparten una forma: la respuesta equivocada era internamente consistente, de modo que ninguna invariante que el paquete verificaba podía detectarla, y en todos los casos el fixture de prueba cumplía exactamente la condición bajo la cual el error desaparece.
¿Le afecta?
Si publicó un número de alguno de los siete estimadores de abajo con una versión anterior a 1.9.0, vuelva a correrlo. Si sólo lo corrió sobre datos que cumplen la columna "no afectado cuando", no hay nada que hacer.
| Estimador | Qué estaba mal | No afectado cuando | Dirección del error |
|---|---|---|---|
var.identify.proxy_svar |
El vector de impacto se devolvía en la métrica de Sigma y no en la de Sigma^-1 — proporcional a Sigma b_1, no a b_1. El choque identificado era una mezcla de todos los choques estructurales. |
Sigma es proporcional a la identidad (residuos i.i.d.) — ahí el error es exactamente cero |
Crece con la estructura fuera de la diagonal de Sigma. 31% en un elemento de un DGP de 3 variables, con el patrón de signos relativos equivocado |
var.panel |
Importa el mismo _proxy_impact_factory |
ídem | ídem |
inference.swamy_test |
La forma cuadrática se centraba en la media aritmética y no en beta_bar_W, la ponderada por precisión |
Todas las unidades se estiman con la misma precisión | Sobre-rechaza la homogeneidad de pendientes, nunca sub-rechaza. Tamaño al 5% nominal: 0.050 con precisión igual, 0.078 con dispersión 2×, 0.975 con 0.1 frente a 3.0 |
garch.dcc_fit |
Los rendimientos crudos se estandarizaban con una volatilidad ajustada sobre los centrados, de modo que Qbar estimaba mu_i · mu_j |
mean="zero" — el valor por defecto, e idéntico bit a bit al anterior sobre datos ya centrados. Sólo mean="constant" está afectado |
Correlaciones atraídas hacia m²/(m²+1), con m = mu/sd. Un valor verdadero de 0 se reportaba como +0.94 con media 5 y desviación 1 |
state_space.simulation_smoother |
Los interceptos del modelo quedaban en el segundo paso de Durbin–Koopman, sumando b una segunda vez |
c y d son ambos cero — todos los fixtures de la suite, e idéntico bit a bit ahí |
Cada draw desplazado por el intercepto completo. Con d = 5 los draws quedaban exactamente −5.0 de la media posterior, contra un error Monte Carlo de 0.012 |
var.wild_bootstrap_var |
Los draws fallidos se escribían en la pila de percentiles como la estimación puntual, sin contador ni advertencia | Ningún draw falló | Bandas demasiado estrechas, monótonamente en la fracción de fallos f; ancho cero una vez que f ≥ 1−2a. Peor precisamente cuando el impact_fn de proxy_svar falla por instrumento débil — la banda se estrechaba cuando debía ensancharse |
var.identify.rigobon_svar |
El bootstrap emparejaba bloques de residuos remuestreados con las etiquetas de régimen en orden de calendario, destruyendo la identificación en cada draw | Sólo la estimación puntual; lo que estaba mal es la banda | Bandas unas 8 veces más anchas en un DGP con razón de varianzas verdadera 3.0 (los draws promediaban 1.14 y nunca superaron 1.50 en 500) |
var.estimate_var |
Aceptaba datos no finitos y devolvía coeficientes todo-NaN sin lanzar excepción | La entrada es finita | No es un número equivocado sino uno silencioso: Sigma, los residuos y toda IRF, FEVD, descomposición histórica y banda construidas sobre el ajuste salían todo-NaN y perfectamente bien formadas. Ahora es un LinAlgError con nombre |
Las derivaciones completas, las magnitudes medidas y por qué cada fixture
no podía alcanzar su propio error están en
CHANGELOG.md,
bajo 1.9.0, "Fixed — affects results published in every release from
0.92.0 to 1.8.0".
Qué hay que volver a correr
- Cualquier respuesta a impulso proxy-SVAR publicada de
proxy_svarovar.panel. Cambian la estimación puntual y la banda. - Cualquier banda de Rigobon. La estimación puntual se sostiene; la banda no.
- Cualquier rechazo de
swamy_testen un panel con precisión desigual entre unidades — muestras cortas mezcladas con largas, países pequeños con grandes. Ése es el caso normal, no el exótico. - Cualquier correlación de
dcc_fit(mean="constant"). La ruta por defectomean="zero"no requiere nada. - Cualquier draw de
simulation_smootherde un modelo con deriva de estado o intercepto de medición distintos de cero. - Cualquier banda de
wild_bootstrap_varcuya corrida haya reportado fallos de bootstrap — cosa que, antes de 1.9.0, no reportaba. Si el estimador eraproxy_svarcon instrumento débil, suponga que la banda quedó demasiado estrecha.
Hasta dónde llegó la corrección en 1.9.0
Se dice aquí en vez de dejar que un usuario lo descubra:
matlab/— eliminada en 4.0.0. La caja de herramientas de MATLAB era una implementación separada, así que ninguna corrección de Python llegaba a ella. Antes de eliminarla se portaron dos estimadores a mano:+puremacro/+var/proxy.marrastraba el mismo error de métrica en el SVAR con proxy y quedó corregido, y+puremacro/+var/estimate.mahora falla ante entradas no finitas. Los otros cinco estimadores del cuadro anterior nunca se auditaron allí. Como una implementación paralela sin auditar de un estimador ya corregido es un riesgo permanente, y como esa caja de herramientas exigía software propietario que puremacro no requiere, se eliminó en 4.0.0 en lugar de mantenerla. Si alguna vez ejecutó esa caja de herramientas, considere sus resultados no verificados y vuelva a calcularlos con el paquete de Python. Toda función de impulso-respuesta de SVAR con proxy que haya producido antes del 2026-09-02 es incorrecta. El código permanece en el historial de git en la etiquetav3.4.0.- Los cuadernos de este repositorio ya se volvieron a ejecutar.
notebooks/14_tax_multiplier_three_ways, su gemelo_es,notebooks/course/06_lp_narrativa_esy la compilación deplayground/muestran números posteriores a la corrección desde 1.9.0.notebooks/08_garch_volatilityno requirió cambio: llama adcc_fit(panel), y la ruta por defectomean="zero"es idéntica bit a bit. - Los suyos no. Un
.ipynbversionado guarda las salidas de la corrida que lo produjo. Toda celda suya que muestre un resultado de un estimador de arriba, ejecutada antes de 1.9.0, sigue mostrando el número previo a la corrección hasta que la vuelva a ejecutar.
Cómo se decide un aviso
Se emite un aviso cuando se cumplen todas estas condiciones:
- Una versión publicada devolvió un resultado numéricamente equivocado de un estimador público, o un resultado sin la cobertura que declaraba.
- El fallo fue silencioso — sin excepción, sin advertencia, sin una salida visiblemente mal formada.
- Un usuario pudo plausiblemente haber publicado ese número.
Un error que lanza excepción, uno en una ruta no publicada y uno en un auxiliar privado sin consecuencia pública son entradas del CHANGELOG, no avisos.
La regla que se sigue es la de
CONTRIBUTING.md:
el paquete no sustituye un valor faltante por uno plausible, y no se
queda callado sobre un número que calculó mal.