Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Problem calculating elasticities using margins after fixed-effects regression.

    GOAL: To plot a semi-elasticity at different levels of another variable based on a regression with multiple fixed effects.
    PROBLEM: margins does not calculate the semi-elasticities.

    I. Preliminaries
    I am estimating the following extended gravity equation for one year:
    \[ \log{\left(\text{Trade}_{ijp} \right)} = \exp{\Bigg\{ \delta_{ik} + \delta_{jk} + \delta_{ij} + \beta_D \Big[ \log{ \left( \text{Dist}_{ij} \right) } \times \text{RS}_p \Big] + \beta_C \Big[ \mu_i \times \text{RS}_p \Big] + \beta_{CD} \Big[ \mu_i \times \log{ \left( \text{Dist}_{ij} \right) } \times \text{RS}_p \Big] \Bigg\}} \eta_{ij} \]
    where:
    • i and j index the exporter and importer, respectively;
    • p and k index products and industries, respectively (industries may produce many products, but each product belongs to only one industry);
    • The lowercase deltas represent fixed effects (exporter-industry, importer-industry and country-pair);
    • RS is a binary variable indicating if the good is "specific"; and
    • The lower case mu represents a proxy for the "quality" of contract enforcement institutions, normalized to take values from 0 (worse) to 1 (best).
    • The error term (lower case eta) is assumed independent from the regressors with conditional expected value 1.
    I ran the regression using Poisson Pseudo Maximum Likelihood (PPML), where I clustered errors by country-pair:
    Code:
    ppmlhdfe value 1.RS##c.mu##c.ldist, a(ctry_x#sector ctry_m#sector ctry_x#ctry_m) vce(cluster ctry_x#ctry_m) d
    II. Problem with margins
    I want to calculate the semi-elasticity of trade with respect to a marginal increase in the proxy for institutional quality (lower case mu) for different values of log distance. First, I saved the main percentiles of log distance in memory:
    Code:
    summarize ldist, detail
    local mean = `r(mean)'
    In my first attempt, I wrote:
    Code:
    margins, eydx(mu) at(ldist== (`r(p1)' `r(p5)' `r(p10)' `r(p25)' `r(mean)' `r(p50)' `r(p75)' `r(p90)' `r(p95)' `r(p99)') RS == 1) continuous
    Comments:
    - Since I am interested in the semi-elasticity, I use eydx.
    - Since the variable mu is continuous, I add the option continuous

    Although I did not get an error message, most estimates are "not estimable":

    Code:
    ------------------------------------------------------------------------------
                    |               Delta-method
                    |    ey/dx   std. err.   z   P>|z|   [95% conf. interval]
    -------------+----------------------------------------------------------------
    mu           |
              _at |
                 1 |          . (not estimable)
                 2 |          . (not estimable)
                 3 |          . (not estimable)
                 4 |          . (not estimable)
                 5 |          . (not estimable)
                 6 |          . (not estimable)
                 7 |          . (not estimable)
                 8 |          . (not estimable)
                 9 |          . (not estimable)
               10 |          . (not estimable)
    ------------------------------------------------------------------------------
    Based on the discussion in this post, I tried to fix this by adding noestimcheck as an option:
    Code:
    margins, eydx(mu) at(ldist== (`r(p1)' `r(p5)' `r(p10)' `r(p25)' `r(mean)' `r(p50)' `r(p75)' `r(p90)' `r(p95)' `r(p99)') RS == 1) continuous noestimcheck
    Unfortunately, this made things worse and now I get the following error message:
    Code:
    could not calculate numerical derivatives -- discontinuous region with missing values encountered
    Could anybody help me understand what am I missing? I am using Stata 18 (SE) on Windows 11.

    Thanks!

    Luis
    Last edited by Luis Espinoza; 15 Jul 2025, 14:46.

  • #2
    Not having any understanding of trade dynamics, I'm just going to make a guess here based on general principles of regression. If this variable mu is a time-invariant attribute of ctry_m, or of ctry_x, or of the pair ctry_m#ctry_x, then it is, by linear algebra, impossible to estimate mu's marginal effect (nor any elasticity or semielasticity) in a model with those absorbed effects.

    Comment


    • #3
      EDIT TO PREVIOUS POST: The dependent variable in the first equation should have been in levels. That is, it should have been:
      \[ \text{Trade}_{ijp} = \cdots \]

      Hi Clyde,

      Thank you for your response, and apologies for not being more clear in my initial post. I can think of two ways of reading your message, so let me address each one. Obviously, if your message meant something else, please help me understand it.

      I. I cannot identify mu's coefficient in the baseline regression itself, let alone its calculate marginal effects
      If I was working with aggregate bilateral trade data, the variation of mu (a time invariant attribute of ctry_x) would indeed be absorbed by the ctry_x fixed effect (FE) and, thus, I wouldn't be able to get an estimate of mu's coefficient.
      Clarification:
      1. I have bilateral trade flows by product. Thus, even when controlling for exporter-industry, importer-industry and exporter-importer fixed effects, I still can exploit the variation across products within the same country-pair and industry.
      2. I am not interested in estimating the effect of mu itself, but its additional effect on a particular type of goods ("specific" goods, which in my data are those observations with RS = 1). While I cannot estimate the coefficient of mu alone (which is always absorbed by the FEs), I can estimate the three coefficients of interest because all are associated to regressors that vary by product type.
      II. I can get estimates for the coefficients, but marginal effects cannot be calculated anyway
      Even if I can get estimates for the coefficients (which I do), I cannot calculate the marginal effect of mu because part of it is "hidden" in the FEs:
      \[ \frac{\partial E\Big[ \text{Trade}_{ijp} | \text{RS}_p = 1 \Big] }{\partial \mu_i} = \frac{\partial \delta_{ik} }{\partial \mu_i} + \frac{\partial \delta_{ij} }{\partial \mu_i} + \beta_C + \beta_{CD} \log{\text{Dist}_{ij}} \]
      Clarification: I do not want to calculate the above effect, but the following discrete difference, evaluated for different values of log Dist:
      \[ \frac{\partial E\Big[ \text{Trade}_{ijp} | \text{RS}_p = 1 \Big] }{\partial \mu_i} - \frac{\partial E\Big[ \text{Trade}_{ijp} | \text{RS}_p = 0 \Big] }{\partial \mu_i} = \beta_C + \beta_{CD} \log{\text{Dist}_{ij}} \]


      I hope this explanation makes my goal more clear. Is it possible to accomplish my goal using margins?
      Last edited by Luis Espinoza; 15 Jul 2025, 18:13.

      Comment


      • #4
        EDIT TO PREVIOUS POST: I am interested in estimating the second-order derivative:
        \[ \frac{\partial^2 \log{E\Big[ \text{Trade}_{ijp}\Big]} }{\partial \text{RS}_p \partial \mu_i} = \frac{\partial \log{E\Big[ \text{Trade}_{ijp} | \text{RS}_p = 1 \Big]} }{\partial \mu_i} - \frac{\partial \log{E\Big[ \text{Trade}_{ijp} | \text{RS}_p = 0 \Big]} }{\partial \mu_i} = \beta_C + \beta_{CD} \log{\text{Dist}_{ij}} \]

        Comment


        • #5
          ppmlhdfe is from SSC (FAQ Advice #12). If you have derived the expression correctly, then yes, you can use either margins with the -expression()- option or nlcom to calculate the derivative. Although you provide no reproducible example, here is an illustration:

          Consider the model:

          \[
          \mathbb{E}[y \mid x_1, x_2] = \mu(x_1, x_2) = \exp\left( \beta_0 + \beta_1 x_1 + \beta_2 x_1 x_2 \right)
          \]

          The partial derivative of \(\mathbb{E}[y]\) with respect to \(x_1\) is

          \[
          \frac{\partial \mu}{\partial x_1} = \frac{d}{dx_1} \left[ \exp\left( \beta_0 + \beta_1 x_1 + \beta_2 x_1 x_2 \right) \right] = \exp\left( \beta_0 + \beta_1 x_1 + \beta_2 x_1 x_2 \right) \cdot \left( \beta_1 + \beta_2 x_2 \right)
          \]

          Evaluating at Sample Means:

          Let \( \bar{x}_1 \) and \( \bar{x}_2 \) denote the sample means of \( x_1 \) and \( x_2 \), respectively. Then:

          \[
          \left. \frac{\partial \mu}{\partial x_1} \right|_{x_1 = \bar{x}_1, \, x_2 = \bar{x}_2}
          = \exp\left( \beta_0 + \beta_1 \bar{x}_1 + \beta_2 \bar{x}_1 \bar{x}_2 \right) \cdot \left( \beta_1 + \beta_2 \bar{x}_2 \right)
          \]

          Code:
          clear
          input float(id y x1 x2)
            1 2      .2488 -1.1430041
            2 1  1.3352333  1.1311661
            3 1  -.4587567 -1.4932548
            4 1   1.319296   7.923935
            5 2 -2.0332499   4.529856
            6 2   -.646085 -4.5292335
            7 1   5.043857   6.302709
            8 2   5.941895   6.645915
            9 0   3.718591  -.2793825
           10 3   5.071329   2.413525
           11 1   2.602065   7.383534
           12 4   .7288715   2.838717
           13 0    2.93099  -2.412951
           14 2   .4572504  -.7622573
           15 3 -.24726455  -5.066185
           16 2 -2.0624917   7.994617
           17 1  .04221758   3.689781
           18 3  2.0986538   3.779051
           19 3  .14305335 -1.4006286
           20 0  -.8681847   2.469832
           21 4  4.1309566   .6822363
           22 2  1.9485594  1.0957936
           23 1   7.379262   8.829028
           24 2     .07606  2.9235585
           25 5   4.741378  10.108137
           26 3    .304807   3.482954
           27 1  .11917886   4.861798
           28 3  2.0989184  1.8407828
           29 2 -1.9350915   4.587946
           30 3  2.0964124   7.992496
           31 1 -1.6835184   -.412823
           32 1 -.04724126   8.475094
           33 2   5.098127  -3.600388
           34 0  1.6679398   .8006483
           35 3 -.22119495 .025044275
           36 1  1.4548622   .4852332
           37 1  4.3716683   .8371546
           38 3   .6414328   4.800642
           39 5  -5.698874  2.7759914
           40 3   -.961277   4.419597
          end
          
          ppmlhdfe y c.x1 c.x1#c.x2, cl(id) noabsorb d(ppml1)
          foreach var in x1 x2{
              qui sum `var'
              local m`var'=r(mean) 
          }
          
          *USING MARGINS
          margins, dydx(x1) atmeans
          
          *USING EXPRESSION OPTION OF MARGINS
          margins, expression(exp(_b[_cons]+ (_b[x1]*`mx1') +(_b[c.x1#c.x2]*`mx1' *`mx2'))*(_b[x1]+(_b[c.x1#c.x2]*`mx2'))) 
          
          *USING NLCOM 
          nlcom exp(_b[_cons]+ (_b[x1]*`mx1') +(_b[c.x1#c.x2]*`mx1' *`mx2'))*(_b[x1]+(_b[c.x1#c.x2]*`mx2'))
          Res.:

          Code:
          . *USING MARGINS
          . margins, dydx(x1) atmeans
          
          Conditional marginal effects                                Number of obs = 40
          Model VCE: Robust
          
          Expression: Predicted mean of y, predict()
          dy/dx wrt:  x1
          At: x1 = 1.273711 (mean)
              x2 = 2.625667 (mean)
          
          ------------------------------------------------------------------------------
                       |            Delta-method
                       |      dy/dx   std. err.      z    P>|z|     [95% conf. interval]
          -------------+----------------------------------------------------------------
                    x1 |  -.1057673   .0964378    -1.10   0.273    -.2947819    .0832473
          ------------------------------------------------------------------------------
          
          . 
          . *USING EXPRESSION OPTION OF MARGINS
          . margins, expression(exp(_b[_cons]+ (_b[x1]*`mx1') +(_b[c.x1#c.x2]*`mx1' *`mx2'))*(_b[x1]+(_b[c.x1#c.x2]*`mx2'))) 
          warning: option expression() does not contain option predict() or xb().
          warning: prediction constant over observations.
          
          Predictive margins                                          Number of obs = 40
          Model VCE: Robust
          
          Expression: exp(_b[_cons]+ (_b[x1]*1.273710907436907) +(_b[c.x1#c.x2]*1.273710907436907
                      *2.625666642514989))*(_b[x1]+(_b[c.x1#c.x2]*2.625666642514989))
          
          ------------------------------------------------------------------------------
                       |            Delta-method
                       |     Margin   std. err.      z    P>|z|     [95% conf. interval]
          -------------+----------------------------------------------------------------
                 _cons |  -.1057673   .0964378    -1.10   0.273    -.2947819    .0832473
          ------------------------------------------------------------------------------
          
          . 
          . *USING NLCOM 
          . nlcom exp(_b[_cons]+ (_b[x1]*`mx1') +(_b[c.x1#c.x2]*`mx1' *`mx2'))*(_b[x1]+(_b[c.x1#c.x2]*`mx2'))
          
                 _nl_1: exp(_b[_cons]+ (_b[x1]*1.273710907436907) +(_b[c.x1#c.x2]*1.273710907436907 *2.625666642514989))*(_b[x1]+(_b[c.x1#c.x2]*2.
          > 625666642514989))
          
          ------------------------------------------------------------------------------
                     y | Coefficient  Std. err.      z    P>|z|     [95% conf. interval]
          -------------+----------------------------------------------------------------
                 _nl_1 |  -.1057673   .0964378    -1.10   0.273    -.2947819    .0832473
          ------------------------------------------------------------------------------

          Comment


          • #6
            Thank you for sharing this example, Andrew! I was not aware of the expression() option! I was able to solve my problem using it!

            Comment

            Working...
            X