This homework assignment will give you practice working with the basics of the multinomial logit and nested logit demand models. It is closely related to Berry (1994) but is limited in terms of consumer heterogeneity. The following homework (problem set 2) will introduce simulation-based estimators to provide much richer sources of consumer heterogeneity.

The file product_data.csv contains information on 10 different soft drinks, for 100 different markets (or time periods). This dataset contains the following variables: product_ID (the product ID), nest (a variable indicating if the product is a diet or a regular soda), price (the product’s price during period t, in USD), market_share (the market share of the product during period t), sugar (the grams of sugar contained in product \(j\) at time \(t\)), caffeine (the milligrams of caffeine contained in product \(j\) at time \(t\)), caffeine_extract_price (the price of caffeine extract paid by the firm manufacturing product \(j\) at time \(t\)), corn_syrup_price (the price of high fructose corn syrup paid by the firm manufacturing product \(j\) at time \(t\)), and \(t\) (the observation’s time period).

1(a): Multinomial Logit

Assume the indirect utility of consumer \(i\) for consuming soft drink \(j\) in period \(t\) is given by:

\[\begin{equation} u_{ijt} = \alpha p_{jt} + \beta_1 sug_{jt} + \beta_2 caf_{jt} + \gamma_d Diet_j + \gamma_r Regular_j + \xi_{jt} + \varepsilon_{ijt} \end{equation}\]

where \(p_{jt}\) denotes the price (in USD) of product \(j\) at time \(t\), \(sug_{jt}\) denote \(j\)’s sugar content (in grams) at time \(t\), \(caf_{jt}\) denotes \(j\)’s milligrams of caffeine at time \(t\), \(Diet_j\) is an indicator variable equal to 1 if \(j\) is a diet product, \(Regular_j\) is an indicator variable equal to 1 if \(j\) is a regular soda, and \(\xi_{jt}\) represents the unobserved quality of product \(j\) during time period \(t\).

Moreover, assume that \(\varepsilon_{ijt}\) are \(iid\) draws from a standard type 1 extreme value distribution. Note that the only source of heterogeneity between consumer preferences comes from the extreme value shock.

Finally, assume that there is an outside option (product 0) representing not consuming any soft drinks. The utility of the outside option is normalized such that it is mean zero:

\[\begin{equation} u_{i0t} = \varepsilon_{i0t} \end{equation}\]

Recall that given our distributional assumptions over \(\varepsilon_{ijt}\), the probability that consumer \(i\) chooses product \(j\) during time \(t\) is:

\[ s_{ijt} = \mathbb{P}(u_{ijt} > u_{ikt} \: \text{for all} \: k) = \frac{\exp(\delta_{jt})}{\sum_k \exp(\delta_k) + 1 } \]

With \(\delta_{jt} = \alpha p_{jt} + \beta_1 sug_{jt} + \beta_2 caf_{jt} + \gamma_d Diet_j + \gamma_r Regular_j + \xi_{jt}\).

Assume that \(p_{jt}\), \(sug_{jt}\), and \(caf_{jt}\) are all exogenous variables. Estimate the parameters of this model (\(\alpha\), \(\beta_1\), \(\beta_2\), \(\gamma_d\), and \(\gamma_r\)).

Solution:

Note that we can rearrange the market share equation for the outside option (product \(0\)) to get the following expression:

\[ \delta_{jt} = \log(s_{jt}) - \log(s_{0t}) \]

We can then substitute this expression into equation (3) to get:

\[ \log(s_{jt}) - \log(s_{0t}) =\alpha p_{jt} + \beta_1 sug_{jt} + \beta_2 caf_{jt} + \gamma_d Diet_j + \gamma_r Regular_j + \xi_{jt} \]

Given that this is a linear equation, and we have assumed that \(p_{jt}\), \(sug_{jt}\), \(caf_{jt}\), \(Diet_j\), and \(Regular_j\) are all exogenous, we can estimate the parameters of this model by OLS.

multinomial_logit_coeff <- function(product_data, estimation = "IV"){
  
  data <- copy(product_data)
  
  data[, outside_share :=  1 - sum(market_share), by = t]
  
  data[, delta_jt := log(market_share) - log(outside_share)]
  
  if (estimation == "IV"){
  
  coefficients <- ivreg(delta_jt ~ 0 + price + sugar + caffeine + as.factor(nest) | 0 + sugar + caffeine + as.factor(nest) + caffeine_extract_price + corn_syrup_price, data = data)
  
  } else if (estimation == "OLS"){
    
    coefficients <- lm(delta_jt ~ 0 + price + sugar + caffeine + as.factor(nest), data = data)
    
  } else {
    
    stop("estimation must be either IV or OLS")
    
  }
  
  
  return(coefficients)
  
}

OLS_result <- multinomial_logit_coeff(product_data, estimation = "OLS")

