| """ |
| Example 5: Complete GeoBotv1 Framework - Final Features |
| |
| This example demonstrates the final critical components that complete GeoBotv1 |
| to 100% research-grade capability: |
| |
| 1. Vector Autoregression (VAR/SVAR/DFM) - Econometric time-series analysis |
| 2. Hawkes Processes - Conflict contagion and self-exciting dynamics |
| 3. Quasi-Experimental Methods - Causal inference without randomization |
| - Synthetic Control Method (SCM) |
| - Difference-in-Differences (DiD) |
| - Regression Discontinuity Design (RDD) |
| - Instrumental Variables (IV) |
| |
| These methods are essential for: |
| - Multi-country forecasting with spillovers (VAR) |
| - Modeling conflict escalation and contagion (Hawkes) |
| - Estimating policy effects and counterfactuals (quasi-experimental) |
| |
| GeoBotv1 is now COMPLETE with all research-grade mathematical components! |
| """ |
|
|
| import numpy as np |
| import sys |
| sys.path.append('..') |
|
|
| from datetime import datetime, timedelta |
|
|
| |
| from geobot.timeseries import ( |
| VARModel, |
| SVARModel, |
| DynamicFactorModel, |
| GrangerCausality, |
| UnivariateHawkesProcess, |
| MultivariateHawkesProcess, |
| ConflictContagionModel |
| ) |
|
|
| |
| from geobot.models import ( |
| SyntheticControlMethod, |
| DifferenceinDifferences, |
| RegressionDiscontinuity, |
| InstrumentalVariables |
| ) |
|
|
|
|
| def demo_var_model(): |
| """Demonstrate Vector Autoregression for multi-country forecasting.""" |
| print("\n" + "="*80) |
| print("1. Vector Autoregression (VAR) - Multi-Country Spillovers") |
| print("="*80) |
|
|
| |
| |
| np.random.seed(42) |
| T = 100 |
| n_vars = 3 |
|
|
| |
| |
| A1 = np.array([ |
| [0.5, 0.2, 0.1], |
| [0.1, 0.6, 0.15], |
| [0.05, 0.1, 0.55] |
| ]) |
| A2 = np.array([ |
| [0.2, 0.05, 0.0], |
| [0.1, 0.1, 0.05], |
| [0.0, 0.05, 0.2] |
| ]) |
|
|
| |
| data = np.zeros((T, n_vars)) |
| data[0] = np.random.randn(n_vars) * 0.1 |
| data[1] = np.random.randn(n_vars) * 0.1 |
|
|
| for t in range(2, T): |
| data[t] = (A1 @ data[t-1] + A2 @ data[t-2] + |
| np.random.randn(n_vars) * 0.1) |
|
|
| print(f"\nSimulated {T} time periods for {n_vars} countries") |
| print(f"Variables: GDP growth, Military spending, Stability index\n") |
|
|
| |
| var = VARModel(n_lags=2) |
| variable_names = ['GDP_growth', 'Military_spend', 'Stability'] |
| results = var.fit(data, variable_names) |
|
|
| print(f"VAR({results.n_lags}) Estimation Results:") |
| print(f" Log-likelihood: {results.log_likelihood:.2f}") |
| print(f" AIC: {results.aic:.2f}") |
| print(f" BIC: {results.bic:.2f}") |
|
|
| |
| forecast = var.forecast(results, steps=10) |
| print(f"\n10-step ahead forecast:") |
| print(f" GDP growth: {forecast[-1, 0]:.3f}") |
| print(f" Military spending: {forecast[-1, 1]:.3f}") |
| print(f" Stability: {forecast[-1, 2]:.3f}") |
|
|
| |
| print("\nGranger Causality Tests:") |
| for i in range(n_vars): |
| for j in range(n_vars): |
| if i != j: |
| gc_result = var.granger_causality(results, i, j) |
| if gc_result['p_value'] < 0.05: |
| print(f" {variable_names[j]} β {variable_names[i]}: " |
| f"F={gc_result['f_statistic']:.2f}, p={gc_result['p_value']:.3f} β") |
|
|
| |
| irf_result = var.impulse_response(results, steps=10) |
| print("\nImpulse Response Functions computed (10 steps)") |
| print(f" Shock to Military spending β GDP growth at t=5: {irf_result.irf[0, 1, 5]:.4f}") |
|
|
| |
| fevd = var.forecast_error_variance_decomposition(results, steps=10) |
| print("\nForecast Error Variance Decomposition (horizon=10):") |
| for i, var_name in enumerate(variable_names): |
| contributions = fevd[i, :, -1] |
| print(f" {var_name} variance explained by:") |
| for j, source_name in enumerate(variable_names): |
| print(f" {source_name}: {contributions[j]:.1%}") |
|
|
| print("\nβ VAR model demonstrates multi-country interdependencies!") |
|
|
|
|
| def demo_hawkes_process(): |
| """Demonstrate Hawkes processes for conflict contagion.""" |
| print("\n" + "="*80) |
| print("2. Hawkes Processes - Conflict Escalation and Contagion") |
| print("="*80) |
|
|
| |
| print("\nSimulating conflict events with self-excitation...") |
| hawkes = UnivariateHawkesProcess() |
|
|
| |
| |
| events = hawkes.simulate(mu=0.3, alpha=0.6, beta=1.2, T=100.0) |
|
|
| print(f"Generated {len(events)} conflict events over 100 time units") |
| print(f"Average rate: {len(events) / 100.0:.2f} events/unit\n") |
|
|
| |
| result = hawkes.fit(events, T=100.0) |
|
|
| print("Estimated Hawkes Parameters:") |
| print(f" Baseline intensity (ΞΌ): {result.params.mu:.3f}") |
| print(f" Excitation (Ξ±): {result.params.alpha:.3f}") |
| print(f" Decay rate (Ξ²): {result.params.beta:.3f}") |
| print(f" Branching ratio: {result.params.branching_ratio:.3f}") |
| print(f" Process is {'STABLE' if result.params.is_stable else 'EXPLOSIVE'}") |
|
|
| |
| t_future = 105.0 |
| intensity = hawkes.predict_intensity(events, result.params, t_future) |
| print(f"\nPredicted conflict intensity at t={t_future}: {intensity:.3f}") |
|
|
| |
| print("\n" + "-"*80) |
| print("Multivariate Hawkes: Cross-Country Conflict Contagion") |
| print("-"*80) |
|
|
| countries = ['Syria', 'Iraq', 'Lebanon'] |
| contagion_model = ConflictContagionModel(countries=countries) |
|
|
| |
| mu = np.array([0.5, 0.3, 0.2]) |
| alpha = np.array([ |
| [0.3, 0.15, 0.1], |
| [0.2, 0.25, 0.1], |
| [0.15, 0.1, 0.2] |
| ]) |
| beta = np.ones((3, 3)) * 1.5 |
|
|
| multi_hawkes = MultivariateHawkesProcess(n_dimensions=3) |
| events_multi = multi_hawkes.simulate(mu=mu, alpha=alpha, beta=beta, T=100.0) |
|
|
| print(f"\nSimulated events:") |
| for i, country in enumerate(countries): |
| print(f" {country}: {len(events_multi[i])} events") |
|
|
| |
| events_dict = {country: events_multi[i] for i, country in enumerate(countries)} |
| fit_result = contagion_model.fit(events_dict, T=100.0) |
|
|
| print(f"\nFitted contagion model:") |
| print(f" Spectral radius: {fit_result['spectral_radius']:.3f} (< 1 = stable)") |
| print(f" Most contagious source: {fit_result['most_contagious_source']}") |
| print(f" Most vulnerable target: {fit_result['most_vulnerable_target']}") |
|
|
| |
| pathways = contagion_model.identify_contagion_pathways(fit_result, threshold=0.1) |
| print("\nSignificant contagion pathways (branching ratio > 0.1):") |
| for source, target, strength in pathways[:5]: |
| print(f" {source} β {target}: {strength:.3f}") |
|
|
| |
| risks = contagion_model.contagion_risk(events_dict, fit_result, t=105.0, horizon=5.0) |
| print("\nConflict risk over next 5 time units:") |
| for country, risk in risks.items(): |
| print(f" {country}: {risk:.1%}") |
|
|
| print("\nβ Hawkes processes capture conflict escalation dynamics!") |
|
|
|
|
| def demo_synthetic_control(): |
| """Demonstrate Synthetic Control Method.""" |
| print("\n" + "="*80) |
| print("3. Synthetic Control Method - Policy Impact Estimation") |
| print("="*80) |
|
|
| |
| print("\nScenario: Economic sanctions imposed on Country A at t=50") |
| print("Question: What is the causal effect on GDP growth?\n") |
|
|
| |
| np.random.seed(42) |
| T = 100 |
| J = 10 |
|
|
| |
| time = np.arange(T) |
| trend = 0.02 * time + np.random.randn(T) * 0.1 |
|
|
| |
| control_outcomes = np.zeros((T, J)) |
| for j in range(J): |
| control_outcomes[:, j] = trend + np.random.randn(T) * 0.15 + np.random.randn() * 0.5 |
|
|
| |
| treated_outcome = trend + np.random.randn(T) * 0.15 |
|
|
| |
| treatment_time = 50 |
| true_effect = -0.8 |
| treated_outcome[treatment_time:] += true_effect + np.random.randn(T - treatment_time) * 0.1 |
|
|
| |
| scm = SyntheticControlMethod() |
| result = scm.fit( |
| treated_outcome=treated_outcome, |
| control_outcomes=control_outcomes, |
| treatment_time=treatment_time, |
| control_names=[f"Country_{j+1}" for j in range(J)] |
| ) |
|
|
| print("Synthetic Control Results:") |
| print(f" Pre-treatment fit (RMSPE): {result.pre_treatment_fit:.4f}") |
| print(f"\nSynthetic Country A is weighted combination of:") |
| for j, weight in enumerate(result.weights): |
| if weight > 0.01: |
| print(f" {result.control_units[j]}: {weight:.1%}") |
|
|
| |
| avg_effect = np.mean(result.treatment_effect[treatment_time:]) |
| print(f"\nEstimated treatment effect (post-sanctions):") |
| print(f" Average: {avg_effect:.3f} (true effect: {true_effect:.3f})") |
| print(f" Final period: {result.treatment_effect[-1]:.3f}") |
|
|
| |
| p_value = scm.placebo_test(treated_outcome, control_outcomes, treatment_time, n_permutations=J) |
| print(f"\nPlacebo test p-value: {p_value:.3f}") |
| if p_value < 0.05: |
| print(" β Effect is statistically significant (unusual compared to placebos)") |
| else: |
| print(" β Effect not significant (could be random)") |
|
|
| print("\nβ Synthetic control provides credible counterfactual!") |
|
|
|
|
| def demo_difference_in_differences(): |
| """Demonstrate Difference-in-Differences.""" |
| print("\n" + "="*80) |
| print("4. Difference-in-Differences (DiD) - Regime Change Analysis") |
| print("="*80) |
|
|
| |
| print("\nScenario: Regime change in Country T at t=50") |
| print("Compare to similar countries without regime change\n") |
|
|
| np.random.seed(42) |
|
|
| |
| treated_pre = 3.0 + np.random.randn(50) * 0.5 |
| control_pre = 3.2 + np.random.randn(50) * 0.5 |
|
|
| |
| true_effect = 1.5 |
| treated_post = 3.0 + true_effect + np.random.randn(50) * 0.5 |
| control_post = 3.2 + np.random.randn(50) * 0.5 |
|
|
| |
| did = DifferenceinDifferences() |
| result = did.estimate(treated_pre, treated_post, control_pre, control_post) |
|
|
| print("Difference-in-Differences Results:") |
| print(f"\n Pre-treatment difference: {result.pre_treatment_diff:.3f}") |
| print(f" Post-treatment difference: {result.post_treatment_diff:.3f}") |
| print(f"\n Average Treatment Effect (ATT): {result.att:.3f}") |
| print(f" Standard error: {result.se:.3f}") |
| print(f" t-statistic: {result.t_stat:.3f}") |
| print(f" p-value: {result.p_value:.4f}") |
|
|
| if result.p_value < 0.05: |
| print(f"\n β Regime change had significant effect (true effect: {true_effect:.3f})") |
| else: |
| print("\n β Effect not statistically significant") |
|
|
| |
| if abs(result.pre_treatment_diff) < 0.5: |
| print("\n β Parallel trends assumption plausible (small pre-treatment diff)") |
| else: |
| print("\n β Parallel trends questionable (large pre-treatment diff)") |
|
|
| print("\nβ DiD isolates causal effect of regime change!") |
|
|
|
|
| def demo_regression_discontinuity(): |
| """Demonstrate Regression Discontinuity Design.""" |
| print("\n" + "="*80) |
| print("5. Regression Discontinuity Design (RDD) - Election Effects") |
| print("="*80) |
|
|
| |
| print("\nScenario: Effect of hawkish candidate winning election") |
| print("Running variable: Vote share (cutoff = 50%)") |
| print("Outcome: Military spending increase\n") |
|
|
| np.random.seed(42) |
| n = 500 |
|
|
| |
| vote_share = np.random.uniform(0.3, 0.7, n) |
|
|
| |
| |
| outcome = 2.0 + 1.5 * vote_share + np.random.randn(n) * 0.3 |
|
|
| |
| true_effect = 0.8 |
| outcome[vote_share >= 0.5] += true_effect |
|
|
| |
| rdd = RegressionDiscontinuity(cutoff=0.5) |
| result = rdd.estimate_sharp( |
| running_var=vote_share, |
| outcome=outcome, |
| bandwidth=0.15, |
| kernel='triangular' |
| ) |
|
|
| print("Regression Discontinuity Results:") |
| print(f"\n Bandwidth: {result.bandwidth:.3f}") |
| print(f" Observations below cutoff: {result.n_left}") |
| print(f" Observations above cutoff: {result.n_right}") |
| print(f"\n Treatment effect (LATE): {result.treatment_effect:.3f}") |
| print(f" Standard error: {result.se:.3f}") |
| print(f" t-statistic: {result.t_stat:.3f}") |
| print(f" p-value: {result.p_value:.4f}") |
|
|
| if result.p_value < 0.05: |
| print(f"\n β Winning election causes increase in military spending") |
| print(f" (true effect: {true_effect:.3f})") |
| else: |
| print("\n β Effect not statistically significant") |
|
|
| print("\nβ RDD exploits threshold-based treatment assignment!") |
|
|
|
|
| def demo_instrumental_variables(): |
| """Demonstrate Instrumental Variables.""" |
| print("\n" + "="*80) |
| print("6. Instrumental Variables (IV) - Trade and Conflict") |
| print("="*80) |
|
|
| |
| print("\nScenario: Does trade reduce conflict?") |
| print("Problem: Trade is endogenous (reverse causality, omitted variables)") |
| print("Instrument: Geographic distance to major trade routes\n") |
|
|
| np.random.seed(42) |
| n = 300 |
|
|
| |
| distance = np.random.uniform(100, 1000, n) |
|
|
| |
| unobserved = np.random.randn(n) |
|
|
| |
| trade = 50 - 0.03 * distance + 2.0 * unobserved + np.random.randn(n) * 5 |
|
|
| |
| true_effect = -0.15 |
| conflict = 10 + true_effect * trade - 1.5 * unobserved + np.random.randn(n) * 2 |
|
|
| |
| iv = InstrumentalVariables() |
| result = iv.estimate_2sls( |
| outcome=conflict, |
| endogenous=trade, |
| instrument=distance |
| ) |
|
|
| print("Instrumental Variables (2SLS) Results:") |
| print(f"\n First stage F-statistic: {result.first_stage_f:.2f}") |
| if result.weak_instrument: |
| print(" β Warning: Weak instrument (F < 10)") |
| else: |
| print(" β Strong instrument (F > 10)") |
|
|
| print(f"\n OLS estimate (biased): {result.beta_ols[0]:.4f}") |
| print(f" IV estimate (consistent): {result.beta_iv[0]:.4f}") |
| print(f" IV standard error: {result.se_iv[0]:.4f}") |
| print(f"\n True causal effect: {true_effect:.4f}") |
|
|
| |
| if abs(result.beta_ols[0] - result.beta_iv[0]) > 0.05: |
| print("\n β OLS and IV differ substantially β endogeneity present") |
| print(" IV corrects for bias!") |
| else: |
| print("\n OLS and IV similar β endogeneity may be small") |
|
|
| print("\nβ IV isolates causal effect using exogenous variation!") |
|
|
|
|
| def demo_dynamic_factor_model(): |
| """Demonstrate Dynamic Factor Model for nowcasting.""" |
| print("\n" + "="*80) |
| print("7. Dynamic Factor Model (DFM) - High-Dimensional Nowcasting") |
| print("="*80) |
|
|
| |
| print("\nScenario: Nowcast regional tension from 50 economic/political indicators") |
| print("DFM extracts common latent factors driving all indicators\n") |
|
|
| np.random.seed(42) |
| T = 200 |
| n_indicators = 50 |
| n_factors = 3 |
|
|
| |
| true_factors = np.zeros((T, n_factors)) |
| for k in range(n_factors): |
| |
| for t in range(1, T): |
| true_factors[t, k] = 0.8 * true_factors[t-1, k] + np.random.randn() * 0.5 |
|
|
| |
| true_loadings = np.random.randn(n_indicators, n_factors) |
|
|
| |
| data = true_factors @ true_loadings.T + np.random.randn(T, n_indicators) * 0.5 |
|
|
| |
| dfm = DynamicFactorModel(n_factors=3, n_lags=1) |
| model = dfm.fit(data) |
|
|
| print(f"Dynamic Factor Model Results:") |
| print(f"\n Number of indicators: {n_indicators}") |
| print(f" Number of factors: {n_factors}") |
| print(f" Explained variance: {model['explained_variance_ratio']:.1%}") |
|
|
| |
| factors = model['factors'] |
| print(f"\n Extracted factor dimensions: {factors.shape}") |
| print(f" Factor 1 final value: {factors[-1, 0]:.3f}") |
| print(f" Factor 2 final value: {factors[-1, 1]:.3f}") |
| print(f" Factor 3 final value: {factors[-1, 2]:.3f}") |
|
|
| |
| forecast = dfm.forecast(model, steps=10) |
| print(f"\n 10-step ahead forecast dimensions: {forecast.shape}") |
| print(f" Average forecasted indicator value: {np.mean(forecast[-1]):.3f}") |
|
|
| |
| corr_0 = np.corrcoef(true_factors[:, 0], factors[:, 0])[0, 1] |
| print(f"\n Factor recovery (correlation with true): {abs(corr_0):.3f}") |
|
|
| print("\nβ DFM reduces dimensionality while preserving information!") |
|
|
|
|
| def main(): |
| """Run all demonstrations of final features.""" |
| print("=" * 80) |
| print("GeoBotv1 - COMPLETE FRAMEWORK DEMONSTRATION") |
| print("=" * 80) |
| print("\nThis example showcases the final components that complete GeoBotv1:") |
| print("β’ Vector Autoregression (VAR/SVAR/DFM)") |
| print("β’ Hawkes Processes for conflict contagion") |
| print("β’ Quasi-Experimental Causal Inference") |
| print(" - Synthetic Control Method") |
| print(" - Difference-in-Differences") |
| print(" - Regression Discontinuity Design") |
| print(" - Instrumental Variables") |
|
|
| |
| demo_var_model() |
| demo_hawkes_process() |
| demo_synthetic_control() |
| demo_difference_in_differences() |
| demo_regression_discontinuity() |
| demo_instrumental_variables() |
| demo_dynamic_factor_model() |
|
|
| print("\n" + "=" * 80) |
| print("GeoBotv1 Framework is NOW 100% COMPLETE!") |
| print("=" * 80) |
| print("\nπ All Research-Grade Mathematical Components Implemented:") |
| print("\nπ CORE FRAMEWORKS:") |
| print(" β Optimal Transport (Wasserstein, Kantorovich, Sinkhorn)") |
| print(" β Causal Inference (DAGs, SCMs, Do-Calculus)") |
| print(" β Bayesian Inference (MCMC, Particle Filters, VI)") |
| print(" β Stochastic Processes (SDEs, Jump-Diffusion)") |
| print(" β Time-Series Models (Kalman, HMM, VAR, Hawkes)") |
| print(" β Quasi-Experimental Methods (SCM, DiD, RDD, IV)") |
| print(" β Machine Learning (GNNs, Risk Scoring, Embeddings)") |
| print("\nπ SPECIALIZED CAPABILITIES:") |
| print(" β Multi-country interdependency modeling (VAR)") |
| print(" β Conflict contagion and escalation (Hawkes)") |
| print(" β Policy counterfactuals (Synthetic Control)") |
| print(" β Regime change effects (Difference-in-Differences)") |
| print(" β Election outcomes impact (Regression Discontinuity)") |
| print(" β Trade-conflict nexus (Instrumental Variables)") |
| print(" β High-dimensional nowcasting (Dynamic Factor Models)") |
| print("\n㪠MATHEMATICAL RIGOR:") |
| print(" β Measure-theoretic probability foundations") |
| print(" β Continuous-time dynamics (SDEs)") |
| print(" β Causal identification strategies") |
| print(" β Structural econometric methods") |
| print(" β Point process theory") |
| print(" β Optimal transport geometry") |
| print("\nπ‘ GeoBotv1 is ready for production geopolitical forecasting!") |
| print("=" * 80 + "\n") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|