In this session, I am going to cover demand estimation.
- Compute equilibrium outcomes with RCL demand
- Simulate market-level data
- Extremely similar to the logit demand simulation
- Build the BLP estimator from Berry, Levinsohn, and Pakes (1995)
2021-10-29
In this session, I am going to cover demand estimation.
In this first part, we are going to assume that consumer \(i \in \lbrace1,...,I\rbrace\) utility from good \(j \in \lbrace1,...,J\rbrace\) in market \(t \in \lbrace1,...,T\rbrace\) takes the form
\[ u_{ijt} = \boldsymbol x_{jt} \boldsymbol \beta_{it} - \alpha p_{jt} + \xi_{jt} + \epsilon_{ijt} \]
where
We have \(J\) firms and each product has \(K\) characteristics.
i = 100; # Number of consumers J = 10; # Number of firms K = 2; # Product characteristics T = 100; # Number of markets β = [.5, 2, -1]; # Preferences varζ = 5; # Variance of the random taste rangeJ = [2, 6]; # Min and max firms per market varX = 1; # Variance of X varξ = 2; # Variance of xi
Demand is the main difference w.r.t. the logit model. Now we have individual shocks \(\zeta\) we have to integrate over.
function demand(p::Vector, X::Matrix, β::Vector, ξ::Matrix, ζ::Matrix)::Tuple{Vector, Number} """Compute demand""" δ = [X p] * (β .+ ζ) # Mean value δ0 = zeros(1, size(ζ, 2)) # Mean value of the outside option u = [δ; δ0] + ξ # Utility e = exp.(u) # Take exponential q = mean(e ./ sum(e, dims=1), dims=2) # Compute demand return q[1:end-1], q[end] end;
Computing profits is instead exactly the same as before. We just have to save the shocks \(\zeta\) to be sure demand is stable.
function profits(p::Vector, c::Vector, X::Matrix, β::Vector, ξ::Matrix, ζ::Matrix)::Vector """Compute profits""" q, _ = demand(p, X, β, ξ, ζ) # Compute demand pr = (p - c) .* q # Compute profits return pr end;
function profits_j(pj::Number, j::Int, p::Vector, c::Vector, X::Matrix, β::Vector, ξ::Matrix, ζ::Matrix)::Number """Compute profits of firm j""" p[j] = pj # Insert price of firm j pr = profits(p, c, X, β, ξ, ζ) # Compute profits return pr[j] end;
We can now compute the equilibrium for a specific market, as before.
function equilibrium(c::Vector, X::Matrix, β::Vector, ξ::Matrix, ζ::Matrix)::Vector """Compute equilibrium prices and profits""" p = 2 .* c; dist = 1; iter = 0; # Iterate until convergence while (dist > 1e-8) && (iter<1000) # Compute best reply for each firm p_old = copy(p); for j=1:length(p) obj_fun(pj) = - profits_j(pj[1], j, p, c, X, β, ξ, ζ); optimize(x -> obj_fun(x), [1.0], LBFGS()); end # Update distance dist = max(abs.(p - p_old)...); iter += 1; end return p end;
We are now ready to simulate the data, i.e. equilibrium outcomes across different markets. We first draw all the variables.
function draw_data(I::Int, J::Int, K::Int, rangeJ::Vector, varζ::Number, varX::Number, varξ::Number)::Tuple """Draw data for one market""" J_ = rand(rangeJ[1]:rangeJ[2]) # Number of firms (products) X_ = rand(Exponential(varX), J_, K) # Product characteristics ξ_ = rand(Normal(0, varξ), J_+1, I) # Product-level utility shocks # Consumer-product-level preference shocks ζ_ = [rand(Normal(0,1), 1, I) * varζ; zeros(K,I)] w_ = rand(Uniform(0, 1), J_) # Cost shifters ω_ = rand(Uniform(0, 1), J_) # Cost shocks c_ = w_ + ω_ # Cost j_ = sort(sample(1:J, J_, replace=false)) # Subset of firms return X_, ξ_, ζ_, w_, c_, j_ end;
Then we simulate the data for one market.
function compute_mkt_eq(I::Int, J::Int, β::Vector, rangeJ::Vector, varζ::Number, varX::Number, varξ::Number)::DataFrame """Compute equilibrium one market""" # Initialize variables K = size(β, 1) - 1 X_, ξ_, ζ_, w_, c_, j_ = draw_data(I, J, K, rangeJ, varζ, varX, varξ) # Compute equilibrium p_ = equilibrium(c_, X_, β, ξ_, ζ_) # Equilibrium prices q_, q0 = demand(p_, X_, β, ξ_, ζ_) # Demand with shocks pr_ = (p_ - c_) .* q_ # Profits # Save to data q0_ = ones(length(j_)) .* q0 df = DataFrame(j=j_, w=w_, p=p_, q=q_, q0=q0_, pr=pr_) for k=1:K df[!,"x$k"] = X_[:,k] df[!,"z$k"] = sum(X_[:,k]) .- X_[:,k] end return df end;
We repeat for \(T\) markets.
function simulate_data(I::Int, J::Int, β::Vector, T::Int, rangeJ::Vector, varζ::Number, varX::Number, varξ::Number) """Simulate full dataset""" df = compute_mkt_eq(I, J, β, rangeJ, varζ, varX, varξ) df[!, "t"] = ones(nrow(df)) * 1 for t=2:T df_temp = compute_mkt_eq(I, J, β, rangeJ, varζ, varX, varξ) df_temp[!, "t"] = ones(nrow(df_temp)) * t append!(df, df_temp) end CSV.write("../data/blp.csv", df) return df end;
Now let’s run the code
# Simulate df = simulate_data(i, J, β, T, rangeJ, varζ, varX, varξ);
What does the data look like? Let’s switch to R!
# Read data df = fread("../data/blp.csv") kable(df[1:6,], digits=4)
j | w | p | q | q0 | pr | x1 | z1 | x2 | z2 | t |
---|---|---|---|---|---|---|---|---|---|---|
2 | 0.2639 | 5.9452 | 0.1639 | 0.5268 | 0.7921 | 1.3461 | 0.7353 | 0.3688 | 0.8783 | 1 |
3 | 0.1369 | 2.5301 | 0.1389 | 0.5268 | 0.2753 | 0.4272 | 1.6541 | 0.2955 | 0.9516 | 1 |
5 | 0.2587 | 2.4449 | 0.1704 | 0.5268 | 0.3431 | 0.3081 | 1.7732 | 0.5828 | 0.6643 | 1 |
6 | 0.6062 | 4.2605 | 0.2256 | 0.5354 | 0.8077 | 1.0894 | 0.7809 | 0.3267 | 0.3921 | 2 |
7 | 0.1020 | 3.0919 | 0.2390 | 0.5354 | 0.6863 | 0.7809 | 1.0894 | 0.3921 | 0.3267 | 2 |
2 | 0.3524 | 2.7008 | 0.1297 | 0.3862 | 0.2396 | 0.1354 | 4.0332 | 0.5467 | 2.0619 | 3 |
The BLP estimation procedure
First, we need to compute the shares implied by aspecific vector of \(\delta\)s
function implied_shares(Xt_::Matrix, ζt_::Matrix, δt_::Vector, δ0::Matrix)::Vector """Compute shares implied by deltas and shocks""" u = [δt_ .+ (Xt_ * ζt_); δ0] # Utility e = exp.(u) # Take exponential q = mean(e ./ sum(e, dims=1), dims=2) # Compute demand return q[1:end-1] end;
We can now compute the inner loop and invert the demand function: from shares \(q\) to \(\delta\)s
function inner_loop(qt_::Vector, Xt_::Matrix, ζt_::Matrix)::Vector """Solve the inner loop: compute delta, given the shares""" δt_ = ones(size(qt_)) δ0 = zeros(1, size(ζt_, 2)) dist = 1 # Iterate until convergence while (dist > 1e-8) q = implied_shares(Xt_, ζt_, δt_, δ0) δt2_ = δt_ + log.(qt_) - log.(q) dist = max(abs.(δt2_ - δt_)...) δt_ = δt2_ end return δt_ end;
We can now repeat the inversion for every market and get the vector of mean utilities \(\delta\)s from the observed market shares \(q\).
function compute_delta(q_::Vector, X_::Matrix, ζ_::Matrix, T::Vector)::Vector """Compute residuals""" δ_ = zeros(size(T)) # Loop over each market for t in unique(T) qt_ = q_[T.==t] # Quantity in market t Xt_ = X_[T.==t,:] # Characteristics in mkt t δ_[T.==t] = inner_loop(qt_, Xt_, ζ_) # Solve inner loop end return δ_ end;
Now that we have \(\delta\), it is pretty straightforward to compute \(\xi\). We just need to perform a linear regression (with instruments) of mean utilities \(\delta\) on prices \(p\) and product characteristics \(X\) and compute the residuals \(\xi\).
function compute_xi(X_::Matrix, IV_::Matrix, δ_::Vector)::Tuple """Compute residual, given delta (IV)""" β_ = inv(IV_' * X_) * (IV_' * δ_) # Compute coefficients (IV) ξ_ = δ_ - X_ * β_ # Compute errors return ξ_, β_ end;
We now have all the ingredients to set up the GMM objective function.
function GMM(varζ_::Number)::Tuple """Compute GMM objective function""" δ_ = compute_delta(q_, X_, ζ_ * varζ_, T) # Compute deltas ξ_, β_ = compute_xi(X_, IV_, δ_) # Compute residuals gmm = ξ_' * Z_ * Z_' * ξ_ / length(ξ_)^2 # Compute ortogonality condition return gmm, β_ end;
First, we need to set up our objects
# Retrieve data T = Int.(df.t) X_ = [df.x1 df.x2 df.p] q_ = df.q q0_ = df.q0 IV_ = [df.x1 df.x2 df.w] Z_ = [df.x1 df.x2 df.z1 df.z2]
What would a logit regression estimate?
# Compute logit estimate y = log.(df.q) - log.(df.q0); β_logit = inv(IV_' * X_) * (IV_' * y); print("Estimated logit coefficients: $β_logit")
## Estimated logit coefficients: [1.6707629684340313, 1.090127651610374, -0.8676967920899061]
We can now run the BLP machinery
# Draw shocks (less) ζ_ = [rand(Normal(0,1), 1, i); zeros(K, i)]; # Minimize GMM objective function varζ_ = optimize(x -> GMM(x[1])[1], [2.0], LBFGS()).minimizer[1]; β_blp = GMM(varζ_)[2]; print("Estimated BLP coefficients: $β_blp")
## Estimated BLP coefficients: [0.5404717706555511, 1.1612479679061647, -0.5876407838141476]
Berry, Steven, James Levinsohn, and Ariel Pakes. 1995. “Automobile Prices in Market Equilibrium.” Econometrica: Journal of the Econometric Society, 841–90.