summary(OLS_result)
## 
## Call:
## lm(formula = delta_jt ~ 0 + price + sugar + caffeine + as.factor(nest), 
##     data = data)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -2.87517 -0.61320  0.02783  0.63307  2.52055 
## 
## Coefficients:
##                        Estimate Std. Error t value Pr(>|t|)    
## price                  -1.62610    0.02102  -77.35   <2e-16 ***
## sugar                   1.52806    0.04081   37.44   <2e-16 ***
## caffeine                1.44580    0.02862   50.52   <2e-16 ***
## as.factor(nest)Diet    -2.44060    0.14861  -16.42   <2e-16 ***
## as.factor(nest)Regular -6.69212    0.24541  -27.27   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.8947 on 995 degrees of freedom
## Multiple R-squared:  0.9329, Adjusted R-squared:  0.9326 
## F-statistic:  2769 on 5 and 995 DF,  p-value: < 2.2e-16

Problem 1(b)

Now assume that \(sug_{jt}\), $ caf_{jt}$, $ Diet_j$ and $ Regular_j$ are exogenous, but that \(p_{jt}\) is correlated with the unobserved quality \(\xi_{jt}\). Use caffeine_extract_price and corn_syrup_price as instruments for prices, and estimate the parameters of the model. What conditions must these two variables satisfy to be valid instruments?

Solution: If \(p_{jt}\) is correlated with the unobserved product quality \(\xi_{jt}\), the estimates we obtained in part (a) will be biased. We can therefore use the usual 2SLS IV estimator using caffeine_extract_price and corn_syrup_price as instruments for prices. In order for us to use these variables as instruments, they must satisfy the usual IV assumptions:

  1. $[z_{jt} _{jt}] = 0 $
  2. $[z_{jt} x_{jt}^{T}] : $ is full rank

Where \(z_{jt}\) is a vector with all the exogenous variables in our model and \(x_{jt}\) is a vector with \(sug_{jt}\), $ caf_{jt}$, $ Diet_j$, $ Regular_j$, and \(p_{jt}\). In our context, it implies that our instruments (input costs) must be correlated with prices, but uncorrelated with the unobserved product quality. Intuitively, input costs affect prices via higher marginal costs, but users only care about the caffeine and sugar content, not about how much the firm paid for these inputs.

#Let's simply use the function we created in part (a)

IV_result <- multinomial_logit_coeff(product_data, estimation = "IV")

summary(IV_result)
## 
## Call:
## ivreg(formula = delta_jt ~ 0 + price + sugar + caffeine + as.factor(nest) | 
##     0 + sugar + caffeine + as.factor(nest) + caffeine_extract_price + 
##         corn_syrup_price, data = data)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -3.96113 -0.57243  0.05239  0.61460  2.36528 
## 
## Coefficients:
##                        Estimate Std. Error t value Pr(>|t|)    
## price                  -1.41045    0.15057  -9.367   <2e-16 ***
## sugar                   1.42768    0.08153  17.511   <2e-16 ***
## caffeine                1.38206    0.05332  25.918   <2e-16 ***
## as.factor(nest)Diet    -2.55733    0.17585 -14.543   <2e-16 ***
## as.factor(nest)Regular -6.61816    0.26307 -25.158   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.9409 on 995 degrees of freedom
## Multiple R-Squared: 0.9258,  Adjusted R-squared: 0.9255 
## Wald test:  1439 on 5 and 995 DF,  p-value: < 2.2e-16

Problem 1(c)

Use the parameters you estimated in problem 1 (b) to derive the vector of price own-price derivatives \(\frac{\partial s_{jt}}{\partial p_{jt}}\) for all \(j\) and all \(t\). Use this vector to estimate the vector of price elasticities \(\frac{\partial s_{jt}}{\partial p_{jt}} \frac{p_{jt}}{s_{jt}}\) for all \(j\) and all \(t\).

Solution:

The own-price derivative of the choice probability for product \(j\) in period \(t\) is:

\[ \frac{\partial s_{jt}}{\partial p_{jt} }=\alpha s_{ jt}\left(1-s_{jt}\right) \]

Therefore, the own-price elasticity for product \(j\) in period \(t\) is:

\[ \alpha s_{ jt}\left(1-s_{jt}\right) \times \frac{p_{jt}}{s_{jt}} \]

price_elasticity_mult_logit <- function(product_data, alpha){
  
  data <- copy(product_data)
  
  data[, price_derivative :=  alpha * market_share * (1 - market_share)]
  
  data[, price_elasticities := price_derivative * (price / market_share)]
  
  result <- data.table(product_ID = data$product_ID, nest = data$nest, 
price_derivative = data$price_derivative, price_elasticities = 
  data$price_elasticities, t = data$t)
  
  return(result)
  
}

price_elasticity_mult_logit_vec <- price_elasticity_mult_logit(product_data = 
product_data, alpha = IV_result$coefficients[1])

price_elasticity_mult_logit_vec

Problem 1(d)

