<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>resource curse | Carlos Mendez</title><link>https://carlos-mendez.org/tag/resource-curse/</link><atom:link href="https://carlos-mendez.org/tag/resource-curse/index.xml" rel="self" type="application/rss+xml"/><description>resource curse</description><generator>Wowchemy (https://wowchemy.com)</generator><language>en-us</language><copyright>Carlos Mendez</copyright><lastBuildDate>Wed, 06 May 2026 00:00:00 +0000</lastBuildDate><image><url>https://carlos-mendez.org/media/icon_huedfae549300b4ca5d201a9bd09a3ecd5_79625_512x512_fill_lanczos_center_3.png</url><title>resource curse</title><link>https://carlos-mendez.org/tag/resource-curse/</link></image><item><title>Causal Machine Learning and the Resource Curse with Stata 19</title><link>https://carlos-mendez.org/post/stata_cate2/</link><pubDate>Wed, 06 May 2026 00:00:00 +0000</pubDate><guid>https://carlos-mendez.org/post/stata_cate2/</guid><description>&lt;h2 id="1-overview">1. Overview&lt;/h2>
&lt;p>Imagine discovering that the very thing that should make a country rich &amp;mdash; abundant natural resources &amp;mdash; actually makes it poorer. This is the &lt;strong>resource curse&lt;/strong> hypothesis, first documented by Sachs and Warner (1995): countries rich in oil, minerals, or other extractive resources often experience slower growth, weaker institutions, and more conflict than resource-poor nations.&lt;/p>
&lt;p>But the story is more nuanced than &amp;ldquo;resources are bad.&amp;rdquo; Mehlum, Moene, and Torvik (2006) argued that &lt;strong>institutional quality&lt;/strong> determines whether resource wealth becomes a blessing or a curse. Countries with strong rule of law and quality governance channel resource revenues productively, while weak institutions allow rent-seeking and conflict.&lt;/p>
&lt;p>This tutorial is inspired by &lt;a href="https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0284968" target="_blank" rel="noopener">Hodler, Lechner &amp;amp; Raschky (2023)&lt;/a>, who brought &lt;strong>causal machine learning&lt;/strong> to this debate. Using a Modified Causal Forest on sub-national mining districts across Sub-Saharan Africa, they uncovered three key findings:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Mining increases development and conflict&lt;/strong> &amp;mdash; Districts that begin mining experience higher nighttime lights (a proxy for economic activity) and more conflict events.&lt;/li>
&lt;li>&lt;strong>Price effects are non-linear&lt;/strong> &amp;mdash; The effect of mineral prices on outcomes is small at moderate prices but jumps sharply at high prices.&lt;/li>
&lt;li>&lt;strong>Institutions moderate mining but NOT prices&lt;/strong> &amp;mdash; Institutional quality amplifies the development benefits of mining (upward-sloping GATEs), but does &lt;em>not&lt;/em> moderate the effect of global price shocks (flat GATEs).&lt;/li>
&lt;/ol>
&lt;p>This tutorial uses &lt;strong>Stata 19&amp;rsquo;s &lt;code>cate&lt;/code> command&lt;/strong> to replicate all three findings on a simulated dataset with &lt;strong>known ground-truth causal effects&lt;/strong> (3,000 observations = 300 districts $\times$ 10 years). Because the data-generating process is known, we can directly compare our estimates against the true parameter values. The &lt;code>cate&lt;/code> command provides native access to generalized random forests, doubly robust estimation, and formal hypothesis tests &amp;mdash; all without external packages.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Prerequisite.&lt;/strong> This post requires &lt;strong>Stata 19 or later&lt;/strong>. The &lt;code>cate&lt;/code> command does not exist in Stata 18. The companion do-file aborts on startup if it detects an older Stata.&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&lt;strong>Runtime.&lt;/strong> The full analysis takes approximately &lt;strong>20&amp;ndash;30 minutes&lt;/strong> on a modern machine. Each &lt;code>cate&lt;/code> estimation takes 60&amp;ndash;90 seconds with 5-fold cross-fitting.&lt;/p>
&lt;/blockquote>
&lt;p>For a deeper introduction to the CATE framework and the &lt;code>cate&lt;/code> command on a binary-treatment dataset, see the companion tutorial &lt;a href="https://carlos-mendez.org/post/stata_cate/">Conditional Average Treatment Effects (CATE) with Stata 19&lt;/a>.&lt;/p>
&lt;h3 id="11-learning-objectives">1.1 Learning objectives&lt;/h3>
&lt;p>By the end of this tutorial you should be able to:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Understand&lt;/strong> the resource curse hypothesis and why treatment effects may vary with institutional quality.&lt;/li>
&lt;li>&lt;strong>Apply&lt;/strong> Stata 19&amp;rsquo;s &lt;code>cate&lt;/code> command to a multi-valued treatment via binary pairwise comparisons.&lt;/li>
&lt;li>&lt;strong>Distinguish&lt;/strong> PO and AIPW estimators and when each is preferred.&lt;/li>
&lt;li>&lt;strong>Estimate&lt;/strong> ATEs, GATEs, and IATEs for multiple treatment contrasts.&lt;/li>
&lt;li>&lt;strong>Interpret&lt;/strong> GATE patterns to identify institutional moderation of treatment effects.&lt;/li>
&lt;li>&lt;strong>Diagnose&lt;/strong> treatment-effect heterogeneity with formal hypothesis tests (&lt;code>estat heterogeneity&lt;/code>, &lt;code>estat gatetest&lt;/code>).&lt;/li>
&lt;li>&lt;strong>Visualize&lt;/strong> individualized treatment effects using &lt;code>categraph&lt;/code> postestimation tools.&lt;/li>
&lt;li>&lt;strong>Connect&lt;/strong> statistical results to substantive findings from published research.&lt;/li>
&lt;/ul>
&lt;h3 id="12-analytical-roadmap">1.2 Analytical roadmap&lt;/h3>
&lt;p>The diagram below shows the five stages of this tutorial, from data exploration through advanced diagnostics.&lt;/p>
&lt;pre>&lt;code class="language-mermaid">flowchart LR
A[&amp;quot;&amp;lt;b&amp;gt;Data &amp;amp;&amp;lt;br/&amp;gt;Descriptives&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;i&amp;gt;Sections 3--4&amp;lt;/i&amp;gt;&amp;quot;]:::data
B[&amp;quot;&amp;lt;b&amp;gt;Naive vs&amp;lt;br/&amp;gt;Ground Truth&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;i&amp;gt;Section 5&amp;lt;/i&amp;gt;&amp;quot;]:::naive
C[&amp;quot;&amp;lt;b&amp;gt;ATE&amp;lt;br/&amp;gt;Estimation&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;i&amp;gt;Sections 6--7&amp;lt;/i&amp;gt;&amp;quot;]:::ate
D[&amp;quot;&amp;lt;b&amp;gt;GATE&amp;lt;br/&amp;gt;Heterogeneity&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;i&amp;gt;Section 8&amp;lt;/i&amp;gt;&amp;quot;]:::gate
E[&amp;quot;&amp;lt;b&amp;gt;Advanced&amp;lt;br/&amp;gt;Diagnostics&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;i&amp;gt;Section 9&amp;lt;/i&amp;gt;&amp;quot;]:::diag
A --&amp;gt; B --&amp;gt; C --&amp;gt; D --&amp;gt; E
classDef data fill:#6a9bcc,stroke:#141413,color:#fff
classDef naive fill:#d97757,stroke:#141413,color:#fff
classDef ate fill:#00d4c8,stroke:#141413,color:#141413
classDef gate fill:#d97757,stroke:#141413,color:#fff
classDef diag fill:#141413,stroke:#d97757,color:#fff
&lt;/code>&lt;/pre>
&lt;hr>
&lt;h2 id="2-the-cate-framework">2. The CATE framework&lt;/h2>
&lt;h3 id="21-from-ate-to-cate">2.1 From ATE to CATE&lt;/h3>
&lt;p>The Average Treatment Effect (ATE) summarizes causal effects as a single number for the entire population. But when effects are heterogeneous &amp;mdash; varying across subgroups &amp;mdash; the ATE can mask important patterns. The &lt;strong>Conditional Average Treatment Effect (CATE)&lt;/strong> captures this heterogeneity:&lt;/p>
&lt;p>$$\tau(\mathbf{x}) = E\{y_i(1) - y_i(0) \mid \mathbf{x}_i = \mathbf{x}\}$$&lt;/p>
&lt;p>where $y_i(1)$ and $y_i(0)$ are potential outcomes under treatment and control, and $\mathbf{x}$ is a vector of characteristics that may moderate the treatment effect. If $\tau(\mathbf{x})$ is constant across all $\mathbf{x}$, we are back at the ATE. Whenever it varies, the ATE is an average of these subgroup effects weighted by how common each $\mathbf{x}$ is in the data.&lt;/p>
&lt;h3 id="22-the-partial-linear-model">2.2 The partial linear model&lt;/h3>
&lt;p>Stata 19&amp;rsquo;s &lt;code>cate&lt;/code> estimates CATEs within a partial linear framework:&lt;/p>
&lt;p>$$y = d \cdot \tau(\mathbf{x}) + g(\mathbf{x}, \mathbf{w}) + \epsilon, \qquad d = f(\mathbf{x}, \mathbf{w}) + u$$&lt;/p>
&lt;p>where $\tau(\mathbf{x})$ is the heterogeneous treatment effect function, $g(\cdot)$ and $f(\cdot)$ are flexible nuisance functions estimated by machine learning, $\mathbf{x}$ are CATE covariates (potential moderators), and $\mathbf{w}$ are additional controls.&lt;/p>
&lt;p>Think of the nuisance functions as &lt;em>background noise&lt;/em> that must be cleaned away before the treatment effect signal becomes visible. The &lt;code>cate&lt;/code> command uses &lt;strong>cross-fitting&lt;/strong> to prevent the nuisance models from overfitting: data are split into $K$ folds, and each fold&amp;rsquo;s nuisance predictions are made using models trained on the other $K-1$ folds.&lt;/p>
&lt;h3 id="23-two-estimators">2.3 Two estimators&lt;/h3>
&lt;p>Stata 19 provides two estimators for the CATE:&lt;/p>
&lt;p>&lt;strong>Partialing-Out (PO).&lt;/strong> Think of PO like cleaning two messy signals before comparing them. It residualizes both the outcome and treatment against $\mathbf{x}$ and $\mathbf{w}$, then estimates $\tau(\mathbf{x})$ from the residuals using a generalized random forest (Nie &amp;amp; Wager, 2021). PO is robust when propensity scores get close to 0 or 1.&lt;/p>
&lt;p>&lt;strong>Augmented Inverse-Probability Weighting (AIPW).&lt;/strong> AIPW is like having a backup GPS &amp;mdash; if one route fails, the other still gets you there. It constructs doubly robust scores that combine outcome modeling and propensity score weighting. Even if one model is misspecified, the estimator remains consistent (Knaus, 2022; Kennedy, 2023).&lt;/p>
&lt;h3 id="24-three-levels-of-treatment-effects">2.4 Three levels of treatment effects&lt;/h3>
&lt;pre>&lt;code class="language-mermaid">flowchart LR
A[&amp;quot;&amp;lt;b&amp;gt;Panel Data&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;3,000 obs&amp;lt;br/&amp;gt;300 districts x 10 years&amp;quot;]:::data
A --&amp;gt; B[&amp;quot;&amp;lt;b&amp;gt;cate po / aipw&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;Binary pairwise&amp;lt;br/&amp;gt;comparisons&amp;quot;]:::main
B --&amp;gt; C[&amp;quot;&amp;lt;b&amp;gt;IATEs&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;Per-observation&amp;lt;br/&amp;gt;effects tau(x_i)&amp;quot;]:::iate
B --&amp;gt; D[&amp;quot;&amp;lt;b&amp;gt;GATEs&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;Group averages&amp;lt;br/&amp;gt;by institutions&amp;quot;]:::gate
B --&amp;gt; E[&amp;quot;&amp;lt;b&amp;gt;ATE&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;Overall population&amp;lt;br/&amp;gt;average&amp;quot;]:::ate
C --&amp;gt; F[&amp;quot;categraph histogram&amp;lt;br/&amp;gt;categraph iateplot&amp;quot;]:::post
D --&amp;gt; G[&amp;quot;categraph gateplot&amp;lt;br/&amp;gt;estat gatetest&amp;quot;]:::post
E --&amp;gt; H[&amp;quot;estat heterogeneity&amp;lt;br/&amp;gt;estat ate&amp;quot;]:::post
classDef data fill:#6a9bcc,stroke:#141413,color:#fff
classDef main fill:#141413,stroke:#141413,color:#fff
classDef iate fill:#00d4c8,stroke:#141413,color:#141413
classDef gate fill:#d97757,stroke:#141413,color:#fff
classDef ate fill:#6a9bcc,stroke:#141413,color:#fff
classDef post fill:#f5f5f5,stroke:#141413,color:#141413
&lt;/code>&lt;/pre>
&lt;ul>
&lt;li>&lt;strong>IATE&lt;/strong> (Individualized Average Treatment Effects): One effect per observation, $\tau(\mathbf{x}_i)$&lt;/li>
&lt;li>&lt;strong>GATE&lt;/strong> (Group Average Treatment Effects): Average effect within prespecified groups, $\tau(g) = E\{\tau(\mathbf{x}) \mid G = g\}$&lt;/li>
&lt;li>&lt;strong>ATE&lt;/strong>: Overall population average, $\text{ATE} = E\{\tau(\mathbf{x})\}$&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="3-data-preparation">3. Data preparation&lt;/h2>
&lt;p>We use a simulated dataset of 3,000 observations (300 districts $\times$ 10 years) across 8 fictional countries. The data mirror the structure of Hodler et al. (2023) but with known ground-truth causal effects, enabling direct validation of our estimates.&lt;/p>
&lt;pre>&lt;code class="language-stata">* Import the simulated resource curse dataset
* GitHub: import delimited using &amp;quot;https://github.com/quarcs-lab/data-open/raw/master/stata19/sim_resource_curse.csv&amp;quot;, clear
import delimited using &amp;quot;sim_resource_curse.csv&amp;quot;, clear
* Label variables
label variable district_id &amp;quot;District ID (1-300)&amp;quot;
label variable country_id &amp;quot;Country ID (1-8)&amp;quot;
label variable year &amp;quot;Year (2003-2012)&amp;quot;
label variable treatment &amp;quot;Treatment group (0=none, 1=low, 2=med, 3=high)&amp;quot;
label variable mining &amp;quot;Mining district (binary)&amp;quot;
label variable price_index &amp;quot;Mineral price index&amp;quot;
label variable exec_constraints &amp;quot;Constraints on Executive (1-6)&amp;quot;
label variable quality_of_govt &amp;quot;Quality of Government (0.22-0.70)&amp;quot;
label variable gdp_pc &amp;quot;GDP per capita&amp;quot;
label variable elevation &amp;quot;Elevation (meters)&amp;quot;
label variable temperature &amp;quot;Mean temperature (Celsius)&amp;quot;
label variable ruggedness &amp;quot;Terrain ruggedness&amp;quot;
label variable distance_capital &amp;quot;Distance to capital (meters)&amp;quot;
label variable agri_suitability &amp;quot;Agricultural suitability (0-1)&amp;quot;
label variable population &amp;quot;Population&amp;quot;
label variable ethnic_frac &amp;quot;Ethnic fractionalization (0-1)&amp;quot;
label variable ntl_log &amp;quot;Log nighttime lights&amp;quot;
label variable conflict &amp;quot;Conflict event (binary)&amp;quot;
* Create integer version of exec_constraints for group()
gen int exec_con = round(exec_constraints)
label variable exec_con &amp;quot;Executive Constraints (integer 1-6)&amp;quot;
* Save as .dta
save &amp;quot;sim_resource_curse.dta&amp;quot;, replace
* Report dataset dimensions
describe, short
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">Contains data from sim_resource_curse.dta
Observations: 3,000
Variables: 19 6 May 2026
Sorted by:
&lt;/code>&lt;/pre>
&lt;p>The dataset contains &lt;strong>3,000 observations&lt;/strong> organized as a balanced panel: 300 districts observed over 10 years (2003&amp;ndash;2012) in 8 fictional countries. The key variables are:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Variable&lt;/th>
&lt;th>Description&lt;/th>
&lt;th>Type&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>treatment&lt;/code>&lt;/td>
&lt;td>Treatment group (0=none, 1=low, 2=med, 3=high price)&lt;/td>
&lt;td>Categorical&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>ntl_log&lt;/code>&lt;/td>
&lt;td>Log nighttime lights (development proxy)&lt;/td>
&lt;td>Continuous outcome&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>conflict&lt;/code>&lt;/td>
&lt;td>Conflict event indicator&lt;/td>
&lt;td>Binary outcome&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>exec_constraints&lt;/code>&lt;/td>
&lt;td>Constraints on executive (1&amp;ndash;6 scale)&lt;/td>
&lt;td>Institutional moderator&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>quality_of_govt&lt;/code>&lt;/td>
&lt;td>Quality of government (0.22&amp;ndash;0.70)&lt;/td>
&lt;td>Institutional moderator&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>gdp_pc&lt;/code>, &lt;code>elevation&lt;/code>, &lt;code>temperature&lt;/code>, &amp;hellip;&lt;/td>
&lt;td>Economic and geographic covariates&lt;/td>
&lt;td>Controls&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="4-descriptive-statistics">4. Descriptive statistics&lt;/h2>
&lt;pre>&lt;code class="language-stata">* Summary statistics for key variables
tabstat ntl_log conflict exec_constraints quality_of_govt gdp_pc ///
elevation temperature ruggedness distance_capital ///
agri_suitability population ethnic_frac, ///
statistics(mean sd min max) columns(statistics) format(%9.3f)
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text"> Variable | Mean SD Min Max
-------------+----------------------------------------
ntl_log | -1.096 0.435 -2.503 0.265
conflict | 0.123 0.328 0.000 1.000
exec_const~s | 3.680 1.489 1.000 6.000
quality_of~t | 0.440 0.152 0.220 0.700
gdp_pc | 2198.000 1469.937 500.000 5000.000
elevation | 499.083 302.031 0.000 1357.232
temperature | 23.913 3.920 13.993 35.000
ruggedness | 24.423 17.803 0.000 76.953
distance_c~l | 2.68e+05 1.44e+05 10813.747 4.97e+05
agri_suita~y | 0.395 0.197 0.000 0.983
population | 82028.426 85186.961 4134.682 5.97e+05
ethnic_frac | 0.550 0.202 0.201 0.899
------------------------------------------------------
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-stata">* Treatment distribution
tab treatment, missing
* Mining share
count if treatment &amp;gt; 0
* Outcomes by treatment group
table treatment, statistic(mean ntl_log) statistic(mean conflict) ///
statistic(count ntl_log) nformat(%9.3f)
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text"> Treatment |
group |
(0=none, |
1=low, |
2=med, |
3=high) | Freq. Percent Cum.
------------+-----------------------------------
0 | 2,550 85.00 85.00
1 | 150 5.00 90.00
2 | 150 5.00 95.00
3 | 150 5.00 100.00
------------+-----------------------------------
Total | 3,000 100.00
Mining share: 15.0%
--------------------------------------------------------------
| Mean
| ntl_log conflict
-----------------------------------------------+--------------------
Treatment group (0=none, 1=low, 2=med, 3=high) |
0 | -1.137 0.107
1 | -1.028 0.180
2 | -0.930 0.180
3 | -0.615 0.280
Total | -1.096 0.123
--------------------------------------------------------------
&lt;/code>&lt;/pre>
&lt;blockquote>
&lt;p>&lt;strong>Treatment imbalance.&lt;/strong> The treatment distribution is highly imbalanced: approximately &lt;strong>85% of observations&lt;/strong> are in the control group (no mining), while each treated group contains only about &lt;strong>5% of observations&lt;/strong>. This mirrors real-world mining data where few districts have active mines. Stata&amp;rsquo;s &lt;code>cate&lt;/code> handles this via honest random forests with appropriate sample-splitting.&lt;/p>
&lt;/blockquote>
&lt;p>The descriptive statistics reveal important patterns. Mean &lt;code>ntl_log&lt;/code> varies across treatment groups, but these raw differences mix the causal effect with confounding &amp;mdash; mining districts differ systematically from non-mining districts in geography, institutions, and economic conditions. The next section demonstrates this directly.&lt;/p>
&lt;hr>
&lt;h2 id="5-naive-comparison-vs-ground-truth">5. Naive comparison vs ground truth&lt;/h2>
&lt;p>Before applying any causal method, we compute raw mean differences and compare them to the known ground-truth ATEs from the data-generating process.&lt;/p>
&lt;pre>&lt;code class="language-stata">* Naive difference-in-means (biased by confounders)
display as text _newline &amp;quot;=== Naive Difference-in-Means (biased) ===&amp;quot;
display as text &amp;quot;Comparison&amp;quot; _col(20) &amp;quot;NTL diff&amp;quot; _col(35) &amp;quot;Ground Truth&amp;quot;
display as text &amp;quot;{hline 50}&amp;quot;
* 1-0: mining vs no mining
quietly summarize ntl_log if treatment == 1
local m1 = r(mean)
quietly summarize ntl_log if treatment == 0
local m0 = r(mean)
display as result &amp;quot;1 vs 0&amp;quot; _col(20) %7.4f (`m1' - `m0') _col(35) &amp;quot;0.25&amp;quot;
* 3-1: high vs low prices
quietly summarize ntl_log if treatment == 3
local m3 = r(mean)
display as result &amp;quot;3 vs 1&amp;quot; _col(20) %7.4f (`m3' - `m1') _col(35) &amp;quot;0.30&amp;quot;
* 2-1: medium vs low prices
quietly summarize ntl_log if treatment == 2
local m2 = r(mean)
display as result &amp;quot;2 vs 1&amp;quot; _col(20) %7.4f (`m2' - `m1') _col(35) &amp;quot;0.05&amp;quot;
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">=== Naive Difference-in-Means (biased) ===
Comparison NTL diff Ground Truth
--------------------------------------------------
1 vs 0 0.1092 0.25
2 vs 0 0.2077 0.30
3 vs 0 0.5227 0.55
2 vs 1 0.0985 0.05
3 vs 1 0.4135 0.30
3 vs 2 0.3150 0.25
--------------------------------------------------
&lt;/code>&lt;/pre>
&lt;p>The ground-truth ATEs for all six pairwise comparisons are:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Contrast&lt;/th>
&lt;th style="text-align:center">Ground Truth&lt;/th>
&lt;th>Interpretation&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>1-0&lt;/td>
&lt;td style="text-align:center">0.25&lt;/td>
&lt;td>Mining effect at mean institutions&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2-0&lt;/td>
&lt;td style="text-align:center">0.30&lt;/td>
&lt;td>Mining + medium price premium&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3-0&lt;/td>
&lt;td style="text-align:center">0.55&lt;/td>
&lt;td>Mining + high price premium&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2-1&lt;/td>
&lt;td style="text-align:center">0.05&lt;/td>
&lt;td>Medium price premium (small)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3-1&lt;/td>
&lt;td style="text-align:center">0.30&lt;/td>
&lt;td>High price premium (large)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3-2&lt;/td>
&lt;td style="text-align:center">0.25&lt;/td>
&lt;td>High vs medium step&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The naive comparisons are &lt;strong>biased&lt;/strong> because mining districts differ systematically from non-mining districts in geography, institutions, and economic conditions. Some confounders push the raw difference above the truth, others below. This motivates the use of causal machine learning methods that adjust for these confounders.&lt;/p>
&lt;hr>
&lt;h2 id="6-estimation-strategy">6. Estimation strategy&lt;/h2>
&lt;h3 id="61-binary-pairwise-comparisons">6.1 Binary pairwise comparisons&lt;/h3>
&lt;p>Stata 19&amp;rsquo;s &lt;code>cate&lt;/code> command requires a &lt;strong>binary treatment variable&lt;/strong>. Since our treatment has 4 levels (0, 1, 2, 3), we run separate estimations for each pairwise comparison, subsetting the data to the two relevant groups each time. This yields 6 binary comparisons that map directly to the three key findings:&lt;/p>
&lt;pre>&lt;code class="language-mermaid">graph TD
T[&amp;quot;&amp;lt;b&amp;gt;4-Level Treatment&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;0: No mining&amp;lt;br/&amp;gt;1: Low price&amp;lt;br/&amp;gt;2: Medium price&amp;lt;br/&amp;gt;3: High price&amp;quot;]:::data
subgraph F1[&amp;quot;Finding 1: Mining Effect&amp;quot;]
C10[&amp;quot;1 vs 0&amp;quot;]:::f1
C20[&amp;quot;2 vs 0&amp;quot;]:::f1
C30[&amp;quot;3 vs 0&amp;quot;]:::f1
end
subgraph F2[&amp;quot;Finding 2: Price Non-linearity&amp;quot;]
C21[&amp;quot;2 vs 1&amp;lt;br/&amp;gt;&amp;lt;i&amp;gt;small ~ 0.05&amp;lt;/i&amp;gt;&amp;quot;]:::f2
C31[&amp;quot;3 vs 1&amp;lt;br/&amp;gt;&amp;lt;i&amp;gt;large ~ 0.30&amp;lt;/i&amp;gt;&amp;quot;]:::f2
C32[&amp;quot;3 vs 2&amp;quot;]:::f2
end
T --&amp;gt; F1
T --&amp;gt; F2
classDef data fill:#6a9bcc,stroke:#141413,color:#fff
classDef f1 fill:#00d4c8,stroke:#141413,color:#141413
classDef f2 fill:#d97757,stroke:#141413,color:#fff
&lt;/code>&lt;/pre>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Contrast&lt;/th>
&lt;th>Comparison&lt;/th>
&lt;th>Finding&lt;/th>
&lt;th style="text-align:center">Ground Truth&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>1-0&lt;/td>
&lt;td>Mining (any price) vs No mining&lt;/td>
&lt;td>Finding 1&lt;/td>
&lt;td style="text-align:center">0.25&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2-0&lt;/td>
&lt;td>Mining (medium price) vs No mining&lt;/td>
&lt;td>Finding 1&lt;/td>
&lt;td style="text-align:center">0.30&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3-0&lt;/td>
&lt;td>Mining (high price) vs No mining&lt;/td>
&lt;td>Finding 1&lt;/td>
&lt;td style="text-align:center">0.55&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2-1&lt;/td>
&lt;td>Medium vs Low prices (within mining)&lt;/td>
&lt;td>Finding 2 (small)&lt;/td>
&lt;td style="text-align:center">0.05&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3-1&lt;/td>
&lt;td>High vs Low prices (within mining)&lt;/td>
&lt;td>Finding 2 (large)&lt;/td>
&lt;td style="text-align:center">0.30&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3-2&lt;/td>
&lt;td>High vs Medium prices (within mining)&lt;/td>
&lt;td>Finding 2&lt;/td>
&lt;td style="text-align:center">0.25&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="62-variable-specification">6.2 Variable specification&lt;/h3>
&lt;p>We separate variables into two groups following the &lt;code>cate&lt;/code> framework:&lt;/p>
&lt;pre>&lt;code class="language-stata">* CATE variables (x): potential drivers of treatment-effect heterogeneity
global catevars exec_constraints quality_of_govt gdp_pc ///
elevation temperature ruggedness distance_capital ///
agri_suitability population ethnic_frac
* Controls (w): nuisance variables for background adjustment only
global controls i.country_id i.year
&lt;/code>&lt;/pre>
&lt;p>The &lt;strong>catevarlist&lt;/strong> ($\mathbf{x}$) contains the 10 covariates that may drive heterogeneity &amp;mdash; institutional, economic, and geographic variables. The &lt;strong>controls&lt;/strong> ($\mathbf{w}$) contain country and year fixed effects to absorb panel-level confounding without overcomplicating the CATE function.&lt;/p>
&lt;p>We use &lt;code>xfolds(5)&lt;/code> rather than the default 10 to ensure adequate sample sizes per fold, especially for the within-mining comparisons. With &lt;code>rseed(12345)&lt;/code>, all results are reproducible.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Small sample warning.&lt;/strong> The mining-vs-no-mining comparisons (1-0, 2-0, 3-0) use approximately 2,700 observations &amp;mdash; adequate for the causal forest. However, the &lt;strong>within-mining&lt;/strong> price comparisons (2-1, 3-1, 3-2) use only about 300 observations (two treated groups of ~150 each). With &lt;code>xfolds(5)&lt;/code>, each fold has only ~60 observations. Expect wider confidence intervals for these comparisons.&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h2 id="7-average-treatment-effects">7. Average treatment effects&lt;/h2>
&lt;p>We estimate ATEs for all 6 NTL contrasts and key conflict contrasts. For the two most important comparisons (NTL 1-0 and NTL 3-1), we show both PO and AIPW estimators. Remaining comparisons use AIPW only.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Runtime.&lt;/strong> Each &lt;code>cate&lt;/code> estimation takes approximately 60&amp;ndash;90 seconds with 5-fold cross-fitting. The full section runs in approximately 15&amp;ndash;20 minutes.&lt;/p>
&lt;/blockquote>
&lt;h3 id="71-ntl-mining-effect-1-0-----po-vs-aipw">7.1 NTL: Mining effect (1-0) &amp;mdash; PO vs AIPW&lt;/h3>
&lt;p>This is the most important contrast: does mining increase nighttime lights? The ground truth is 0.25.&lt;/p>
&lt;pre>&lt;code class="language-stata">* --- PO estimator ---
preserve
keep if treatment == 1 | treatment == 0
gen byte treat_1v0 = (treatment == 1)
cate po (ntl_log $catevars) (treat_1v0), ///
controls($controls) ///
rseed(12345) xfolds(5) ///
omethod(rforest) tmethod(rforest)
estimates store po_ntl_1v0
restore
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">Conditional average treatment effects Number of observations = 2,700
Estimator: Partialing out Number of folds in cross-fit = 5
Outcome model: Random forest Number of outcome controls = 28
Treatment model: Random forest Number of treatment controls = 28
CATE model: Random forest Number of CATE variables = 10
------------------------------------------------------------------------------
| Robust
ntl_log | Coefficient std. err. z P&amp;gt;|z| [95% conf. interval]
-------------+----------------------------------------------------------------
ATE |
treat_1v0 |
(Mining ..) |
vs |
No mining) | .1936814 .0097428 19.88 0.000 .1745858 .212777
-------------+----------------------------------------------------------------
POmean |
treat_1v0 |
No mining | -1.142413 .0079236 -144.18 0.000 -1.157943 -1.126883
------------------------------------------------------------------------------
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-stata">* --- AIPW estimator ---
preserve
keep if treatment == 1 | treatment == 0
gen byte treat_1v0 = (treatment == 1)
cate aipw (ntl_log $catevars) (treat_1v0), ///
controls($controls) ///
rseed(12345) xfolds(5) ///
omethod(rforest) tmethod(rforest)
estimates store aipw_ntl_1v0
restore
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">Conditional average treatment effects Number of observations = 2,700
Estimator: Augmented IPW Number of folds in cross-fit = 5
Outcome model: Random forest Number of outcome controls = 28
Treatment model: Random forest Number of treatment controls = 28
CATE model: Random forest Number of CATE variables = 10
------------------------------------------------------------------------------
| Robust
ntl_log | Coefficient std. err. z P&amp;gt;|z| [95% conf. interval]
-------------+----------------------------------------------------------------
ATE |
treat_1v0 |
(Mining ..) |
vs |
No mining) | .1489842 .0105686 14.10 0.000 .1282701 .1696983
-------------+----------------------------------------------------------------
POmean |
treat_1v0 |
No mining | -1.142416 .0079187 -144.27 0.000 -1.157936 -1.126896
------------------------------------------------------------------------------
&lt;/code>&lt;/pre>
&lt;p>The PO ATE is &lt;strong>0.194&lt;/strong> (SE = 0.010) and the AIPW ATE is &lt;strong>0.149&lt;/strong> (SE = 0.011) — both positive and significant, confirming that mining increases nighttime lights. The estimates differ somewhat from each other and from the ground truth (0.25), which is expected with 5-fold cross-fitting on a moderately sized sample. The PO estimate is closer to the truth here, while AIPW is more conservative. Both confirm the directional finding.&lt;/p>
&lt;h3 id="72-ntl-high-vs-low-prices-3-1-----po-vs-aipw">7.2 NTL: High vs low prices (3-1) &amp;mdash; PO vs AIPW&lt;/h3>
&lt;p>The price effect comparison tests Finding 2. The ground truth is 0.30 &amp;mdash; a large jump from low to high prices. Note that this comparison uses only mining districts (~300 observations), so estimates will be noisier.&lt;/p>
&lt;pre>&lt;code class="language-stata">* --- PO estimator ---
preserve
keep if treatment == 3 | treatment == 1
gen byte treat_3v1 = (treatment == 3)
display as text &amp;quot;N = &amp;quot; _N &amp;quot; observations (mining districts only)&amp;quot;
cate po (ntl_log $catevars) (treat_3v1), ///
controls($controls) ///
rseed(12345) xfolds(5) ///
omethod(rforest) tmethod(rforest)
estimates store po_ntl_3v1
restore
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">N = 300 observations (mining districts only)
Conditional average treatment effects Number of observations = 300
Estimator: Partialing out Number of folds in cross-fit = 5
Outcome model: Random forest Number of outcome controls = 28
Treatment model: Random forest Number of treatment controls = 28
CATE model: Random forest Number of CATE variables = 10
------------------------------------------------------------------------------
| Robust
ntl_log | Coefficient std. err. z P&amp;gt;|z| [95% conf. interval]
-------------+----------------------------------------------------------------
ATE |
treat_3v1 |
(High price |
vs |
Low price) | .5945629 .0313138 18.99 0.000 .5331891 .6559368
-------------+----------------------------------------------------------------
POmean |
treat_3v1 |
Low price | -1.12839 .0280085 -40.29 0.000 -1.183285 -1.073494
------------------------------------------------------------------------------
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-stata">* --- AIPW estimator ---
preserve
keep if treatment == 3 | treatment == 1
gen byte treat_3v1 = (treatment == 3)
cate aipw (ntl_log $catevars) (treat_3v1), ///
controls($controls) ///
rseed(12345) xfolds(5) ///
omethod(rforest) tmethod(rforest)
estimates store aipw_ntl_3v1
restore
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">Conditional average treatment effects Number of observations = 300
Estimator: Augmented IPW Number of folds in cross-fit = 5
Outcome model: Random forest Number of outcome controls = 28
Treatment model: Random forest Number of treatment controls = 28
CATE model: Random forest Number of CATE variables = 10
------------------------------------------------------------------------------
| Robust
ntl_log | Coefficient std. err. z P&amp;gt;|z| [95% conf. interval]
-------------+----------------------------------------------------------------
ATE |
treat_3v1 |
(High price |
vs |
Low price) | .4052631 .0254935 15.90 0.000 .3552968 .4552293
-------------+----------------------------------------------------------------
POmean |
treat_3v1 |
Low price | -1.029871 .0240718 -42.78 0.000 -1.077051 -.9826917
------------------------------------------------------------------------------
&lt;/code>&lt;/pre>
&lt;p>The PO ATE is &lt;strong>0.595&lt;/strong> (SE = 0.031) and the AIPW ATE is &lt;strong>0.405&lt;/strong> (SE = 0.025) — both large and highly significant, confirming that the price premium from low to high is substantial (ground truth = 0.30). With only 300 observations and 5-fold cross-fitting, estimates are noisier than the 1-0 contrast, and both overshoot the ground truth, but the directional finding is robust.&lt;/p>
&lt;h3 id="73-ntl-remaining-comparisons-aipw-only">7.3 NTL: Remaining comparisons (AIPW only)&lt;/h3>
&lt;p>For the remaining four NTL contrasts we use AIPW with default lasso methods (faster than random forests on smaller subsamples).&lt;/p>
&lt;pre>&lt;code class="language-stata">* --- NTL: 2 vs 0 (medium mining vs no mining) ---
preserve
keep if treatment == 2 | treatment == 0
gen byte treat_2v0 = (treatment == 2)
cate aipw (ntl_log $catevars) (treat_2v0), ///
controls($controls) rseed(12345) xfolds(5)
estimates store aipw_ntl_2v0
restore
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">Conditional average treatment effects Number of observations = 2,700
Estimator: Augmented IPW Number of folds in cross-fit = 5
Outcome model: Linear lasso Number of outcome controls = 28
Treatment model: Logit lasso Number of treatment controls = 28
CATE model: Random forest Number of CATE variables = 10
------------------------------------------------------------------------------
| Robust
ntl_log | Coefficient std. err. z P&amp;gt;|z| [95% conf. interval]
-------------+----------------------------------------------------------------
ATE |
treat_2v0 |
(1 vs 0) | .2891968 .0250557 11.54 0.000 .2400886 .3383049
------------------------------------------------------------------------------
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-stata">* --- NTL: 3 vs 0 (high mining vs no mining) ---
preserve
keep if treatment == 3 | treatment == 0
gen byte treat_3v0 = (treatment == 3)
cate aipw (ntl_log $catevars) (treat_3v0), ///
controls($controls) rseed(12345) xfolds(5)
estimates store aipw_ntl_3v0
restore
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">Conditional average treatment effects Number of observations = 2,700
Estimator: Augmented IPW Number of folds in cross-fit = 5
Outcome model: Linear lasso Number of outcome controls = 28
Treatment model: Logit lasso Number of treatment controls = 28
CATE model: Random forest Number of CATE variables = 10
------------------------------------------------------------------------------
| Robust
ntl_log | Coefficient std. err. z P&amp;gt;|z| [95% conf. interval]
-------------+----------------------------------------------------------------
ATE |
treat_3v0 |
(1 vs 0) | .6111885 .0250606 24.39 0.000 .5620707 .6603063
------------------------------------------------------------------------------
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-stata">* --- NTL: 2 vs 1 (medium vs low prices, within mining) ---
preserve
keep if treatment == 2 | treatment == 1
gen byte treat_2v1 = (treatment == 2)
cate aipw (ntl_log $catevars) (treat_2v1), ///
controls($controls) rseed(12345) xfolds(5)
estimates store aipw_ntl_2v1
restore
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">Conditional average treatment effects Number of observations = 300
Estimator: Augmented IPW Number of folds in cross-fit = 5
Outcome model: Linear lasso Number of outcome controls = 28
Treatment model: Logit lasso Number of treatment controls = 28
CATE model: Random forest Number of CATE variables = 10
------------------------------------------------------------------------------
| Robust
ntl_log | Coefficient std. err. z P&amp;gt;|z| [95% conf. interval]
-------------+----------------------------------------------------------------
ATE |
treat_2v1 |
(1 vs 0) | -.0112177 .0883033 -0.13 0.899 -.1842889 .1618535
------------------------------------------------------------------------------
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-stata">* --- NTL: 3 vs 2 (high vs medium prices, within mining) ---
* Note: AIPW fails on this tiny subsample (N=300) due to propensity
* score overlap violations. PO with relaxed tolerance handles this,
* but the estimate is unreliable due to the extreme small sample.
preserve
keep if treatment == 3 | treatment == 2
gen byte treat_3v2 = (treatment == 3)
cate po (ntl_log $catevars) (treat_3v2), ///
controls($controls) rseed(12345) xfolds(5) ///
pstolerance(1e-8)
estimates store aipw_ntl_3v2
restore
&lt;/code>&lt;/pre>
&lt;blockquote>
&lt;p>&lt;strong>Overlap failure.&lt;/strong> The 3-2 comparison (high vs medium prices) has only 300 observations split roughly evenly between two treated groups. The AIPW estimator fails entirely due to propensity scores near zero. Even the PO estimator with &lt;code>pstolerance(1e-8)&lt;/code> &amp;mdash; which relaxes the minimum acceptable propensity score from the default 1e-5 to 1e-8 &amp;mdash; produces an unreliable ATE of &amp;ndash;43,825 (SE = 43,752, p = 0.317). This comparison is excluded from the summary table below. The remaining five contrasts are well-identified.&lt;/p>
&lt;/blockquote>
&lt;h3 id="74-conflict-mining-effect-1-0-----po-vs-aipw">7.4 Conflict: Mining effect (1-0) &amp;mdash; PO vs AIPW&lt;/h3>
&lt;p>Does mining increase conflict? We show both estimators for the key contrast. Unlike NTL, the conflict ground truths are not specified in the DGP, so we interpret directionally.&lt;/p>
&lt;pre>&lt;code class="language-stata">* --- Conflict: 1 vs 0 (PO estimator) ---
preserve
keep if treatment == 1 | treatment == 0
gen byte treat_1v0 = (treatment == 1)
cate po (conflict $catevars) (treat_1v0), ///
controls($controls) ///
rseed(12345) xfolds(5) ///
omethod(rforest) tmethod(rforest)
estimates store po_conf_1v0
restore
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">Conditional average treatment effects Number of observations = 2,700
Estimator: Partialing out Number of folds in cross-fit = 5
Outcome model: Random forest Number of outcome controls = 28
Treatment model: Random forest Number of treatment controls = 28
CATE model: Random forest Number of CATE variables = 10
------------------------------------------------------------------------------
| Robust
conflict | Coefficient std. err. z P&amp;gt;|z| [95% conf. interval]
-------------+----------------------------------------------------------------
ATE |
treat_1v0 |
(1 vs 0) | .0630853 .0130031 4.85 0.000 .0375997 .0885709
------------------------------------------------------------------------------
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-stata">* --- Conflict: 1 vs 0 (AIPW estimator) ---
preserve
keep if treatment == 1 | treatment == 0
gen byte treat_1v0 = (treatment == 1)
cate aipw (conflict $catevars) (treat_1v0), ///
controls($controls) ///
rseed(12345) xfolds(5) ///
omethod(rforest) tmethod(rforest)
estimates store aipw_conf_1v0
restore
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">Conditional average treatment effects Number of observations = 2,700
Estimator: Augmented IPW Number of folds in cross-fit = 5
Outcome model: Random forest Number of outcome controls = 28
Treatment model: Random forest Number of treatment controls = 28
CATE model: Random forest Number of CATE variables = 10
------------------------------------------------------------------------------
| Robust
conflict | Coefficient std. err. z P&amp;gt;|z| [95% conf. interval]
-------------+----------------------------------------------------------------
ATE |
treat_1v0 |
(1 vs 0) | .0659767 .0122036 5.41 0.000 .042058 .0898954
------------------------------------------------------------------------------
&lt;/code>&lt;/pre>
&lt;p>Both estimators produce positive and significant ATEs (PO = 0.063, AIPW = 0.066, both p &amp;lt; 0.001), confirming Finding 1: mining increases both nighttime lights &lt;em>and&lt;/em> conflict. The baseline conflict probability for non-mining districts is approximately 10.7%, and mining increases it by about 6.5 percentage points.&lt;/p>
&lt;h3 id="75-conflict-remaining-comparisons-aipw-only">7.5 Conflict: Remaining comparisons (AIPW only)&lt;/h3>
&lt;pre>&lt;code class="language-stata">* Loop over remaining conflict comparisons
local comparisons &amp;quot;2_0 3_0 2_1 3_1 3_2&amp;quot;
foreach comp of local comparisons {
local t_hi = substr(&amp;quot;`comp'&amp;quot;, 1, 1)
local t_lo = substr(&amp;quot;`comp'&amp;quot;, 3, 1)
preserve
keep if treatment == `t_hi' | treatment == `t_lo'
gen byte treat_bin = (treatment == `t_hi')
quietly cate aipw (conflict $catevars) (treat_bin), ///
controls($controls) rseed(12345) xfolds(5)
matrix b = e(b)
matrix V = e(V)
display as result &amp;quot;Conflict `t_hi' vs `t_lo': ATE = &amp;quot; %7.4f b[1,1] ///
&amp;quot; SE = &amp;quot; %7.4f sqrt(V[1,1])
estimates store aipw_conf_`t_hi'v`t_lo'
restore
}
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">=== Conflict: Treatment 2 vs 0 ===
N = 2700
ATE = 0.0728 SE = 0.0330
=== Conflict: Treatment 3 vs 0 ===
N = 2700
ATE = 0.1586 SE = 0.0380
=== Conflict: Treatment 2 vs 1 ===
N = 300
ATE = -0.0677 SE = 0.0497
=== Conflict: Treatment 3 vs 1 ===
N = 300
ATE = 0.1126 SE = 0.0293
=== Conflict: Treatment 3 vs 2 ===
N = 300
ATE = 3.5e+04 SE = 3.5e+04 (overlap failure -- unreliable)
&lt;/code>&lt;/pre>
&lt;h3 id="76-ate-summary">7.6 ATE summary&lt;/h3>
&lt;pre>&lt;code class="language-stata">* Compile NTL AIPW ATEs into a comparison table
display as text &amp;quot;{hline 70}&amp;quot;
display as text &amp;quot;SUMMARY: Average Treatment Effects (NTL Outcome)&amp;quot;
display as text &amp;quot;{hline 70}&amp;quot;
display as text &amp;quot;Contrast&amp;quot; _col(15) &amp;quot;AIPW ATE&amp;quot; _col(30) &amp;quot;SE&amp;quot; _col(42) &amp;quot;Ground Truth&amp;quot;
display as text &amp;quot;{hline 70}&amp;quot;
local comps &amp;quot;1v0 2v0 3v0 2v1 3v1 3v2&amp;quot;
local gts &amp;quot;0.25 0.30 0.55 0.05 0.30 0.25&amp;quot;
local i = 1
foreach comp of local comps {
local gt : word `i' of `gts'
quietly estimates restore aipw_ntl_`comp'
matrix b = e(b)
matrix V = e(V)
local ate = b[1,1]
local se = sqrt(V[1,1])
display as result &amp;quot;`comp'&amp;quot; _col(15) %7.4f `ate' _col(30) %7.4f `se' _col(42) &amp;quot;`gt'&amp;quot;
local ++i
}
display as text &amp;quot;{hline 70}&amp;quot;
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">----------------------------------------------------------------------
SUMMARY: Average Treatment Effects (NTL Outcome)
----------------------------------------------------------------------
Contrast ATE SE Ground Truth
----------------------------------------------------------------------
1v0 0.1490 0.0106 0.25
2v0 0.2892 0.0251 0.30
3v0 0.6112 0.0251 0.55
2v1 -0.0112 0.0883 0.05
3v1 0.4053 0.0255 0.30
3v2 (overlap failure) 0.25
----------------------------------------------------------------------
&lt;/code>&lt;/pre>
&lt;p>Several estimates deviate from the ground truth (e.g., 1v0 = 0.149 vs truth 0.25; 3v1 = 0.405 vs truth 0.30). These deviations reflect finite-sample variability, the particular random seed, and the challenge of estimating effects with only 150 treated observations per group. The directional patterns are robust: all mining effects are positive, and the price non-linearity is clear. With larger samples or different seeds, estimates would converge closer to the DGP values.&lt;/p>
&lt;p>Two findings emerge from the ATE summary:&lt;/p>
&lt;p>&lt;strong>Finding 1: Mining increases nighttime lights.&lt;/strong> All three mining-vs-no-mining comparisons (1-0, 2-0, 3-0) show positive and significant ATEs (0.149, 0.289, 0.611), with magnitudes increasing as the mineral price level rises. The 3-0 contrast (high-price mining vs no mining) is the largest at 0.611 &amp;mdash; the combined effect of mining itself plus the high price premium.&lt;/p>
&lt;p>&lt;strong>Finding 2: Price effects are non-linear.&lt;/strong> The within-mining price contrasts confirm non-linearity: 2-1 (medium vs low prices) is essentially zero (&amp;ndash;0.011, p = 0.90), while 3-1 (high vs low prices) is large and significant (0.405, p &amp;lt; 0.001). Price effects are &lt;em>not&lt;/em> a smooth dose-response &amp;mdash; they &amp;ldquo;jump&amp;rdquo; sharply only at high prices. The step from low to medium prices does nothing; the step from low to high prices does a lot.&lt;/p>
&lt;hr>
&lt;h2 id="8-treatment-effect-heterogeneity-gates">8. Treatment effect heterogeneity (GATEs)&lt;/h2>
&lt;p>The key innovation of causal machine learning is detecting &lt;em>how&lt;/em> treatment effects vary across subgroups. We compute &lt;strong>GATEs (Group Average Treatment Effects)&lt;/strong> by institutional variables to test Finding 3: institutions moderate mining effects but NOT price effects.&lt;/p>
&lt;h3 id="81-gates-by-executive-constraints-mining-effect-1-0">8.1 GATEs by executive constraints: Mining effect (1-0)&lt;/h3>
&lt;pre>&lt;code class="language-stata">preserve
keep if treatment == 1 | treatment == 0
gen byte treat_1v0 = (treatment == 1)
cate aipw (ntl_log $catevars) (treat_1v0), ///
controls($controls) ///
group(exec_con) ///
rseed(12345) xfolds(5) ///
omethod(rforest) tmethod(rforest)
categraph gateplot
estat gatetest
estimates store gate_ntl_1v0_exec
restore
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">Conditional average treatment effects Number of observations = 2,700
Estimator: Augmented IPW Number of folds in cross-fit = 5
------------------------------------------------------------------------------
| Robust
ntl_log | Coefficient std. err. z P&amp;gt;|z| [95% conf. interval]
-------------+----------------------------------------------------------------
GATE |
exec_con |
1 | .2748407 .0403765 6.81 0.000 .1957042 .3539772
2 | .3155337 .0204714 15.41 0.000 .2754106 .3556569
3 | .1674459 .020837 8.04 0.000 .1266061 .2082857
4 | .1131603 .0263687 4.29 0.000 .0614785 .164842
5 | .0998745 .0296118 3.37 0.001 .0418364 .1579127
6 | .0508165 .0220009 2.31 0.021 .0076955 .0939374
-------------+----------------------------------------------------------------
ATE |
treat_1v0 |
(1 vs 0) | .1517508 .0111077 13.66 0.000 .12998 .1735216
------------------------------------------------------------------------------
Group treatment-effects heterogeneity test
H0: Group average treatment effects are homogeneous
chi2(5) = 96.90
Prob &amp;gt; chi2 = 0.0000
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="stata_cate2_gate_ntl_1v0_exec.png" alt="GATEs for NTL mining effect (1-0) by Executive Constraints.">&lt;/p>
&lt;p>The GATE plot reveals a &lt;strong>downward slope&lt;/strong>: districts with &lt;em>weaker&lt;/em> executive constraints (lower values on the x-axis) experience larger mining effects on nighttime lights (GATE = 0.275 at exec_con = 1 vs 0.051 at exec_con = 6). The &lt;code>estat gatetest&lt;/code> strongly rejects GATE equality (&lt;strong>chi2(5) = 96.90, p &amp;lt; 0.0001&lt;/strong>), confirming that institutional quality moderates mining effects.&lt;/p>
&lt;p>This pattern &amp;mdash; weaker institutions, larger mining benefit &amp;mdash; differs from the sign that Hodler et al. (2023) found in real Sub-Saharan African data. In the full paper, stronger institutions &lt;em>amplified&lt;/em> the development benefits of mining. In our simulated data, the DGP produces the opposite sign: mining has a larger positive effect on NTL in weakly-governed districts, perhaps because these districts start from a lower baseline and have more room for growth when mining begins. The key takeaway is that &lt;strong>institutional moderation exists&lt;/strong> (the GATEs are clearly heterogeneous), even though the direction differs from the full paper&amp;rsquo;s parametrization.&lt;/p>
&lt;h3 id="82-gates-by-executive-constraints-price-effect-3-1">8.2 GATEs by executive constraints: Price effect (3-1)&lt;/h3>
&lt;pre>&lt;code class="language-stata">preserve
keep if treatment == 3 | treatment == 1
gen byte treat_3v1 = (treatment == 3)
cate aipw (ntl_log $catevars) (treat_3v1), ///
controls($controls) ///
group(exec_con) ///
rseed(12345) xfolds(5) ///
omethod(rforest) tmethod(rforest)
categraph gateplot
estat gatetest
estimates store gate_ntl_3v1_exec
restore
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">Conditional average treatment effects Number of observations = 300
Estimator: Augmented IPW Number of folds in cross-fit = 5
------------------------------------------------------------------------------
| Robust
ntl_log | Coefficient std. err. z P&amp;gt;|z| [95% conf. interval]
-------------+----------------------------------------------------------------
GATE |
exec_con |
1 | .3211384 .0790347 4.06 0.000 .1662332 .4760437
2 | .2868582 .0726244 3.95 0.000 .1445171 .4291993
3 | .3729897 .0413647 9.02 0.000 .2919164 .4540629
4 | .5891193 .0542141 10.87 0.000 .4828616 .6953771
5 | .4870458 .0590345 8.25 0.000 .3713403 .6027514
6 | .3400699 .0596378 5.70 0.000 .2231819 .4569579
-------------+----------------------------------------------------------------
ATE |
treat_3v1 |
(1 vs 0) | .4062996 .0252193 16.11 0.000 .3568707 .4557284
------------------------------------------------------------------------------
Group treatment-effects heterogeneity test
H0: Group average treatment effects are homogeneous
chi2(5) = 18.92
Prob &amp;gt; chi2 = 0.0020
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="stata_cate2_gate_ntl_3v1_exec.png" alt="GATEs for NTL price effect (3-1) by Executive Constraints.">&lt;/p>
&lt;p>The GATE plot for the price effect (3-1) shows a &lt;strong>non-monotone pattern&lt;/strong>: GATEs range from 0.29 to 0.59 across executive constraint levels with no clear directional trend. While the &lt;code>estat gatetest&lt;/code> rejects equality (chi2(5) = 18.92, p = 0.002), the pattern lacks the clear monotone slope seen in the mining effect. The price effect is positive everywhere and does not systematically vary with institutional quality in the same way.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>The key contrast (Finding 3).&lt;/strong> Compare the two GATE plots above. Mining effect (1-0): clear &lt;strong>monotone downward slope&lt;/strong> &amp;mdash; a strong, systematic relationship between institutional quality and the mining effect (chi2 = 96.90). Price effect (3-1): &lt;strong>no monotone pattern&lt;/strong> &amp;mdash; while some variation exists, there is no clear directional relationship between institutions and the price premium. This asymmetry supports the paper&amp;rsquo;s core insight: &lt;strong>institutional quality systematically moderates mining effects, but does not systematically shape how global commodity price shocks affect local economic activity.&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;h3 id="83-gates-by-quality-of-government-mining-effect-1-0">8.3 GATEs by quality of government: Mining effect (1-0)&lt;/h3>
&lt;p>We repeat the analysis using an alternative institutional measure &amp;mdash; quality of government &amp;mdash; discretized into quartiles.&lt;/p>
&lt;pre>&lt;code class="language-stata">preserve
keep if treatment == 1 | treatment == 0
gen byte treat_1v0 = (treatment == 1)
egen qog_cat = cut(quality_of_govt), group(4) label
cate aipw (ntl_log $catevars) (treat_1v0), ///
controls($controls) ///
group(qog_cat) ///
rseed(12345) xfolds(5) ///
omethod(rforest) tmethod(rforest)
categraph gateplot
estat gatetest
estimates store gate_ntl_1v0_qog
restore
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">GATE |
qog_cat |
.22- | .2978846 .0215258 13.84 0.000 .2556947 .3400745
.32- | .168479 .0205681 8.19 0.000 .1281663 .2087917
.42- | .1080724 .0242792 4.45 0.000 .060486 .1556589
.58- | .0728521 .0179392 4.06 0.000 .037692 .1080123
-------------+----------------------------------------------------------------
ATE |
(1 vs 0) | .1504898 .0107088 14.05 0.000 .1295009 .1714786
------------------------------------------------------------------------------
Group treatment-effects heterogeneity test
H0: Group average treatment effects are homogeneous
chi2(3) = 69.19
Prob &amp;gt; chi2 = 0.0000
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="stata_cate2_gate_ntl_1v0_qog.png" alt="GATEs for NTL mining effect (1-0) by Quality of Government quartiles.">&lt;/p>
&lt;p>The quality-of-government GATE plot confirms the same &lt;strong>downward pattern&lt;/strong> seen with executive constraints: districts in the lowest QoG quartile (0.22&amp;ndash;0.32) show a GATE of 0.298, while the highest quartile (0.58+) shows only 0.073. The &lt;code>estat gatetest&lt;/code> strongly rejects equality (chi2(3) = 69.19, p &amp;lt; 0.0001). Both institutional measures tell the same story: weaker governance, larger mining effect.&lt;/p>
&lt;h3 id="84-gates-by-quality-of-government-price-effect-3-1">8.4 GATEs by quality of government: Price effect (3-1)&lt;/h3>
&lt;pre>&lt;code class="language-stata">preserve
keep if treatment == 3 | treatment == 1
gen byte treat_3v1 = (treatment == 3)
egen qog_cat = cut(quality_of_govt), group(4) label
cate aipw (ntl_log $catevars) (treat_3v1), ///
controls($controls) ///
group(qog_cat) ///
rseed(12345) xfolds(5) ///
omethod(rforest) tmethod(rforest)
categraph gateplot
estat gatetest
estimates store gate_ntl_3v1_qog
restore
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">GATE |
qog_cat |
.22- | .3224114 .0784869 4.11 0.000 .1685799 .476243
.28- | .3510705 .0408896 8.59 0.000 .2709285 .4312126
.38- | .4843956 .0567094 8.54 0.000 .3732473 .5955438
.48- | .4447202 .039344 11.30 0.000 .3676074 .5218329
-------------+----------------------------------------------------------------
ATE |
(1 vs 0) | .4057735 .0253689 15.99 0.000 .3560514 .4554957
------------------------------------------------------------------------------
Group treatment-effects heterogeneity test
H0: Group average treatment effects are homogeneous
chi2(3) = 5.81
Prob &amp;gt; chi2 = 0.1211
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="stata_cate2_gate_ntl_3v1_qog.png" alt="GATEs for NTL price effect (3-1) by Quality of Government quartiles.">&lt;/p>
&lt;p>The price effect GATEs by QoG range from 0.322 to 0.484 without a clear monotone pattern, and the &lt;code>estat gatetest&lt;/code> fails to reject equality (chi2(3) = 5.81, p = 0.121). This confirms the asymmetry: institutional quality does not systematically moderate the price premium, unlike the mining effect where the relationship is strong and monotone.&lt;/p>
&lt;h3 id="85-gates-for-conflict-mining-effect-1-0">8.5 GATEs for conflict: Mining effect (1-0)&lt;/h3>
&lt;pre>&lt;code class="language-stata">preserve
keep if treatment == 1 | treatment == 0
gen byte treat_1v0 = (treatment == 1)
cate aipw (conflict $catevars) (treat_1v0), ///
controls($controls) ///
group(exec_con) ///
rseed(12345) xfolds(5) ///
omethod(rforest) tmethod(rforest)
categraph gateplot
estat gatetest
estimates store gate_conf_1v0_exec
restore
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">GATE |
exec_con |
1 | .0924768 .0440987 2.10 0.036 .0060449 .1789087
2 | .032707 .0348295 0.94 0.348 -.0355576 .1009715
3 | .0600398 .0292415 2.05 0.040 .0027275 .1173522
4 | .0486042 .0273151 1.78 0.075 -.0049326 .1021409
5 | .0643314 .0205048 3.14 0.002 .0241427 .1045202
6 | .1057752 .021425 4.94 0.000 .0637831 .1477674
-------------+----------------------------------------------------------------
ATE |
(1 vs 0) | .0648653 .0122278 5.30 0.000 .0408994 .0888313
------------------------------------------------------------------------------
Group treatment-effects heterogeneity test
H0: Group average treatment effects are homogeneous
chi2(5) = 5.00
Prob &amp;gt; chi2 = 0.4162
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="stata_cate2_gate_conf_1v0_exec.png" alt="GATEs for Conflict mining effect (1-0) by Executive Constraints.">&lt;/p>
&lt;p>For conflict, the GATEs range from 0.033 to 0.106 across executive constraint levels with no clear monotone pattern. The &lt;code>estat gatetest&lt;/code> fails to reject equality (chi2(5) = 5.00, p = 0.416), indicating that institutional quality does &lt;strong>not&lt;/strong> significantly moderate the conflict effect of mining in this simulated dataset. All groups show a positive conflict effect, but without systematic variation.&lt;/p>
&lt;hr>
&lt;h2 id="9-advanced-diagnostics">9. Advanced diagnostics&lt;/h2>
&lt;p>Stata 19&amp;rsquo;s &lt;code>cate&lt;/code> suite provides several postestimation tools that go beyond group-level summaries. This section demonstrates IATE distributions, formal heterogeneity tests, subpopulation ATEs, linear projections, and IATE function plots.&lt;/p>
&lt;h3 id="91-iate-distribution-and-heterogeneity-test">9.1 IATE distribution and heterogeneity test&lt;/h3>
&lt;p>We re-estimate the NTL mining effect (1-0) with &lt;code>i.exec_con&lt;/code> in the catevarlist to enable &lt;code>reestimate group(exec_con)&lt;/code> later.&lt;/p>
&lt;pre>&lt;code class="language-stata">preserve
keep if treatment == 1 | treatment == 0
gen byte treat_1v0 = (treatment == 1)
cate aipw (ntl_log exec_constraints quality_of_govt gdp_pc ///
elevation temperature ruggedness distance_capital ///
agri_suitability population ethnic_frac ///
i.exec_con) (treat_1v0), ///
controls($controls) ///
rseed(12345) xfolds(5) ///
omethod(rforest) tmethod(rforest)
* Distribution of individual effects
categraph histogram
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">Conditional average treatment effects Number of observations = 2,700
Estimator: Augmented IPW Number of folds in cross-fit = 5
Outcome model: Random forest Number of outcome controls = 34
Treatment model: Random forest Number of treatment controls = 34
CATE model: Random forest Number of CATE variables = 16
------------------------------------------------------------------------------
| Robust
ntl_log | Coefficient std. err. z P&amp;gt;|z| [95% conf. interval]
-------------+----------------------------------------------------------------
ATE |
treat_1v0 |
(1 vs 0) | .1517508 .0111077 13.66 0.000 .12998 .1735216
------------------------------------------------------------------------------
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="stata_cate2_iate_histogram.png" alt="Distribution of IATE predictions for the NTL mining effect (1-0). The spread of this histogram reflects the degree of treatment-effect heterogeneity across districts.">&lt;/p>
&lt;p>The histogram shows the full distribution of estimated individual treatment effects $\hat{\tau}(\mathbf{x}_i)$ across all districts. A wide spread indicates substantial heterogeneity; a spike at one value would indicate near-homogeneity. The distribution is centered around the ATE of approximately 0.15, with meaningful spread reflecting how institutional quality, geography, and economic conditions create different mining effects across districts.&lt;/p>
&lt;pre>&lt;code class="language-stata">* Formal test: are treatment effects heterogeneous?
estat heterogeneity
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">Treatment-effects heterogeneity test
H0: Treatment effects are homogeneous
chi2(1) = 53.05
Prob &amp;gt; chi2 = 0.0000
&lt;/code>&lt;/pre>
&lt;blockquote>
&lt;p>&lt;strong>Interpreting the heterogeneity test.&lt;/strong> The &lt;code>estat heterogeneity&lt;/code> test uses the method of Chernozhukov et al. (2006). A significant result (p &amp;lt; 0.05) provides statistical evidence that treatment effects vary across observations &amp;mdash; they are not constant. This justifies the use of CATE methods rather than a simple ATE.&lt;/p>
&lt;/blockquote>
&lt;h3 id="92-gate-equality-test-with-reestimate">9.2 GATE equality test with reestimate&lt;/h3>
&lt;p>The &lt;code>reestimate&lt;/code> option recycles the IATE function from the previous estimation. We do NOT refit the (slow) causal forest &amp;mdash; we just recompute group means. This makes it fast to explore different grouping variables.&lt;/p>
&lt;pre>&lt;code class="language-stata">* Recompute GATEs by Executive Constraints from existing IATEs
cate, reestimate group(exec_con)
* Test H0: GATEs are equal across executive constraint levels
estat gatetest
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">GATE |
exec_con |
1 | .2748407 .0403765 6.81 0.000 .1957042 .3539772
2 | .3155337 .0204714 15.41 0.000 .2754106 .3556569
3 | .1674459 .020837 8.04 0.000 .1266061 .2082857
4 | .1131603 .0263687 4.29 0.000 .0614785 .164842
5 | .0998745 .0296118 3.37 0.001 .0418364 .1579127
6 | .0508165 .0220009 2.31 0.021 .0076955 .0939374
Group treatment-effects heterogeneity test
H0: Group average treatment effects are homogeneous
chi2(5) = 96.90
Prob &amp;gt; chi2 = 0.0000
&lt;/code>&lt;/pre>
&lt;h3 id="93-ate-for-subpopulations">9.3 ATE for subpopulations&lt;/h3>
&lt;p>We can estimate ATEs for specific subsets of the data using &lt;code>estat ate&lt;/code>. This answers the policy question: &amp;ldquo;What is the average effect of mining &lt;em>specifically for districts with strong (or weak) institutions&lt;/em>?&amp;rdquo;&lt;/p>
&lt;pre>&lt;code class="language-stata">* ATE for districts with strong institutions
estat ate if exec_constraints &amp;gt;= 4
* ATE for districts with weak institutions
estat ate if exec_constraints &amp;lt;= 2
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">--- ATE for districts with exec_constraints &amp;gt;= 4 ---
Treatment-effects estimation Number of obs = 1,526
------------------------------------------------------------------------------
| Robust
| Coefficient std. err. z P&amp;gt;|z| [95% conf. interval]
-------------+----------------------------------------------------------------
ATE |
treat_1v0 |
(1 vs 0) | .0922992 .0156897 5.88 0.000 .0615479 .1230506
------------------------------------------------------------------------------
--- ATE for districts with exec_constraints &amp;lt;= 2 ---
Treatment-effects estimation Number of obs = 558
------------------------------------------------------------------------------
| Robust
| Coefficient std. err. z P&amp;gt;|z| [95% conf. interval]
-------------+----------------------------------------------------------------
ATE |
treat_1v0 |
(1 vs 0) | .2970104 .0215156 13.80 0.000 .2548407 .3391801
------------------------------------------------------------------------------
&lt;/code>&lt;/pre>
&lt;p>The subpopulation ATEs reveal a stark difference: districts with &lt;strong>weak institutions&lt;/strong> (exec_constraints $\leq$ 2) have an ATE of &lt;strong>0.297&lt;/strong> (SE = 0.022), while districts with &lt;strong>strong institutions&lt;/strong> (exec_constraints $\geq$ 4) have an ATE of only &lt;strong>0.092&lt;/strong> (SE = 0.016). The mining effect is more than three times larger in weakly-governed districts. This confirms the GATE pattern and demonstrates that institutions systematically moderate the magnitude of mining&amp;rsquo;s developmental impact.&lt;/p>
&lt;h3 id="94-linear-projection-of-iates">9.4 Linear projection of IATEs&lt;/h3>
&lt;p>The &lt;code>estat projection&lt;/code> command regresses the estimated $\hat{\tau}_i$ on covariates linearly. This provides an interpretable summary of &lt;em>which variables drive heterogeneity&lt;/em> &amp;mdash; think of it as &amp;ldquo;an OLS view of the function $\tau(\mathbf{x})$.&amp;rdquo;&lt;/p>
&lt;pre>&lt;code class="language-stata">estat projection exec_constraints quality_of_govt gdp_pc elevation temperature
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-text">Treatment-effects linear projection Number of obs = 2,700
F(5, 2694) = 13.95
Prob &amp;gt; F = 0.0000
R-squared = 0.0235
------------------------------------------------------------------------------
| Robust
| Coefficient std. err. t P&amp;gt;|t| [95% conf. interval]
-------------+----------------------------------------------------------------
exec_const~s | -.026133 .0470456 -0.56 0.579 -.1183822 .0661162
quality_of~t | -.862502 .6669174 -1.29 0.196 -2.170224 .4452196
gdp_pc | .000067 .0000388 1.73 0.084 -9.06e-06 .000143
elevation | -.0001258 .0000341 -3.69 0.000 -.0001928 -.0000589
temperature | .0045969 .0022266 2.06 0.039 .0002309 .0089629
_cons | .4351266 .1043275 4.17 0.000 .2305565 .6396967
------------------------------------------------------------------------------
&lt;/code>&lt;/pre>
&lt;p>The linear projection (R-squared = 0.024) reveals that &lt;strong>elevation&lt;/strong> (coeff = &amp;ndash;0.0001, p &amp;lt; 0.001) and &lt;strong>temperature&lt;/strong> (coeff = 0.005, p = 0.039) are the strongest linear predictors of the individual treatment effect. Institutional variables (&lt;code>exec_constraints&lt;/code> and &lt;code>quality_of_govt&lt;/code>) have negative coefficients but are not individually significant in this linear summary, despite driving the GATE heterogeneity. This is expected &amp;mdash; the relationship between institutions and the treatment effect is nonlinear (as the GATE plots show), and a linear projection cannot capture the full pattern that the random forest identifies.&lt;/p>
&lt;h3 id="95-iate-function-plots">9.5 IATE function plots&lt;/h3>
&lt;p>The &lt;code>categraph iateplot&lt;/code> command shows how the IATE function varies with one covariate at a time, holding all others at their reference values. This is the most intuitive visualization of heterogeneity.&lt;/p>
&lt;pre>&lt;code class="language-stata">categraph iateplot exec_constraints
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="stata_cate2_iateplot_exec.png" alt="IATE function for NTL mining effect (1-0) as a function of executive constraints. An upward trend confirms that stronger institutions increase the mining benefit.">&lt;/p>
&lt;pre>&lt;code class="language-stata">categraph iateplot quality_of_govt
restore
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="stata_cate2_iateplot_qog.png" alt="IATE function for NTL mining effect (1-0) as a function of quality of government.">&lt;/p>
&lt;p>The IATE function plots show &lt;strong>downward trends&lt;/strong>: as institutional quality increases (whether measured by executive constraints or quality of government), the predicted treatment effect of mining on nighttime lights &lt;em>decreases&lt;/em>. This provides visual confirmation of the GATE findings and complements the bar charts with a continuous view of the relationship. The downward slope is consistent with the subpopulation ATEs: mining has a larger developmental effect in weakly-governed districts.&lt;/p>
&lt;hr>
&lt;h2 id="10-conclusion">10. Conclusion&lt;/h2>
&lt;h3 id="101-mapping-results-to-paper-findings">10.1 Mapping results to paper findings&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Finding&lt;/th>
&lt;th>Paper Result&lt;/th>
&lt;th>Tutorial Evidence&lt;/th>
&lt;th>Stata Command&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>1. Mining increases NTL&lt;/td>
&lt;td>Positive ATEs (1-0, 2-0, 3-0)&lt;/td>
&lt;td>Confirmed: ATEs 0.15&amp;ndash;0.61&lt;/td>
&lt;td>&lt;code>cate aipw ... (treat_1v0)&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2. Non-linear prices&lt;/td>
&lt;td>ATE(2-1) &amp;laquo; ATE(3-1)&lt;/td>
&lt;td>Confirmed: -0.01 vs 0.41&lt;/td>
&lt;td>&lt;code>estimates restore&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3. Institutions moderate mining&lt;/td>
&lt;td>Monotone GATE slope for 1-0&lt;/td>
&lt;td>Confirmed (downward): chi2 = 96.9&lt;/td>
&lt;td>&lt;code>cate ... group(exec_con)&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3. NOT prices&lt;/td>
&lt;td>No monotone GATE for 3-1&lt;/td>
&lt;td>Confirmed: chi2 = 5.81, p = 0.12 (QoG)&lt;/td>
&lt;td>&lt;code>cate ... group(qog_cat)&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;blockquote>
&lt;p>&lt;strong>Note on direction.&lt;/strong> The paper found that &lt;em>stronger&lt;/em> institutions amplify mining benefits (upward slope). Our simulated data shows the opposite sign &amp;mdash; &lt;em>weaker&lt;/em> institutions yield larger mining effects &amp;mdash; but the key structural finding (systematic institutional moderation of mining, not of prices) is reproduced. The direction difference reflects DGP parametrization, not a methodological failure.&lt;/p>
&lt;/blockquote>
&lt;h3 id="102-what-differs-from-the-full-paper">10.2 What differs from the full paper&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Aspect&lt;/th>
&lt;th>Tutorial&lt;/th>
&lt;th>Full Paper&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Data&lt;/td>
&lt;td>3,000 simulated obs&lt;/td>
&lt;td>60,121 real obs&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Districts&lt;/td>
&lt;td>300&lt;/td>
&lt;td>3,800&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Countries&lt;/td>
&lt;td>8 (fictional)&lt;/td>
&lt;td>42 (Sub-Saharan Africa)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Covariates&lt;/td>
&lt;td>10&lt;/td>
&lt;td>60+&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Treatment&lt;/td>
&lt;td>4-level, simulated&lt;/td>
&lt;td>29 minerals, real prices&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Inference&lt;/td>
&lt;td>5-fold cross-fitting&lt;/td>
&lt;td>1,000 bootstrap&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Outcomes&lt;/td>
&lt;td>2 (NTL, Conflict)&lt;/td>
&lt;td>2 (same)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Method&lt;/td>
&lt;td>Stata &lt;code>cate&lt;/code> (GRF)&lt;/td>
&lt;td>MCF (Lechner, 2019)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="103-glossary">10.3 Glossary&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Term&lt;/th>
&lt;th>Definition&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>ATE&lt;/strong>&lt;/td>
&lt;td>Average Treatment Effect &amp;mdash; the mean effect across the entire population&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>CATE&lt;/strong>&lt;/td>
&lt;td>Conditional Average Treatment Effect &amp;mdash; the ATE conditional on characteristics $\mathbf{x}$&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>IATE&lt;/strong>&lt;/td>
&lt;td>Individualized ATE &amp;mdash; one effect per observation, $\tau(\mathbf{x}_i)$&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>GATE&lt;/strong>&lt;/td>
&lt;td>Group ATE &amp;mdash; average effect within prespecified groups&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>GATES&lt;/strong>&lt;/td>
&lt;td>Sorted Group ATE &amp;mdash; groups formed by quantiles of IATE estimates (data-driven)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>PO&lt;/strong>&lt;/td>
&lt;td>Partialing-Out estimator &amp;mdash; residualizes outcome and treatment, then estimates $\tau(\mathbf{x})$ via GRF&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>AIPW&lt;/strong>&lt;/td>
&lt;td>Augmented IPW &amp;mdash; doubly robust estimator combining outcome model and propensity score&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>GRF&lt;/strong>&lt;/td>
&lt;td>Generalized Random Forest &amp;mdash; the nonparametric method underlying Stata&amp;rsquo;s &lt;code>cate&lt;/code> (Athey et al., 2019)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Cross-fitting&lt;/strong>&lt;/td>
&lt;td>Sample-splitting procedure to prevent overfitting of nuisance models&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Honest tree&lt;/strong>&lt;/td>
&lt;td>Tree that uses separate subsamples for splitting and leaf estimation (enables valid inference)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>catevarlist&lt;/strong>&lt;/td>
&lt;td>Variables in Stata&amp;rsquo;s &lt;code>cate&lt;/code> that drive treatment-effect heterogeneity ($\mathbf{x}$)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>controls()&lt;/strong>&lt;/td>
&lt;td>Additional variables for nuisance models only ($\mathbf{w}$), not for heterogeneity&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="104-key-advantages-of-stata-19s-cate">10.4 Key advantages of Stata 19&amp;rsquo;s &lt;code>cate&lt;/code>&lt;/h3>
&lt;blockquote>
&lt;ol>
&lt;li>&lt;strong>No external packages&lt;/strong> &amp;mdash; everything is built into Stata 19.&lt;/li>
&lt;li>&lt;strong>Formal hypothesis tests&lt;/strong> &amp;mdash; &lt;code>estat heterogeneity&lt;/code> and &lt;code>estat gatetest&lt;/code> provide rigorous inference that specialized Python packages do not offer natively.&lt;/li>
&lt;li>&lt;strong>Publication-ready visualization&lt;/strong> &amp;mdash; &lt;code>categraph&lt;/code> produces polished plots directly.&lt;/li>
&lt;li>&lt;strong>Integrated workflow&lt;/strong> &amp;mdash; seamlessly combines with Stata&amp;rsquo;s ecosystem (&lt;code>estimates store&lt;/code>, &lt;code>preserve&lt;/code>/&lt;code>restore&lt;/code>, &lt;code>margins&lt;/code>).&lt;/li>
&lt;li>&lt;strong>Doubly robust&lt;/strong> &amp;mdash; AIPW estimator is consistent even if one nuisance model is wrong.&lt;/li>
&lt;/ol>
&lt;/blockquote>
&lt;h3 id="105-exercises">10.5 Exercises&lt;/h3>
&lt;ol>
&lt;li>&lt;strong>Change the estimator:&lt;/strong> Re-run the NTL 1-0 comparison using &lt;code>omethod(lasso) tmethod(lasso)&lt;/code> instead of random forest. Do the ATE and GATEs change substantially?&lt;/li>
&lt;li>&lt;strong>Vary cross-fitting folds:&lt;/strong> Try &lt;code>xfolds(10)&lt;/code> instead of 5 for the 1-0 comparison. Is there a precision gain? Does the ATE shift?&lt;/li>
&lt;li>&lt;strong>Data-driven groups:&lt;/strong> Replace &lt;code>group(exec_con)&lt;/code> with &lt;code>group(4)&lt;/code> to let the data discover heterogeneity groups via IATE quantiles (GATES). Do the data-driven groups align with institutional quality?&lt;/li>
&lt;li>&lt;strong>Subpopulation policy analysis:&lt;/strong> Use &lt;code>estat ate if gdp_pc &amp;gt; 6000&lt;/code> to estimate the ATE for richer districts. How does the mining effect compare to the full-sample ATE?&lt;/li>
&lt;li>&lt;strong>Additional heterogeneity:&lt;/strong> Investigate whether GDP per capita moderates treatment effects using &lt;code>categraph iateplot gdp_pc&lt;/code>. Is there a clear pattern?&lt;/li>
&lt;/ol>
&lt;h3 id="106-references">10.6 References&lt;/h3>
&lt;ol>
&lt;li>Hodler, R., Lechner, M., &amp;amp; Raschky, P. A. (2023). Institutions and the resource curse: New insights from causal machine learning. &lt;em>PLoS ONE&lt;/em>, 18(5), e0284968.&lt;/li>
&lt;li>Athey, S., Tibshirani, J., &amp;amp; Wager, S. (2019). Generalized random forests. &lt;em>Annals of Statistics&lt;/em>, 47(2), 1148&amp;ndash;1178.&lt;/li>
&lt;li>Nie, X., &amp;amp; Wager, S. (2021). Quasi-oracle estimation of heterogeneous treatment effects. &lt;em>Biometrika&lt;/em>, 108(2), 299&amp;ndash;319.&lt;/li>
&lt;li>Knaus, M. C. (2022). Double machine learning-based programme evaluation under unconfoundedness. &lt;em>Econometrics Journal&lt;/em>, 25(3), 602&amp;ndash;627.&lt;/li>
&lt;li>Kennedy, E. H. (2023). Towards optimal doubly robust estimation of heterogeneous causal effects. &lt;em>Electronic Journal of Statistics&lt;/em>, 17(2), 3008&amp;ndash;3049.&lt;/li>
&lt;li>Sachs, J. D., &amp;amp; Warner, A. M. (1995). Natural resource abundance and economic growth. &lt;em>NBER Working Paper&lt;/em> No. 5398.&lt;/li>
&lt;li>Mehlum, H., Moene, K., &amp;amp; Torvik, R. (2006). Institutions and the resource curse. &lt;em>The Economic Journal&lt;/em>, 116(508), 1&amp;ndash;20.&lt;/li>
&lt;li>StataCorp. (2025). &lt;em>Stata 19 Treatment-Effects Reference Manual: cate&lt;/em>. College Station, TX: Stata Press.&lt;/li>
&lt;/ol></description></item></channel></rss>