The BLP Method of Demand Curve Estimation¶
Author:
Conghan Zheng
Last updated:
17 MAR 2023
Compiled with
: Python 3.9.6
In this example, we perform structural demand estimation using the algorithm described in Berry, Levinsohn & Pakes (1995).
Model¶
Suppose there are M markets indexed by $m = 1,\dots, M$, and let $J_m$ be the number of options available to each consumer in market $m$. Following the exposition by Nevo (2000), the (indirect) choice-specific utility that consumer $i$ in market $m$ obtains from product $j$ (with $j=0$ representing the "no-purchase" option, that is, the outside good) is given by:
\begin{align*} \tilde{u}_{ijm} = \underbrace{x_{jm} \beta_i + \alpha_i (y_i - p_{jm})}_{\substack{\text{deterministic component}}} + \underbrace{\xi_{jm} + \varepsilon_{ijm}}_{\text{random component}} \end{align*}
where:
- $y_i$ is the income of consumer $i$.
- $p_{jm}$ is the price of product $j$.
- $x_{jm}$ is a $k$-dimensional vector of observed non-price attributes of product $j$ in market $m$.
- $\alpha_i$ is consumer $i$'s marginal utility from income.
- $\beta_i$ is the vector of tastes of consumer $i$, with $k$ dimensions.
- $\xi_{jm}$ is the unobserved (by the econometrician) attributes of product $j$ in market $m$.
- $\varepsilon_{ijm}$ is a mean-zero stochastic term.
Note that the utility from income, $\alpha_i y_i$, plays no part in the consumer's choice, so actually we can just drop it out, or transform price $p_{jm}$ to $\frac{p_{jm}}{y_i}$. From now on we consider the following monotonic transformation of the original utility specification: \begin{align} u_{ijm} = \underbrace{x_{jm} \beta_i - \alpha_i p_{jm} }_{ \equiv V_{ijm}} + \xi_{jm} + \varepsilon_{ijm} \label{eq:main} \tag{1} \end{align}
Empirical Strategy¶
The Endogeneity of Price¶
The key issue that motivates the BLP estimation approach is the endogeneity of price. The price of each product depends on all its attributes. Some attributes are observed by the producer but not measured by the researcher and are included in $\xi$, yet they affect the demand and/or the costs for the product. Therefore, price $p_{jm}$ depends on $\xi_{jm}$.
The BLP approach to this problem is to move $\xi_{jm}$ to the observed portion of utility. We separate the deterministic component $V_{ijm}$ into two parts: $\bar{V}_{jm}$, the portion that varies over products and markets but not consumers, and $\tilde{V}_{ijm}$, the portion that varies over consumers as well as markets and products. Thus, we can write: \begin{align} \eqref{eq:main}: \quad u_{ijm} &= V_{ijm} + \xi_{jm} + \varepsilon_{ijm} \nonumber \\ &\equiv \bar{V}_{jm} + \tilde{V}_{ijm} + \xi_{jm} + \varepsilon_{ijm} \nonumber \\ &= \underbrace{\bar{V}_{jm} + \xi_{jm}}_{\equiv \delta_{jm}} +\tilde{V}_{ijm} + \varepsilon_{ijm} \nonumber \\ &\equiv \delta_{jm} + \tilde{V}_{ijm} + \varepsilon_{ijm} \label{eq:step1} \tag{2} \end{align} where $\delta_{jm}$ is constant for each product in each market. A choice model based on this utility specification does not entail any endogeneity, a constant included for each market-product level absorbs $x_{jm}$.
One difficulty in decomposing $V_{ijm}$ into $\bar{V}_{jm}$ and $\tilde{V}_{ijm}$ is that all terms in the indirect utility \eqref{eq:main} except for $\xi_{jm}$ has a subscript $i$ (think about $\alpha_i p_{jm}$, $x_{jm} \beta_i$, and $\varepsilon_{ijm}$). To describe how consumer preferences vary as a function of the individual characteristics, we model the distribution of consumer taste parameters $\alpha_i$ and $\beta_i$. \begin{align} (\alpha_i,\beta_i)' &= (\alpha,\beta)' + \Pi \cdot \eta_i + \Sigma \cdot \nu_i , \quad \theta \equiv (\Pi, \Sigma) \label{eq:rpl} \tag{3} \end{align} where $\alpha$ and $\beta$ are the average levels of the two parameters, $\eta_i$ and $\nu_i$ are the individual-varying part, and the second equality depends on $\Sigma$ being diagonal. According to Nevo (2000), given that no individual data is observed, the individual characteristics consist of two components: the demographics $\eta_i$ which is referred to as observed, and additional characteristics $\nu_i$ which is referred to as unobserved.
Even though we do not observe individual data, demographic variables $\eta_i$ is still considered as "observed". We may not know the individual income of each agent, but we may know some feature of the income distribution. And finally we might have a sample from the joint distribution of several demographic variables (e.g., income, age, family size, race, and education, etc. from Census data).
The additional characteristics $\nu_i$ might include things like whether the individual owns a dog, which could be very important in the decision of which car to buy (suppose we are considering the automobile markets as in the BLP paper), but are unlikely to be collected by any data project.
Using \eqref{eq:step1} and \eqref{eq:rpl}, we can rewrite the original model \eqref{eq:main} as \begin{align} u_{ijm} &= \delta_{jm} + \tilde{V}_{ijm}(\theta) + \varepsilon_{ijm} \nonumber \\ &= \delta_{jm} + (x_{jm},p_{jm}) \cdot (\Pi \eta_i + \Sigma \nu_i) + \varepsilon_{ijm} \label{eq:step1_ex} \tag{4}\\ \delta_{jm} &= \bar{V}_{jm}(\alpha,\beta) + \xi_{jm} \nonumber \\ &= x_{jm} \beta - \alpha p_{jm} + \xi_{jm} \label{eq:delta} \tag{5} \end{align} $(\alpha,\beta)$ and $\theta$ are all the parameters of the model, usually vector $(\alpha, \beta)$ is called the linear parameters, and vector $\theta$ is called the nonlinear parameters (the reasons for the names will be discussed below).
Model \eqref{eq:step1_ex} and \eqref{eq:delta} tells us that $(\alpha,\beta)$ (the linear parameters) and $\theta$ (the nonlinear parameters) are all the parameters we need to estimate in this model.
The Outer Loop¶
We proceed with the estimation of the choice model with utility specification \eqref{eq:step1_ex}. Recall from last semester's Microeconometrics the additive random utility interpretation of MNL and CL ($U_{j} = x_j \beta + \varepsilon_j$). We get a similar form in the current case, only the parameters $(\eta_i, \nu_i)$ have randomness. A multi-choice logit model where the parameter $\beta$ in the deterministic component are allowed to be random is called a Random Parameters Logit (RPL, also called a Mixed Logit). RPL model is suitable to model the aggregation over heterogeneous consumers (in our context, random coefficients actually means individual coefficients).
Given that the unobservables $\{\varepsilon_{ijm}\}$ are independent and type I extreme value distributed, the individual choice probability is \begin{align} S_{ijm} &= \mathbf{P}(u_{ijm} \geq u_{ikm}, \forall k = 1,\dots,M) \nonumber \\ &= \mathbf{P}\bigg(\varepsilon_{ijm} - \varepsilon_{ikm} \leq \left(\delta_{jm} +\tilde{V}_{ijm}(\theta)\right) - \left( \delta_{km} + \tilde{V}_{ikm}(\theta) \right), \forall k = 1,\dots,M \bigg) \nonumber \\ &= \int_{\varepsilon_{ijm}: \, u_{ijm} \geq u_{ikm}, \forall k} \mathrm{d} F(\varepsilon_{ijm}) \nonumber \\ &= \frac{e^{\delta_{jm} + \tilde{V}_{ijm}(\theta)}}{\sum_l e^{\delta_{lm} + \tilde{V}_{ijm}(\theta)}} \label{emax} \tag{6} \end{align} We can integrate out the randomness (in our context, "individualness") from $\eta_i$ and $\nu_i$ analytically, and get the market share of product $j$ in market $m$: \begin{align} S_{jm} &\overset{\eqref{eq:rpl}}{=} \int_{\nu_i} \int_{\eta_i} S_{ijm} \mathrm{d} F(\eta_i, \nu_i \vert \theta) \nonumber \\ &= \int_{\nu_i} \int_{\eta_i} \frac{e^{\delta_{jm} + \tilde{V}_{ijm}(\theta)}}{\sum_l e^{\delta_{lm} + \tilde{V}_{ilm}(\theta)}} \mathrm{d} F(\eta_i, \nu_i \vert \theta) \label{eq:ints} \tag{7} \end{align}
Notice that the integral in \eqref{eq:ints} is multidimensional. BLP assumed that the distribution $F(\cdot)$ is the product of $k+1$ independent normals (1 from $\alpha_i$, $k$ from $\beta_{i}$). The above integrals are typically evaluated by Monte Carlo simulation with $N_m$ (number of sampled consumers in market $m$) draws of $(\eta_i, \nu_i)$ from $F(\eta_i, \nu_i \vert \theta)$: \begin{align*} \hat{S}_{jm} &= \frac{1}{N_m} \sum_{i=1}^{N_m} \frac{e^{\delta_{jm} + \tilde{V}_{ijm}(\theta)}}{\sum_l e^{\delta_{lm} + \tilde{V}_{ilm}(\theta)}} \label{eq:markov} \tag{8} \end{align*} In principle, other numerical integration method could also be used.
The Inner Loop¶
Once the choice model is estimated, the estimated constants $\delta$ can be used as the dependent variable in linear regression \eqref{eq:delta} to estimate $(\alpha,\beta)$. Since price is endogenous in that regression, it should be estimated by IV. BLP proposes two instruments: the average non-price attributes of other products by the same manufacturer; and the average nonprice attributes of other firms’ products.
But before that, we need to first address the issue that there might be a very large number of constants $\delta_{jm}$ to estimate: $J \times M \times T$ (number of products times number of markets times number of years).
BLP provides an algorithm for estimating them quickly, within the iterative process for the other parameters. We already know that $\hat{S}_{jm}$ is a function of $\delta_{jm}$ and $\theta$ from \eqref{eq:markov}. For a correctly specified model and a given value of $\theta$, contants $\delta_{jm}$ determine predicted market shares $\hat{S}_{jm}$ for each product, and therefore can be set such that the predicted shares equal actual shares: $\hat{S}_{jm}(\delta_{jm}) = S_{jm}$, at each trial value of $\theta$.
Instead of estimating the constants $\delta_{jm}$ by usual gradient-based methods, the iterative procedure recalibrates constants so that $\hat{S}_{jm}(\delta_{jm}) = S_{jm}$. The constants are adjusted iteratively by \begin{align} \delta_{jm}^{t+1} = \delta_{jm}^{t} + \ln \left( \frac{S_{jm}}{\hat{S}_{jm}(\delta^{t}_{jm})} \right) \label{eq:contraction} \tag{9} \end{align} Please think about how the process \eqref{eq:contraction} moves each constant in the "right" direction.
BLP shows that the iterative adjustment process is a contraction mapping, such that it is guaranteed to converge to a unique set of constants $\delta$. For any given value of $\theta$, the calibrated constants $\delta$s are uniquely determined (by the iterative adjustment process), that is, $\hat{\delta} = \hat{\delta}(\theta)$. This implies that the choice probability $S_{ijm}$ is now a function of $\theta$ alone: \begin{align*} \hat{S}_{ijm}(\theta) &= \hat{S}_{ijm}(\delta(\theta), \theta) \end{align*} The optimization of the whole problem is only over $\theta$.
The Nested Fixed Point Algorithm (NFP)¶
For any given $\theta$, the inner loop of the NFP \eqref{eq:contraction} solves the share equations $\hat{S}_{jm} = S_{jm}$ until the successive iterates $\delta_{jm}^{t+1}$ and $\delta_{jm}^{t}$ are sufficiently close. \begin{align*} \quad & \hat{\delta}_{jm} (\theta) = \mathop{\mathrm{argmin}}\limits_{\delta_{jm}} \enspace \lVert \delta_{jm}^{t} - \delta_{jm}^{t+1} \rVert \end{align*}
In each iteration of the outer loop, \eqref{eq:delta} is solved by GMM. For the given $\theta$, we solve \begin{align} \left(\hat{\alpha}(\theta), \hat{\beta}(\theta) \right) = \mathop{\mathrm{argmin}}\limits_{(\alpha, \beta)} \enspace g' W^{-1} g \label{eq:gmm} \tag{10} \end{align} and we loop over all possible $\theta$s to minimize the GMM objective function.
The observation-specific moments $g_{jm}$ in \eqref{eq:gmm} are \begin{align} g_{jm} = \xi_{jm} \cdot z_{jm} \overset{\eqref{eq:delta}}{=} \big[\delta_{jm}(\theta) - x_{jm} \beta + \alpha p_{jm}\big] \cdot z_{jm} \label{eq:mmt} \tag{11} \end{align} The optimal weighting matrix $W$ is the asymptotic covariance of $g$: $W = g g'$.
Estimation¶
Resources¶
Python: (best one to choose for now)
R:
Stata:
Steps¶
Decide the numbers of draws $N_m$, arbitrary starting values $\theta^{0}$ and $\delta^0$. Draw random values for $(\eta_i, \nu_i)$ across $i = 1,\dots, N_m$, from i.i.d multivariate normal (of length $k+1$) $F(\eta_i, \nu_i \vert \theta^{0})$. Approximate the integral $\hat{S}_{jm}$ using \eqref{eq:markov}.
Use starting values $\theta^{0}$ and $\delta^0$ and the observed market shares $S$, solve $\hat{\delta}$ by the iterative provess \eqref{eq:contraction}.
Select arbitrary starting values $(\alpha^0, \beta^0)$, calculate the moment conditions $g(\alpha^0, \beta^0, \hat{\delta})$ using \eqref{eq:mmt} and the starting weighting matrix $W^0 = g(\alpha^0, \beta^0, \hat{\delta}) g(\alpha^0, \beta^0, \hat{\delta})'$. Solve for the GMM estimates for $\alpha$ and $\beta$. Update the weighting matrix using the estimates, iterate until the GMM estimates converges. Take the converged weighting matrix and estimates as $\hat{W}$ and $(\hat{\alpha}, \hat{\beta})$.
Take the new values $(\hat{\delta}, \hat{\alpha}, \hat{\beta}, \hat{W})$, find a new value for $\theta$, repeat steps (1) to (3), until the moment expression $g' W^{-1} g$ from \eqref{eq:gmm} is close enough to 0.
The estimates are consistent even if you don't iterate on the weighting matrix in step 3. While an optimal 2-step GMM or an efficient 1-step continuously updated GMM will improve the statistical efficiency (Nevo, 2000; Dubé et al., 2012).
Example: Replicate Nevo (2000)¶
We try to replicate Table 1 of Nevo (2000). For illustration purpose, I don't use the pyblp
package.
"""
Preliminaries
"""
import pandas as pd
import numpy as np
from scipy.optimize import minimize
#!pip install pyblp
import pyblp
from numba import jit, njit, prange
import time
time_start = time.time()
import warnings
warnings.filterwarnings("ignore", category=Warning) ## Supress all warnings
"""
Read in data
"""
## Product data
product = pd.read_csv(pyblp.data.NEVO_PRODUCTS_LOCATION)
product ["cons"] = 1
## Consumer data
consumer = pd.read_csv(pyblp.data.NEVO_AGENTS_LOCATION)
demographic = consumer[["income", "income_squared", "age", "child"]].values
"""
Some data cleansing
"""
## Number of goods per market
J = product.groupby("market_ids").sum(numeric_only=True).cons.values
## Number of markets
M = len(J)
## Number of simulations per market (Accorigin to Nevo, 2000, page 538)
N = 20
"""
We specify the regressors in $\bar{V}$ (linear) and $\tilde{V}$ (non-linear).
The two sets of regressors are not necessarily the same, because we may not want
random coefficients (the $\beta_i$s) over all the regressors.
"""
## The (linear) regressors in V_bar
X1 = np.hstack((product[["prices"]], pd.get_dummies(product["product_ids"])))
## The (non-linear) regressors in V_tilde, over which we want random
# coefficients (so no fixed effects)
X2 = product[["cons", "prices", "sugar", "mushy"]].values
## Number of nonlinear parameters (k=3 because we have "prices", "sugar", "mushy")
k = X2.shape[1] - 1
## Insruments
iv_cols = [col for col in product.columns if 'demand' in col]
Z = np.hstack((product[iv_cols], pd.get_dummies(product["product_ids"])))
"""
Monte carlo simulation for \nu_i
- k+1: k from x, 1 from p
- M: different draws for each market
- N: number of draws
"""
np.random.seed(0)
v = np.reshape(np.random.standard_normal((k + 1) * N * M), (M * N, k + 1))
"""
Class delta
"""
## Shares of the outside good (base category) (See Nevo, 2000, page 520)
product["outside"] = product["shares"].groupby(product["market_ids"]).transform("sum")
## Initial delta: log(share) - log(share(outside good)) (normalization)
delta_0 = np.log(product["shares"]) - np.log(product["outside"])
## Class for updating delta
class delta:
def __init__(self, delta):
self.delta = np.array(delta)
## Initialize a delta object using delta_0
d = delta(delta_0)
"""
Define functions
"""
"""
Common inputs:
- x1: non-price product attributes (linear)
- x2: non-price product attributes (nonlinear)
- p: price
- v: monte carlo draws for \nu
- demographic: comsumer demographics
- delta: initial guess for the mean utility
- sigma: Sigma for nonlinear parameters
- pi: Pi for nonlinear parameters
- J: vector of number of goods per market
- M: numer of markets
- N: number of draws
"""
"""
Function: fill in (deterministic) utility elements
"""
@njit(parallel = True) ## run in parallel
def emax_iter(out, x2, v, demographic, delta, sigma, pi, J, M, N):
for i in prange(N): ## Iterate over the individuals
mj = 0
for m in prange(M): # Iterate over the markets
mktSize = J[m] # Market size of market m
for j in prange(mktSize): # Iterate over all goods in market m
## u(ijm), equation (4)
out[mj, i] = delta[mj] + \
x2[mj, 0] * (v[N * m + i, 0] * sigma[0] +
np.dot(pi[0,:], demographic[N * m + i,:])) + \
x2[mj, 1] * (v[N * m + i, 1] * sigma[1] +
np.dot(pi[1,:], demographic[N * m + i,:])) + \
x2[mj, 2] * (v[N * m + i, 2] * sigma[2] +
np.dot(pi[2,:], demographic[N * m + i,:])) + \
x2[mj, 3] * (v[N * m + i, 3] * sigma[3] +
np.dot(pi[3,:], demographic[N * m + i,:]))
mj += 1
return out
"""
Function: return indirect utility matrix
"""
@jit(forceobj=True)
def indirect_utility(x2, v, demographic, delta, sigma, pi, J, M, N):
sigma = np.abs(sigma) ## positve Sigma
out = np.zeros((sum(J), N)) ## initialization
## Fixed point iteration
out = emax_iter(out, x2, v, demographic, delta, sigma, pi, J, M, N)
return out
"""
Function: compute estimated market shares
outputs:
- q: quantities consumed
- s: market shares
"""
@jit(forceobj=True)
def mkt_share(x2, v, demographic, delta, sigma, pi, J, M, N):
## Quantities bought (initialization)
q = np.zeros((np.sum(J), N))
## Indirect utilities
u = indirect_utility(x2, v, demographic, delta, sigma, pi, J, M, N)
## Exponentiate the utilities
exp_u = np.exp(u)
## Outside good
first_good = 0
for m in range(M):
mktSize = J[m] ## market size of market m
numer = exp_u[first_good:first_good + mktSize,:] ## numerator for shares
denom = 1 + numer.sum(axis = 0) ## demoninator for shares
q[first_good:first_good + mktSize,:] = numer/denom ## quantity(ijm)
first_good += mktSize
## Shares. We use equal weight for all goods.
s = np.matmul(q, np.repeat(1/N, N))
return [q,s]
"""
Function: Solve delta using the iterative process
"""
@jit(forceobj=True)
def solve_delta(s, x2, v, demographic, delta, sigma, pi, J, M, N, tol):
diff = 1
delta_old = delta
while diff > tol:
## The estimated shares
q_s = mkt_share(x2, v, demographic, delta_old, sigma, pi, J, M, N)
sigma_jm = q_s[1]
## Contraction mapping
delta_new = delta_old + np.log(s/sigma_jm)
## Update the difference between iterates
diff = np.max(np.abs(delta_new - delta_old))
delta_old = delta_new.copy()
return delta_old
"""
Function: calculate value of the GMM objective function
"""
def objective(params, s, x1, x2, v, demographic, J, M, N, tol, Z, W):
## Initialization: theta_0
sigma = params[0:4]
pi = params[4:].reshape((4,4))
pi[[0,2,3],1] = 0
pi[[0,2,3],3] = 0
pi[1,2] = 0
## Number of obs. JxM
obs = np.sum(J)
if np.min(sigma) < 0:
return 1e20
else:
d.delta = solve_delta(s, x2, v, demographic, d.delta, sigma, pi, J, M, N, tol) ## inner loop
delta_vector = d.delta.reshape((-1,1))
## Linear parameters (alpha, beta) given theta_0, FOC
b = np.linalg.inv(x1.T @ Z @ W @ Z.T @ x1) @ (x1.T @ Z @ W @ Z.T @ delta_vector)
## Estimate for error term \xi
xi = delta_vector - x1 @ b
g = Z.T @ xi / np.size(xi, axis = 0)
obj = float(obs ** 2 * g.T @ W @ g)
return obj
"""
Starting values
- We choose the same starting values for theta and W as Nevo (2000)
"""
## Initial values for theta
sigma = [ .377, 1.848, 0.004, 0.081 ]
pi1 = [ 3.09, 0, 1.186, 0 ]
pi2 = [ 16.6, -.66, 0, 11.6 ]
pi3 = [ -0.193, 0, 0.03, 0 ]
pi4 = [ 1.468, 0, -1.5, 0 ]
params = np.hstack((sigma, pi1, pi2, pi3, pi4))
## Initial weighting matrix
W0 = np.linalg.inv(Z.T @ Z)
"""
Get the optimal weight matrix
"""
## Using initial weight matrix W0
params_init_wt = minimize(objective,
params,
args = (product.shares.values, X1, X2, v, demographic, J, M, N, 1e-4, Z, W0),
method = "Nelder-Mead")
params_2 = params_init_wt.x
sigma_2 = params_2[0:4]
pi_2 = params_2[4:].reshape((4,4))
d.delta = solve_delta(product.shares.values, X2, v, demographic, d.delta, sigma_2, pi_2, J, M, N, 1e-4) ## inner loop
delta_vector = d.delta.reshape((-1,1))
b = np.linalg.inv(X1.T @ Z @ W0 @ Z.T @ X1) @ (X1.T @ Z @ W0 @ Z.T @ delta_vector)
xi = delta_vector - X1 @ b
## Update weighting matrix
g_ind = Z * xi
obs = np.sum(J)
vg = g_ind.T @ g_ind / obs
## Optimal weighting matrix
Wo = np.linalg.inv(vg)
"""
NFP with optimal weighting matrix
"""
params_optimal = minimize(objective,
params,
args = (product.shares.values, X1, X2, v, demographic, J, M, N, 1e-4, Z, Wo),
method = "Nelder-Mead")
params_estimated = params_optimal.x
time_end = time.time()
elapsed_time = time_end - time_start
elapsed_minutes = int(elapsed_time / 60)
elapsed_seconds = int(elapsed_time % 60)
print("Elapsed time: {}m {}s".format(elapsed_minutes, elapsed_seconds))
Elapsed time: 4m 4s
"""
Print Results
"""
print('-' * 20, " Replication results ", '-' * 20, '\n')
print("Context: \n Length of x vector (k) = ", k, ",\n Number of markets (M) = ", M, ", \n Number of draws (N) = ", N, '\n')
# print("Estimates shares = \n", mkt_share(X2, v, demographic, d.delta, params_estimated[0:(k+1)], params_estimated[(k+1):].reshape(((k+1),(k+1))), J, M, N), "\n") ## the estimated market shares
print("GMM objective value = ", round(objective(params_estimated, product.shares.values, X1, X2, v, demographic, J, M, N, 1e-4, Z, Wo)/np.sum(J), 1), "; Nevo's result = 14.9 \n")
print("alpha(price) = ", round(b[0][0], 3), "; Nevo's result = -32.433 \n")
# print("beta = ", b, "\n") ## the whole vector of linear parameters (alpha, beta), the first element of which is the price coefficient alpha
print("Sigma = \n", params_estimated[0:(k+1)],"\n")
print("Pi = \n", params_estimated[(k+1):].reshape(((k+1),(k+1))),"\n")
-------------------- Replication results -------------------- Context: Length of x vector (k) = 3 , Number of markets (M) = 94 , Number of draws (N) = 20 GMM objective value = 15.4 ; Nevo's result = 14.9 alpha(price) = -38.072 ; Nevo's result = -32.433 Sigma = [2.49897746e-04 9.33870292e+00 2.45505416e-06 3.07782234e-02] Pi = [[ 3.34507418 0. 1.58247038 0. ] [ 1.64308535 0.2381023 0. 11.13164642] [-0.27366374 0. 0.02471842 0. ] [ 2.20558565 0. -1.99445009 0. ]]
References¶
Berry, S., Levinsohn, J., & Pakes, A. (1995). Automobile prices in market equilibrium. Econometrica: Journal of the Econometric Society, 841-890.
Nevo, A. (2000). A practitioner's guide to estimation of random‐coefficients logit models of demand. Journal of economics & management strategy, 9(4), 513-548.
Berry, S., Levinsohn, J., & Pakes, A. (2004). Differentiated products demand systems from a combination of micro and macro data: The new car market. Journal of political Economy, 112(1), 68-105.
Rasmusen, E. (2007). The BLP Method of Demand Curve Estimation in Industrial Organization.
Train, K. E. (2009). Discrete choice methods with simulation. Cambridge university press.
Dubé, J. P., Fox, J. T., & Su, C. L. (2012). Improving the numerical performance of static and dynamic aggregate discrete choice random coefficients demand estimation. Econometrica, 80(5), 2231-2267.