Use the parameters you estimated in problem 1 (b) to derive the vector of cross-price derivatives \(\frac{\partial s_{jt}}{\partial p_{1t}}\) for all \(j \neq 1\) and all \(t\). Use this vector to estimate the vector of cross-price elasticities \(\frac{\partial s_{jt}}{\partial p_{1t}} \frac{p_{1t}}{s_{jt}}\) for all \(j \neq 1\) and all \(t\).

Solution:

The cross-price derivatives are

\[ \frac{\partial s_{jt}}{\partial p_{1t} }=-\alpha s_{1t} s_{jt} \]

Therefore, the cross-price elasticity for product \(j\) with respect to product \(1\) in period \(t\) is:

\[ -\alpha s_{1t} s_{jt} \times \frac{p_{1t}}{s_{jt}} \]

cross_price_elasticity_mult_logit <- function(product_data, alpha, product){
  
  data <- copy(product_data)
  
  selected_product <- data[product_ID == product]
  
  selected_product <- data.table(product_k_ID = selected_product$product_ID, 
price_k = selected_product$price, share_k = selected_product$market_share, 
t = selected_product$t)
  
  data <- merge(data, selected_product, by = "t")
  
  data[, cross_price_derivative := - alpha * market_share * share_k]
  
  data[, cross_price_elasticities := cross_price_derivative * (price_k / market_share)]
  
  data <- data[product_ID != product]
  
  result <- data.table(product_ID = data$product_ID, nest = data$nest,
cross_price_derivative = data$cross_price_derivative, 
cross_price_elasticities = data$cross_price_elasticities, t = data$t)
  
  return(result)
}

cross_price_elasticity_mult_logit_vec <- cross_price_elasticity_mult_logit(product_data =
product_data, alpha = IV_result$coefficients[1], product = 1)

cross_price_elasticity_mult_logit_vec

Problem 1(e)

Write a function that generates the Jacobian matrix of price derivatives \(\Delta(p)\) (i.e., \(\Delta_{ij} = \frac{\partial s_j}{p_i}\)) for a given period. Your function should take the time period, product variables, and model parameters as arguments, and return the Jacobian matrix. Print the Jacobian for the last time period in the sample (t = 100).

build_jacobian_matrix_mult_logit <- function(product_variables, alpha, time_period){
  
  dd <- copy(product_variables)
  dd <- dd[t == time_period]
  dd <- dd[order(nest, product_ID)]
  
  dd[, self_derivative := alpha * market_share * (1 - market_share)]
  
  Jacobian_matrix <- dd[, outer(market_share, -alpha * market_share, "*")]
  
  diag(Jacobian_matrix) <- dd[, self_derivative]
  
  Jacobian_matrix <- as.data.table(Jacobian_matrix)
  
  return(Jacobian_matrix)
  
}

Jacobian_mult <- build_jacobian_matrix_mult_logit(product_variables = product_data, alpha = IV_result$coefficients[1], time_period = 100)

Jacobian_mult

2(a): Nested Logit

Now suppose that there are two sources of consumer heterogeneity (1) an extreme value shock as in problem 1 and (2) a preference for diet soda. Let products \(0,1,2,...,20\) be grouped into three mutually exclusive sets: \(\mathcal{J}_D\) (for diet products), \(\mathcal{J}_R\) (for regular products), and \(\mathcal{J}_0\) (for the outside option). For product \(j \in \mathcal{J}_g\) during time \(t\), let consumer \(i\) derive utility equal to:

\[\begin{equation} u_{ijt} = \alpha p_{jt} + \beta_1 sug_{jt} + \beta_2 caf_{jt} + \gamma_d Diet_j + \gamma_r Regular_j + \xi_{jt} + \varsigma_{igt} + (1 - \sigma) \times \varepsilon_{ijt} \end{equation}\]

Where \(\varepsilon_{ijt}\) is again distributed type 1 extreme value, and \(\varsigma_{igt}\) follows a distribution such that \(\varsigma_{igt} + (1 - \sigma) \times \varepsilon_{ijt}\) is also an extreme value random variable. The parameter \(\sigma\) represents the degree of correlation between the error terms of products in the same nest and satisfies \(0 \leq \sigma < 1\).

Given our distributional assumptions, the inside share of good \(j\) belonging to group \(g\) at time \(t\) is given by:

\[\begin{equation} s_{jt|g} = \frac{ \exp(\frac{\delta_{jt}}{1 - \sigma}) }{ \sum_{k \in \mathcal{J}_g } \exp(\frac{\delta_{kt}}{1 - \sigma})} \end{equation}\]

with \(\delta_{jt} = \alpha p_{jt} + \beta_1 sug_{jt} + \beta_2 caf_{jt} + \gamma_d Diet_j + \gamma_r Regular_j + \xi_{jt}\)

The probability that a product from group \(g\) is chosen is

\[\begin{equation} s_g = \frac{D_{g}^{(1 - \sigma)}}{\sum_g D_{g}^{(1 - \sigma)}} \end{equation}\]

with \(D_g = \sum_{k \in \mathcal{J}_g } \exp(\frac{\delta_{kt}}{1 - \sigma})\)

Therefore, product \(j\)’s share at time \(t\) is

\[\begin{equation} s_{jt} = s_{jt|g} \times s_g \end{equation}\]

Estimate the parameters of the model (\(\alpha\), \(\beta_1\), \(\beta_2\), \(\gamma_d\), and \(\gamma_r\), and \(\sigma\)), assuming that \(p_{jt}\) is correlated with the unobserved quality \(\xi_{jt}\).

Solution:

We can invert the demand system to get the following linear expression:

\[ \log \left(s_{j t}\right)- \log \left(s_{0 t}\right)= \alpha \times p_{jt} + \beta_1 sug_{jt} + \beta_2 caf_{jt} + \gamma_d Diet_j + \gamma_r Regular_j + \sigma \log \left(s_{jt| g}\right)+\xi_{j t} \]

As before, we can use the prices of caffeine and corn syrup as instruments for prices. However, note that \(s_{jt| g}\) is also endogenous, so we need instruments for the inside share as well. Given our assumptions that \(sug_{jt}\) and \(caf_{jt}\) are exogenous, we can use the average \(sug_{jt}\) and \(caf_{jt}\) of competing products inside the same nest to instrument for \(s_{jt| g}\), then estimate \(\alpha\), \(\beta_1\), \(\beta_2\), and \(\sigma\) by 2SLS IV.

nested_logit_coeff <- function(product_data){
  
  data <- copy(product_data)
  
  data[, outside_share :=  1 - sum(market_share), by = t]
  
  data[, delta_jt := log(market_share) - log(outside_share)]
  
  data[, nest_share := sum(market_share), by = c("t", "nest") ]
  
  data[, inside_share := market_share / nest_share]
  
  data[, `:=`(sum_sugar = sum(sugar),
                      count = .N, 
                      adj_sum = sum(sugar) - sugar,
                      adj_count = .N - 1), 
               by = .(t, nest)]
  
  data[, `:=`(competitors_sugar = adj_sum / adj_count,
                      sum_sugar = NULL, 
                      count = NULL,
                      adj_sum = NULL, 
                      adj_count = NULL)]
  
  data[, `:=`(sum_caffeine = sum(caffeine),
                      count = .N, 
                      adj_sum = sum(caffeine) - caffeine,
                      adj_count = .N - 1), 
               by = .(t, nest)]
  
  data[, `:=`(competitors_caffeine = adj_sum / adj_count,
                      sum_caffeine = NULL, 
                      count = NULL,
                      adj_sum = NULL, 
                      adj_count = NULL)]
  
  setorder(data, t , product_ID)
  
  coefficients <- ivreg(delta_jt ~ 0 + price + sugar + caffeine + log(inside_share) + as.factor(nest) | 
  0 + sugar + caffeine + as.factor(nest) + caffeine_extract_price + corn_syrup_price + competitors_sugar + competitors_caffeine, data = data)
  
  xi <- coefficients$residuals 
  
  xi_hat <- data.table(product_ID = data$product_ID, xi = xi, t = data$t)
  
  return(list(coefficients = coefficients, xi_hat = xi_hat))
  
}

Nested_logit_result <- nested_logit_coeff(product_data = product_data)

Nested_logit_coefficients <- Nested_logit_result$coefficients

summary(Nested_logit_coefficients)
## 
## Call:
## ivreg(formula = delta_jt ~ 0 + price + sugar + caffeine + log(inside_share) + 
##     as.factor(nest) | 0 + sugar + caffeine + as.factor(nest) + 
##     caffeine_extract_price + corn_syrup_price + competitors_sugar + 
##     competitors_caffeine, data = data)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.76788 -0.17042 -0.01056  0.17251  0.78072 
## 
## Coefficients:
##                        Estimate Std. Error t value Pr(>|t|)    
## price                  -0.52250    0.03961 -13.191  < 2e-16 ***
## sugar                   0.51846    0.02638  19.655  < 2e-16 ***
## caffeine                0.52071    0.02156  24.152  < 2e-16 ***
## log(inside_share)       0.68313    0.01578  43.299  < 2e-16 ***
## as.factor(nest)Diet     1.89879    0.11943  15.899  < 2e-16 ***
## as.factor(nest)Regular  0.85429    0.18350   4.656 3.67e-06 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.2606 on 994 degrees of freedom
## Multiple R-Squared: 0.9943,  Adjusted R-squared: 0.9943 
## Wald test: 1.584e+04 on 6 and 994 DF,  p-value: < 2.2e-16

Problem 2(b)

Use the parameters you estimated in problem 2 (a) to derive the vector of price self-derivatives \(\frac{\partial s_{jt}}{\partial p_{jt}}\) for all \(j\) and all \(t\). Use this vector to estimate the vector of price elasticities \(\frac{\partial s_{jt}}{\partial p_{jt}} \frac{p_{jt}}{s_{jt}}\) for all \(j\) and all \(t\).

Solution:

The derivative of product \(j\)’s share, for \(j \in \mathcal{J}_g\), with respect to its own price is given by

\[ \frac{\partial s_{jt}}{\partial p_{jt}} = \frac{\partial \delta_{jt}}{\partial p_{jt}} \times \frac{\partial s_{jt} }{\partial \delta_{jt} }=\frac{\alpha}{1-\sigma} s_{jt} \left(1-\sigma s_{jt | g}-(1-\sigma) s_{jt} \right) \]

The own price elasticity of product \(j\) in group \(g\) is therefore given by

\[ \frac{\alpha}{1-\sigma} s_{jt} \left(1-\sigma s_{jt | g}-(1-\sigma) s_{jt} \right) \times \frac{p_{jt}}{s_{jt}} \]

price_elasticity_nested_logit <- function(product_data, alpha , sigma){
  
  data <- copy(product_data)
  
  data[, nest_share := sum(market_share), by = c("t", "nest") ]
  
  data[, inside_share := market_share / nest_share]
  
  data[, price_derivative :=  
  ( (alpha / (1 - sigma)) * market_share * (1 - sigma * inside_share - 
  (1 - sigma) * market_share) )]
  
  data[, price_elasticities := price_derivative * (price / market_share)]
  
  result <- data.table(product_ID = data$product_ID, nest = data$nest, 
  price_derivative = data$price_derivative, price_elasticities = 
  data$price_elasticities, t = data$t)
  
  return(result)
  
}

own_price_elasticity_nested_logit <- price_elasticity_nested_logit(product_data = 
product_data, alpha = Nested_logit_coefficients$coefficients[1], sigma =
Nested_logit_coefficients$coefficients[4])

own_price_elasticity_nested_logit

Problem 2(c)

Use the parameters you estimated in problem 2 (a) to derive the vector of cross-price derivatives \(\frac{\partial s_{jt}}{\partial p_{1t}}\) for all \(j \neq 1\) and all \(t\). Use this vector to estimate the vector of cross-price elasticities \(\frac{\partial s_{jt}}{\partial p_{1t}} \frac{p_{1t}}{s_{jt}}\) for all \(j \neq 1\) and all \(t\).

Solution:

The derivative of product \(j\) ’s share with respect to product \(k\) ’s price, for \(j\) and \(k\) both in group \(g\), equals

\[ \frac{\partial s_{jt}}{\partial p_{kt}} = \frac{\partial \delta_{kt}}{\partial p_{kt}} \times \frac{\partial s_{jt} }{\partial \delta_{kt} }=-\alpha s_{kt} \left(s_{jt} +\frac{\sigma}{1-\sigma} s_{jt|g}\right) \]

The cross-price elasticity is therefore given by

\[ -\alpha s_{kt} \left(s_{jt} +\frac{\sigma}{1-\sigma} s_{jt|g}\right) \times \frac{p_{kt}}{s_{jt}} \]

The derivative of product \(j\) ’s share with respect to product \(k\) ’s mean valuation, for \(j\) and \(k\) in different groups, equals \[ \frac{\partial s_{jt}}{\partial p_{kt}} = \frac{\partial \delta_{kt}}{\partial p_{kt}} \times \frac{\partial s_{jt} }{\partial \delta_{kt} } = -\alpha s_{jt} s_{kt} \]

The cross-price elasticity is therefore given by

\[ -\alpha s_{jt} s_{kt} \times \frac{p_{kt}}{s_{jt}} \]

cross_price_elasticity_nested_logit <- function(product_data, alpha, sigma, product){
  
  data <- copy(product_data)
  
  data[, nest_share := sum(market_share), by = c("t", "nest") ]
  data[, inside_share := market_share / nest_share]
  
  selected_product <- data[product_ID == product]
  
  selected_product <- data.table(
product_k_ID = selected_product$product_ID, 
nest_k = selected_product$nest, price_k = selected_product$price, 
share_k = selected_product$market_share, t = selected_product$t)
  
  data <- merge(data, selected_product, by = "t")
  
  data[, cross_price_derivative := ifelse(nest == nest_k, 
  - alpha * share_k * (market_share + (sigma/(1 - sigma))*inside_share), 
   -alpha * market_share * share_k )]
  
  data[, cross_price_elasticities := cross_price_derivative * (price_k / market_share)]
  
  data <- data[product_ID != product]
  
  result <- data.table(
product_ID = data$product_ID, nest = data$nest,
cross_price_derivative = data$cross_price_derivative, 
cross_price_elasticities = data$cross_price_elasticities, 
t = data$t)
  
  return(result)
}

cross_price_elasticity_nested_logit_vec <- cross_price_elasticity_nested_logit(
product_data = product_data, alpha = Nested_logit_coefficients$coefficients[1], 
sigma = Nested_logit_coefficients$coefficients[4], product = 1)

cross_price_elasticity_nested_logit_vec

Problem 2(d)

How do the results you obtained from parts 2 (a), 2 (b), and 2 (c) compare to the ones from parts 1 (b), 1 (c), and 1(d)?

Solution:

Note that given the assumptions of Multinomial Logit, the cross-price elasticity of all products with respect to product 1 is constant (see problem 1(d)). To see why, let’s go back to the expression for \(\frac{\partial s_{jt}}{\partial p_{kt} }\). Note that this expression implies that the share of consumers who switch from product \(k\) to product \(j\) only depends on the market shares of products \(j\) and \(k\). For instance, suppose that \(k\) is a diet soda. If \(j\) and \(l\) are a diet and a regular soda with the same market share, this implies that a consumer is equally likely to switch from product \(k\) to products \(j\) and \(l\), even though we would expect a consumer of diet products to be more likely to switch to another diet product.

In contrast, under a nested logit specification, the cross-price elasticity with respect to product \(k\) of all products in the same nest as product \(k\) will be higher than the cross-price elasticity for products in other groups. Therefore, consumers who choose a diet soda are now more likely to substitute to another soda in the same nest (diet), compared to a regular soda. Note, however, that the elasticity is still constant within each group.

Problem 2(e)

Write a function that generates the Jacobian matrix of price derivatives \(\Delta(p)\) (i.e., \(\Delta_{ij} = \frac{\partial s_j}{p_i}\)) for a given period, under the nested logit specification. Your function should take the time period, product variables, and model parameters as arguments, and return the Jacobian matrix. Print the Jacobian for the last time period in the sample (t = 100).

build_jacobian_matrix_nested_logit <- function(product_variables, alpha, sigma, time_period){

  
  dd <- copy(product_variables)
  dd <- dd[t == time_period]
  dd <- dd[order(nest, product_ID)]
  
  dd[, nest_share := sum(market_share), by = c("t", "nest") ]
  dd[, inside_share := market_share / nest_share]
  
  dd[, same_nest := (market_share + (sigma / (1 - sigma)) * inside_share )]
  dd[, self_derivative := alpha / (1 - sigma) * market_share * (1 - sigma * inside_share - (1 - sigma) * market_share)]
  
  Jacobian_part_same_nest <- dd[, outer(same_nest, -alpha * market_share, "*")]
  Jacobian_par_diff_nest <- dd[, outer(market_share, -alpha * market_share, "*")]
  
  Jacobian_matrix <- Jacobian_part_same_nest
  Jacobian_matrix[6:10,1:5] <- Jacobian_par_diff_nest[6:10,1:5]
  Jacobian_matrix[1:5,6:10] <- Jacobian_par_diff_nest[1:5,6:10]
  diag(Jacobian_matrix) <- dd[, self_derivative]
  
  return(Jacobian_matrix)
  
}



Jacobian_nested <- build_jacobian_matrix_nested_logit(product_variables = product_data, time_period = 100, alpha = Nested_logit_coefficients$coefficients[1], sigma = Nested_logit_coefficients$coefficients[4])
  
Jacobian_nested
##                [,1]          [,2]          [,3]          [,4]         [,5]
##  [1,] -0.0885689105  3.356217e-04  2.466358e-03  0.0049083352  0.059147049
##  [2,]  0.0003356217 -2.283637e-03  5.445228e-05  0.0001083663  0.001305849
##  [3,]  0.0024663581  5.445228e-05 -1.643590e-02  0.0007963432  0.009596197
##  [4,]  0.0049083352  1.083663e-04  7.963432e-04 -0.0319208495  0.019097532
##  [5,]  0.0591470490  1.305849e-03  9.596197e-03  0.0190975319 -0.173622714
##  [6,]  0.0012854646  2.838050e-05  2.085577e-04  0.0004150537  0.005001533
##  [7,]  0.0146215539  3.228148e-04  2.372245e-03  0.0047210401  0.056890082
##  [8,]  0.0031641791  6.985878e-05  5.133660e-04  0.0010216572  0.012311305
##  [9,]  0.0013403545  2.959236e-05  2.174632e-04  0.0004327767  0.005215101
## [10,]  0.0011881255  2.623145e-05  1.927651e-04  0.0003836246  0.004622803
##                [,6]          [,7]          [,8]          [,9]         [,10]
##  [1,]  0.0012854646  0.0146215539  3.164179e-03  1.340354e-03  1.188126e-03
##  [2,]  0.0000283805  0.0003228148  6.985878e-05  2.959236e-05  2.623145e-05
##  [3,]  0.0002085577  0.0023722453  5.133660e-04  2.174632e-04  1.927651e-04
##  [4,]  0.0004150537  0.0047210401  1.021657e-03  4.327767e-04  3.836246e-04
##  [5,]  0.0050015331  0.0568900816  1.231130e-02  5.215101e-03  4.622803e-03
##  [6,] -0.0610456608  0.0388943185  8.416930e-03  3.565433e-03  3.160494e-03
##  [7,]  0.0388943185 -0.2908553981  9.573861e-02  4.055512e-02  3.594913e-02
##  [8,]  0.0084169295  0.0957386071 -1.379629e-01  8.776336e-03  7.779575e-03
##  [9,]  0.0035654332  0.0405551223  8.776336e-03 -6.350009e-02  3.295448e-03
## [10,]  0.0031604939  0.0359491289  7.779575e-03  3.295448e-03 -5.666243e-02

Problem 3(a)

Assume that the supply side is a single-product Bertrand Nash Equilibrium (each firm owns only one product). That is, firm \(f\) owning product \(j\) solves the following problem in period \(t\) to set prices:

\[ \max_{p_{jt}} \Pi_{ft} = p_{jt} q_{jt} - c_{jt} q_{jt} \]

Where \(c_{jt}\) denotes product \(j\)’s marginal cost, and \(q_{jt} = s_{jt} \bar{M}\). \(\bar{M} = 10,000\) is the number of consumers in this market. Use the firms’ FOCs to estimate the marginal cost for all \(j\) and all \(t\).

Solution:

The FOC for firm \(f\) owning product \(j\) is given by:

\[ \frac{\partial \Pi_{ft}}{\partial p_{jt}} = s_{jt} + (p_{jt} - c_{jt})\times \frac{\partial s_{jt}}{\partial p_{jt}} = 0 \]

We can solve for \(c_{jt}\) to get:

\[ c_{jt} = s_{jt} \times \Big (\frac{\partial s_{jt}}{\partial p_{jt}} \Big)^{-1} + p_{jt} \]

get_marginal_cost <- function(product_data, alpha, sigma){
  
  price_elasticities <- price_elasticity_nested_logit(product_data = product_data,
                        alpha = alpha, sigma = sigma)
  
  dd <- merge(product_data, price_elasticities, by = c("product_ID", "nest", "t"))
  
  dd[, marginal_cost := (market_share + price * price_derivative) * (1 / price_derivative) ]
 
  result <- data.table(product_ID = dd$product_ID, marginal_cost = dd$marginal_cost, t = dd$t)
  
  return(result)
   
}

marginal_cost <- get_marginal_cost(product_data = product_data, 
alpha = Nested_logit_coefficients$coefficients[1], 
sigma = Nested_logit_coefficients$coefficients[4])

marginal_cost

Problem 3(b)

Now assume that the firms who own products 1 and 2 merge at \(t = 100\), so that a single firm now owns both products. Simulate how the prices of all firms would change in this scenario.

Solution:

The FOCs for firm \(1\) are now given by:

\[ \frac{\partial \Pi_{1t}}{\partial p_{1t}} = s_{1t} + (p_{1t} - c_{1t})\times \frac{\partial s_{1t}}{\partial p_{1t}} + (p_{2t} - c_{2t}) \times \frac{\partial s_{2t}}{\partial p_{1t}} = 0 \]

\[ \frac{\partial \Pi_{1t}}{\partial p_{2t}} = s_{2t} + (p_{2t} - c_{2t})\times \frac{\partial s_{2t}}{\partial p_{2t}} + (p_{1t} - c_{1t}) \times \frac{\partial s_{1t}}{\partial p_{2t}} = 0 \]

The FOCs for firms \(f = 3,...,10\) owning products \(j = 3,,..,10\) are given by:

\[ \frac{\partial \Pi_{ft}}{\partial p_{jt}} = s_{jt} + (p_{jt} - c_{jt})\times \frac{\partial s_{jt}}{\partial p_{jt}} = 0 \]

This gives us a system with 10 equations (one for each product) and 10 unknowns (\(p_{jt}\) for \(j = 1,2,..,10\)).

Note that each product’s share \(s_{jt}\) is a function of the vector of prices \(\mathbf{p}_t\), the vectors of characteristics of all products (\(sug_{jt}\), \(caf_{jt}\), \(Diet_j\), \(Regular_j\)), and of the unobserved product quality \(\boldsymbol{\xi}_t\). We can estimate \(\boldsymbol{\xi}_t\) as follows:

\[ \hat{\xi}_{jt} = \delta_{jt} - \hat{\alpha} p_{jt} - \hat{\beta}_1 sug_{jt} - \hat{\beta}_2 caf_{jt} - \hat{\gamma_d} Diet_j - \hat{\gamma_r} Regular_j \]

We then solve for the vector of prices that solves the system of equations to get the simulated vector of prices.

Alternatively, we may write the FOCs in matrix notation as:

\[ \mathbf{s}_t(\mathbf{p}_t) + (\Omega \circ \Delta(\mathbf{p}_t))(\mathbf{p}_t - \mathbf{c}_t) = 0 \]

Where \(\mathbf{s}_t\) represents the vector of shares for all firms, \(\mathbf{p}_t\) the vector of prices of all firms, \(\Omega\) is an ownership matrix with element \(ij\) equal to one if product \(i\) and \(j\) are owned by the same firm, \(\Delta(p_t)\) is the Jacobian matrix derived in part 2(e), \(\circ\) denotes the Hadamard product, and \(\mathbf{c}_t\) is the vector of marginal costs of all firms.

model_parameters <- list(alpha = Nested_logit_coefficients$coefficients[1], 
beta_1 = Nested_logit_coefficients$coefficients[2], beta_2 = 
Nested_logit_coefficients$coefficients[3], sigma = Nested_logit_coefficients$coefficients[4], gamma_d = Nested_logit_coefficients$coefficients[5], gamma_r = Nested_logit_coefficients$coefficients[6])

#We get the estimated xi_{jt} from the function we used for part 2(a)
xi_hat <- Nested_logit_result$xi_hat

firm_primitives <- data.table(product_ID = product_data$product_ID, 
nest = product_data$nest, sugar = product_data$sugar, caffeine =
product_data$caffeine, t = product_data$t)

firm_primitives <- merge(firm_primitives, xi_hat, by = c("product_ID", "t"))

#firm_primitives contains the product_ID, nest, marginal cost, sweetness, healthiness,
# and unobserved product quality xi_{jt} of all products. 
firm_primitives <- merge(firm_primitives, marginal_cost, by = c("product_ID", "t"))

#We will use the original prices as initial value for the solver
initial_prices <- product_data[t == 100][order(product_ID)]$price 

ownership_matrix <- diag(10)
ownership_matrix[1,2] <- 1
ownership_matrix[2,1] <- 1

merger_sim_mat <- function(model_parameters, firm_primitives, ownership_matrix, initial_guess){
  
  alpha <- model_parameters$alpha
  beta_1 <- model_parameters$beta_1
  beta_2 <- model_parameters$beta_2
  gamma_d <- model_parameters$gamma_d
  gamma_r <- model_parameters$gamma_r
  sigma <- model_parameters$sigma
  
  dd <- firm_primitives[t == 100][order(product_ID)]
  
  FOCs <- function(par){
    dd[, diet := ifelse(nest == "Diet", 1, 0)]
    dd[, regular := ifelse(nest == "Regular", 1, 0)]
    dd[, price := par]
    dd[, delta := alpha * price + beta_1 * sugar + beta_2 * caffeine + gamma_d * diet + gamma_r * regular + xi]
    dd[, D_g := sum( exp(delta / (1 - sigma) ) ), by = nest]
    dd[, inside_share := exp(delta / (1 - sigma)) / D_g]
    dd[, group_share := D_g^(1 - sigma) / (D_g[1]^(1-sigma) + D_g[nrow(dd)]^(1-sigma) + 1)]
    dd[, market_share := inside_share * group_share]
    
    Jacobian <- build_jacobian_matrix_nested_logit(product_variables = dd, alpha = alpha, sigma = sigma, time_period = 100)
    
    dd[, FOCs := market_share + (ownership_matrix * Jacobian) %*% (price - marginal_cost)]
    
    return(dd[, FOCs ])
    
  }
  
  #Find W_ft that solve the problem
  res = nleqslv(x = initial_guess, fn = FOCs,
                method = c("Broyden"), global = c("cline"), control = list(allowSingular=TRUE, ftol = 1e-10))
  
  result <- data.table(product_ID = dd$product_ID, nest = dd$nest, price = res$x)
  
  return(result)
  
}


merger_prices <- merger_sim_mat(model_parameters = model_parameters, 
firm_primitives = firm_primitives, initial_guess = initial_prices, ownership_matrix = ownership_matrix)
  
merger_prices

Problem 3(c)

How does the average price of the products from the merging firms change after the merger? How does the average price of competing products in the same nest change after the merger? How does the average price for competing products in a different nest change after the merger?

Solution:

original_prices <- data.table(product_ID = 
product_data[t == 100]$product_ID, original_price = 
product_data[t == 100]$price)

merger_prices <- merge(merger_prices, original_prices, by = "product_ID")

merging_firms_diff <- merger_prices[product_ID <=2][, 
mean(price - original_price)]

competitors_same_nest_diff <- merger_prices[product_ID > 2 & nest == "Diet"][, 
mean(price - original_price)]

competitors_other_nest_diff <- merger_prices[product_ID > 2 & nest == "Regular"][,
mean(price - original_price)]

result <- data.table(Group = c("Merging products", "Competitors in same nest",
"Competitors in a different nest"), Avg_Change = c(merging_firms_diff, 
competitors_same_nest_diff, competitors_other_nest_diff))

result

Problem 3(d)

Now instead assume that all firms collude during the last period (t = 100) and choose the prices that maximize the sum of all profits. Simulate how the prices of all firms would change in this scenario.

Solution:

Note that since firms maximize the sum of all firms’ profits, the equilibrium solution will be equivalent to the one we would have under a hypothetical merger between all firms. Therefore, all we have to do is replace the ownership matrix with a \(10 \times 10\) matrix with all elements equal to \(1\), and we can use the same function we used in part 3(b).

collusion_matrix <- matrix(1, nrow = 10, ncol = 10)

collusion_prices <- merger_sim_mat(model_parameters = model_parameters, 
firm_primitives = firm_primitives, initial_guess = initial_prices, ownership_matrix = collusion_matrix)
  
collusion_prices