BLPestimatoR - Package for Demand Estimation

Daniel Brunner

2018-09-14

Intro

BLPestimatoR provides an efficient estimation algorithm to perform the demand estimation described in Berry, Levinsohn, and Pakes (1995). The routine uses analytic gradients and offers a large number of optimization routines and implemented integration methods as discussed in Brunner et al. (2017).

This extended documentation demonstrates the steps of a typical demand estimation with the package:

The use of the algorithm’s building blocks is explained as well. The well-known training data for the cereal market from Nevo (2001) is used for demonstration purposes.

Data

Model

Since version 0.1.6 the model is provided in R’s formula syntax and consists of five parts. The variable to be explained is given by observed market shares. Explanatory variables are grouped into four (possibly overlapping) categories separated by |:

Nevo’s model can be translated into the following formula syntax:

library(BLPestimatoR)

nevos_model <- as.formula("share ~  price + productdummy |
    0+ productdummy |
    price + sugar + mushy |
    0+ IV1 + IV2 + IV3 + IV4 + IV5 + IV6 + IV7 + IV8 + IV9 + IV10 + 
    IV11 + IV12 + IV13 + IV14 + IV15 + IV16 + IV17 + IV18 + IV19 + IV20")

The model is directly related to consumer \(i\)’s indirect utility from purchasing cereal \(j\) in market \(t\):

\[u_{ijt}=\sum_{m=1}^M x^{(m)}_{jt} \beta_{i,m}+\xi_{jt}+\epsilon_{ijt} \;\; \text{with}\] \[\beta_{i,m}= \bar{\beta}_m + \sum_{r=1}^R \gamma_{m,r} d_{i,r} + \sigma_m \nu_{i,m}\] and

\[\theta_2 = \begin{pmatrix} \sigma_1 & \gamma_{1,1} & \cdots & \gamma_{1,R} \\ \sigma_2 & \gamma_{2,1} & \cdots & \gamma_{2,R} \\ \vdots & \vdots & \ddots & \vdots \\ \sigma_M & \gamma_{M,1} & \cdots & \gamma_{M,R} \end{pmatrix}\]

Dataframe

Product related variables are collected in the dataframe productData with the following requirements:

A variable that uniquely identifies a product in a market (product_identifier) is optional, but enhances clarity (interpreting elasticities, for example, is much easier). market_identifier and product_identifier together uniquely identify an observation, which is used by the function update_BLP_data to update any variable in the data (in this case product_identifier is mandatory).

In the cereal example, this gives the following dataframe:

head(productData)
#>        price const sugar mushy       share     cdid        IV1        IV2
#> 1 0.07208794     1     2     1 0.012417212 market_1 -0.2159728 0.04057341
#> 2 0.11417849     1    18     1 0.007809387 market_1 -0.2452393 0.05474226
#> 3 0.13239066     1     4     1 0.012994511 market_1 -0.1764587 0.04659597
#> 4 0.13034408     1     3     0 0.005769961 market_1 -0.1214013 0.04876037
#> 5 0.15482331     1    12     0 0.017934141 market_1 -0.1326114 0.03962835
#> 6 0.13704921     1    14     0 0.026601892 market_1 -0.1534998 0.04298842
#>          IV3          IV4         IV5           IV6        IV7         IV8
#> 1  -3.247948 -0.523937695 -0.23246005  0.0068326605  3.1397395 -0.57478633
#> 2 -19.832461 -0.180519694  0.01468859  0.0007988026  0.2876539  0.03293960
#> 3  -2.878531 -0.284219004 -0.21553691 -0.0318693281  2.8862741 -0.74976495
#> 4  -2.059918 -0.328412257 -0.22206995 -0.0314740402  4.4531096  0.25567529
#> 5  -6.137598 -0.138625095 -0.18936521 -0.0437471023 -3.5546508  0.13882114
#> 6  -8.417332  0.007829087 -0.13850121 -0.0210582272 -2.7594799  0.05020052
#>          IV9       IV10       IV11        IV12          IV13       IV14
#> 1  0.2062202  0.1774656  2.1163580 -0.15470824 -0.0057964065 0.01453802
#> 2  0.1051208 -0.2875618 -7.3740909 -0.57641176  0.0129908544 0.07614324
#> 3 -0.4789565  0.2147389  2.1878721 -0.20734643  0.0035092777 0.09178117
#> 4 -0.4729673  0.3560980  2.7045762  0.04074801 -0.0037242656 0.09473168
#> 5 -0.6886784  0.2602726  1.2612419  0.03483558 -0.0005676374 0.10245147
#> 6 -0.2734440  0.1273060  0.3375543  0.02351037  0.0002637777 0.08627983
#>         IV15       IV16       IV17       IV18       IV19       IV20
#> 1 0.12624398 0.06734464 0.06842261 0.03480046 0.12634612 0.03548368
#> 2 0.02973565 0.08786672 0.11050060 0.08778380 0.04987192 0.07257905
#> 3 0.16377308 0.11188073 0.10822551 0.08643905 0.12234707 0.10184248
#> 4 0.13527378 0.08809001 0.10176745 0.10177748 0.11074119 0.10433204
#> 5 0.13063951 0.08481820 0.10107461 0.12516923 0.13346381 0.12111110
#> 6 0.07233581 0.02225051 0.10564387 0.11603699 0.09965063 0.10572660
#>   product_id productdummy
#> 1   cereal_1     product1
#> 2   cereal_2     product2
#> 3   cereal_3     product3
#> 4   cereal_4     product4
#> 5   cereal_5     product5
#> 6   cereal_6     product6

Integration Draws

The arguments related to the numerical integration problem are of particular importance when providing own integration draws and weights, which is most relevant for observed heterogeneity (for unobserved heterogeneity, the straightforward approach is the use of automatic integration).

In the cereal data, both, observed and unobserved heterogeneity, is used for the random coefficients. Starting with observed heterogeneity, user provided draws are collected in a list. Each list entry must be named according to the name of a demographic. Each entry contains the following variables:

In the cereal example, observed heterogeneity is provided as follows (list names correspond to the demographics):

demographicData$income[1:4,1:5]
#>       cdid     draw_1     draw_2     draw_3      draw_4
#> 1 market_1 0.49512349  0.3787622  0.1050146 -1.48548093
#> 2 market_2 0.05389113 -1.5030833  0.6217917  0.26922901
#> 3 market_3 0.62459788 -0.2242698 -0.2846169  0.67845943
#> 4 market_4 0.94419851  0.4056359  0.5859923  0.01813051

demographicData$incomesq[1:4,1:5]
#>       cdid     draw_1     draw_2    draw_3      draw_4
#> 1 market_1  8.3313042   6.121865  1.030803 -25.5836047
#> 2 market_2  0.0966346 -25.849845 10.767233   4.0668173
#> 3 market_3 10.8215619  -4.894545 -5.956954  11.8673879
#> 4 market_4 17.1121550   6.629730 10.075529  -0.5537043

demographicData$age[1:4,1:5]
#>       cdid     draw_1     draw_2       draw_3     draw_4
#> 1 market_1 -0.2301090 -2.5326941 -0.006965458 -0.8279460
#> 2 market_2  0.1414545 -0.1813188 -1.279931134 -0.4532526
#> 3 market_3 -0.1813188 -0.5867840  0.208145922 -0.4532526
#> 4 market_4  0.7444506  0.1414545  0.645359728  0.8346017

demographicData$child[1:4,1:5]
#>       cdid     draw_1     draw_2     draw_3     draw_4
#> 1 market_1 -0.2308511  0.7691489 -0.2308511  0.7691489
#> 2 market_2 -0.2308511 -0.2308511  0.7691489 -0.2308511
#> 3 market_3 -0.2308511  0.7691489 -0.2308511 -0.2308511
#> 4 market_4 -0.2308511 -0.2308511 -0.2308511 -0.2308511

If demographic input (demographicData) is missing, the estimation routine considers only coefficients for unobserved heterogeneity. This can be done by already implemented integration methods via integration_method as shown in the estimation section. In Nevo’s cereal example however, a specific set of 20 draws is given. For this situation, draws are also provided as a list (list names correspond to the formula’s random coefficients and each list entry has a variable market_identifier):

originalDraws$constant[1:4,1:5]
#>       cdid       draw_1     draw_2     draw_3      draw_4
#> 1 market_1  0.434100553 -0.7266491 -0.6230607 -0.04131699
#> 2 market_2  0.001702598  0.2228245 -1.0287201  0.38312476
#> 3 market_3 -0.529569305  0.7248712  0.2910167 -1.39164253
#> 4 market_4  0.019233489 -1.4250308 -0.2678170 -2.26541236

# renaming constants:
names(originalDraws)[1] <- "(Intercept)"

originalDraws$price[1:4,1:5]
#>       cdid     draw_1     draw_2     draw_3     draw_4
#> 1 market_1 -1.5008378  0.1331817 -0.1382405  1.2571357
#> 2 market_2  0.0276477 -0.8414414 -0.9056861 -2.0306179
#> 3 market_3 -0.4768085 -0.9348689  1.4300456  2.6188581
#> 4 market_4  0.5396019  0.1698178  0.7128376 -0.1216309

originalDraws$sugar[1:4,1:5]
#>       cdid     draw_1     draw_2     draw_3     draw_4
#> 1 market_1 -1.1510786 -0.5007498  0.7974412 -0.6830540
#> 2 market_2  1.0451218  1.0170277  2.3012550  0.1490338
#> 3 market_3 -1.0187809  0.3107185 -0.9531532  0.8057080
#> 4 market_4 -0.5760582 -0.5072059 -0.7496653  1.1163544

originalDraws$mushy[1:4,1:5]
#>       cdid     draw_1     draw_2      draw_3     draw_4
#> 1 market_1 0.16101681  0.1297316 -0.79554915  0.2590437
#> 2 market_2 0.23595798  0.1345995  0.07284586  0.9509871
#> 3 market_3 0.02922435 -0.1704289  0.36395246  0.4879702
#> 4 market_4 1.27701102  0.4284194  0.46124654 -1.0110437

As demonstrated above, list entries for draws of constants must be named (Intercept). Other names of list entries must match the random coefficients specified in the formula.

Calling BLP_data

Calling BLP_data structures and prepares the data for estimation and creates the data object:

productData$startingGuessesDelta  <- c( log(w_guesses)) # include orig. draws in the product data

nevo_data <- BLP_data(model = nevos_model,
                      market_identifier="cdid",
                      par_delta = "startingGuessesDelta",
                      product_identifier = "product_id",
                      productData = productData,
                      demographic_draws = demographicData,
                      blp_inner_tol = 1e-6, blp_inner_maxit = 5000,
                      integration_draws = originalDraws, 
                      integration_weights= rep(1/20,20))

The arguments in greater detail:

If you decide to update your data later, you can use the function update_BLP_data.

Estimation

Starting guesses

The provided set of starting guesses par_theta2 is matched with formula input and demographic data:

These requirements are demonstrated with Nevo’s starting guesses:

#before:
theta_guesses
#>        [,1]    [,2] [,3]    [,4]   [,5]
#> [1,] 0.3302  5.4819  0.0  0.2037 0.0000
#> [2,] 2.4526 15.8935 -1.2  0.0000 2.6342
#> [3,] 0.0163 -0.2506  0.0  0.0511 0.0000
#> [4,] 0.2441  1.2650  0.0 -0.8091 0.0000
theta_guesses[theta_guesses==0] <- NA 
colnames(theta_guesses) <- c("unobs_sd", "income", "incomesq", "age", "child" )
rownames(theta_guesses) <- c("(Intercept)", "price" , "sugar", "mushy")

# correctly named:
theta_guesses
#>             unobs_sd  income incomesq     age  child
#> (Intercept)   0.3302  5.4819       NA  0.2037     NA
#> price         2.4526 15.8935     -1.2      NA 2.6342
#> sugar         0.0163 -0.2506       NA  0.0511     NA
#> mushy         0.2441  1.2650       NA -0.8091     NA

Calling estimateBLP

The following code performs the demand estimation:


blp_est <- estimateBLP( blp_data=nevo_data,
                        par_theta2 = theta_guesses,
                        solver_method = "BFGS", solver_maxit = 1000, solver_reltol = 1e-6,
                        standardError = "heteroskedastic",
                        extremumCheck = FALSE ,
                        printLevel = 1 )
#> blp_data were prepared with the following arguments:
#> BLP_data(model = nevos_model, market_identifier = "cdid", product_identifier = "product_id", 
#>     par_delta = "startingGuessesDelta", productData = productData, 
#>     demographic_draws = demographicData, integration_draws = originalDraws, 
#>     integration_weights = rep(1/20, 20), blp_inner_tol = 1e-06, 
#>     blp_inner_maxit = 5000)
#> Starting a BLP demand estimation with  2256  observations in  94  markets...
#> [integration::method  integration::amountDraws 20 ]
#> [blp::inner_tol 1e-06  blp::inner_maxit 5000 ]
#> [solver::method BFGS  solver::maxit 1000  solver::reltol 1e-06 ]
#> gmm objective: 29.3522
#> gmm objective: Inf [delta contains NaN's] 
#> gmm objective: Inf [delta contains NaN's] 
#> gmm objective: Inf [delta contains NaN's] 
#> gmm objective: 22451.18
#> gmm objective: 775.9515
#> gmm objective: 71.6209
#> gmm objective: 26.8851
#> gmm objective: Inf [delta contains NaN's] 
#> gmm objective: 330914
#> gmm objective: 12694.84
#> gmm objective: 311.8842
#> gmm objective: 38.2627
#> gmm objective: 26.9935
#> gmm objective: 26.8196
#> gmm objective: 40772.63
#> gmm objective: 1186.144
#> gmm objective: 103.4133
#> gmm objective: 27.9556
#> gmm objective: 26.1524
#> gmm objective: Inf [delta contains NaN's] 
#> gmm objective: Inf [delta contains NaN's] 
#> gmm objective: 28234.6
#> gmm objective: 756.8709
#> gmm objective: 37.7704
#> gmm objective: 24.7211
#> gmm objective: 5772.739
#> gmm objective: 202.5456
#> gmm objective: 27.2616
#> gmm objective: 23.9898
#> gmm objective: 838.469
#> gmm objective: 32.1783
#> gmm objective: 21.9662
#> gmm objective: 23912.56
#> gmm objective: 244.3514
#> gmm objective: 20.9664
#> gmm objective: 1417.216
#> gmm objective: 56.3625
#> gmm objective: 21.2928
#> gmm objective: 20.6459
#> gmm objective: 24.7031
#> gmm objective: 19.3915
#> gmm objective: 192.3949
#> gmm objective: 18.8625
#> gmm objective: 20.5334
#> gmm objective: 17.7234
#> gmm objective: 16.7846
#> gmm objective: 16.4664
#> gmm objective: 15.9588
#> gmm objective: 15.0231
#> gmm objective: 14.9101
#> gmm objective: 14.8987
#> gmm objective: 14.8961
#> gmm objective: 14.8902
#> gmm objective: 14.8788
#> gmm objective: 14.8479
#> gmm objective: 14.7731
#> gmm objective: 14.5807
#> gmm objective: 14.0873
#> gmm objective: 12.8012
#> gmm objective: 11.9828
#> gmm objective: 9.4672
#> gmm objective: Inf [delta contains NaN's] 
#> gmm objective: Inf [delta contains NaN's] 
#> gmm objective: 150504.2
#> gmm objective: 6437.658
#> gmm objective: 224.7393
#> gmm objective: 13.0643
#> gmm objective: 9.2023
#> gmm objective: Inf [delta contains NaN's] 
#> gmm objective: 10140.17
#> gmm objective: 554.5767
#> gmm objective: 34.6091
#> gmm objective: 10.0322
#> gmm objective: 9.1844
#> gmm objective: 75730.14
#> gmm objective: 2145.751
#> gmm objective: 45.6103
#> gmm objective: 9.9089
#> gmm objective: 9.0889
#> gmm objective: 111102.8
#> gmm objective: 17852.06
#> gmm objective: 389.125
#> gmm objective: 20.1367
#> gmm objective: 8.7624
#> gmm objective: 766.0638
#> gmm objective: 49.5382
#> gmm objective: 10.0242
#> gmm objective: 8.6598
#> gmm objective: 155.1232
#> gmm objective: 12.3475
#> gmm objective: 8.5964
#> gmm objective: 308.36
#> gmm objective: 10.1499
#> gmm objective: 8.3448
#> gmm objective: 1593.047
#> gmm objective: 18.5902
#> gmm objective: 7.9521
#> gmm objective: 24.6953
#> gmm objective: 7.4967
#> gmm objective: 7.8465
#> gmm objective: 7.4219
#> gmm objective: 7.3411
#> gmm objective: 7.2325
#> gmm objective: 7.0497
#> gmm objective: 6.9818
#> gmm objective: 6.9711
#> gmm objective: 6.9695
#> gmm objective: 6.9696
#> gmm objective: 6.9692
#> gmm objective: 6.9633
#> gmm objective: 6.9462
#> gmm objective: 6.8986
#> gmm objective: 6.8301
#> gmm objective: 6.6517
#> gmm objective: 6.3046
#> gmm objective: 5.7187
#> gmm objective: 5.0274
#> gmm objective: 4.6491
#> gmm objective: 4.5752
#> gmm objective: 54557.62
#> gmm objective: 2335.286
#> gmm objective: 90.1735
#> gmm objective: 7.3992
#> gmm objective: 4.667
#> gmm objective: 4.576
#> gmm objective: 4.575
#> gmm objective: 14656.41
#> gmm objective: 601.8347
#> gmm objective: 32.5354
#> gmm objective: 5.863
#> gmm objective: 4.6245
#> gmm objective: 4.5771
#> gmm objective: 4.5758
#> gmm objective: 4.5759
#> gmm objective: 4.5757
#> gmm objective: 4.5756
#> gmm objective: 4.5755
#> gmm objective: 4.5754
#> gmm objective: 4.5754
#> gmm objective: 4.5754
#> gmm objective: 4.5753
#> gmm objective: 4.5753
#> gmm objective: 4.5753
#> gmm objective: 4.5753
#> gmm objective: 4.5753
#> gmm objective: 4.5753
#> gmm objective: 4.5753
#> gmm objective: 4.5752
#> gmm objective: 4.5752
#> gmm objective: 16969.25
#> gmm objective: 603.3225
#> gmm objective: 23.8438
#> gmm objective: 5.2753
#> gmm objective: 4.5966
#> gmm objective: 4.575
#> gmm objective: 4.5752
#> gmm objective: 4.5755
#> gmm objective: 4.5755
#> gmm objective: 4.5754
#> gmm objective: 4.5754
#> gmm objective: 4.5754
#> gmm objective: 4.5753
#> gmm objective: 4.5753
#> gmm objective: 4.5753
#> gmm objective: 4.5753
#> gmm objective: 4.5753
#> gmm objective: 4.5753
#> gmm objective: 4.5753
#> gmm objective: 4.5753
#> gmm objective: 4.5753
#> gmm objective: 4.5752
#> gmm objective: 4.5752
#> ------------------------------------------ 
#> Solver message: Successful convergence 
#> ------------------------------------------ 
#> Final GMM evaluation at optimal parameters: 
#> gmm objective: 4.5744
#>   theta (RC): 0.55 3.29 -0.01 0.09 
#>   theta (demogr.): 2.3 577.44 -0.38 0.83 0 -29.63 0 0 1.27 0 0.05 -1.35 0 11.03 0 0 
#>   inner iterations: 70 
#>   gradient: -0.0605 0.0017 -0.162 -0.0354 -0.0926 -0.0083 -2.2061 0.2945 -0.1468 0.0797 -1.2189 0.2315 2e-04 
#> Using the heteroskedastic asymptotic variance-covariance matrix...

summary(blp_est)
#> 
#> Data information:
#> 
#>   94 market(s) with 2256 products 
#>   25 linear coefficient(s) (24 exogenous coefficients) 
#>   13 non-linear parameters related to random coefficients 
#>   4 demographic variable(s) 
#> 
#> Estimation results:
#> 
#>  Linear Coefficients
#>                          Estimate Std. Error   t value     Pr(>|t|)
#> (Intercept)            -2.5769264  0.8531569 -3.020460 2.523909e-03
#> price                 -62.1403350 14.5135858 -4.281529 1.856137e-05
#> productdummyproduct10   1.9000897  0.6653478  2.855784 4.293071e-03
#> productdummyproduct11   3.6767952  0.6664428  5.517045 3.447468e-08
#> productdummyproduct12   0.2615994  0.2287542  1.143583 2.527967e-01
#> productdummyproduct13   2.3591835  0.2184213 10.801071 3.402135e-27
#> productdummyproduct14   3.8446786  0.6855662  5.608034 2.046376e-08
#> productdummyproduct15   4.2873240  0.6779154  6.324276 2.544228e-10
#> productdummyproduct16   6.0916947  0.6723137  9.060792 1.295068e-19
#> productdummyproduct17   2.6036321  0.6510521  3.999115 6.357976e-05
#> productdummyproduct18   1.4324858  0.6079004  2.356448 1.845065e-02
#> productdummyproduct19   4.3135147  0.6191372  6.966977 3.238237e-12
#> productdummyproduct2    4.8750516  0.6334282  7.696297 1.400664e-14
#> productdummyproduct20   4.1706989  0.6075700  6.864557 6.669789e-12
#> productdummyproduct21   4.9106550  0.6827987  7.191951 6.387201e-13
#> productdummyproduct22   1.7215961  0.5917418  2.909370 3.621574e-03
#> productdummyproduct23   3.2960677  0.6839398  4.819237 1.441085e-06
#> productdummyproduct24   1.8879979  0.7307294  2.583717 9.774202e-03
#> productdummyproduct3    2.3028803  0.2314068  9.951652 2.480314e-23
#> productdummyproduct4    1.3668373  0.5940217  2.300989 2.139225e-02
#> 
#> ...
#> 
#>  5 estimates are omitted. They are available in the LinCoefficients generated by summary.
#> 
#>  Random Coefficients
#>                           Estimate   Std. Error    t value     Pr(>|t|)
#> unobs_sd*(Intercept)   0.551339802   0.16015070  3.4426313 0.0005760842
#> unobs_sd*price         3.285559242   1.30636137  2.5150462 0.0119016778
#> unobs_sd*sugar        -0.005237547   0.01336128 -0.3919943 0.6950624582
#> unobs_sd*mushy         0.091406886   0.18480221  0.4946201 0.6208683092
#> income*(Intercept)     2.303677746   1.19131427  1.9337280 0.0531465808
#> income*price         577.439895043 264.92313045  2.1796507 0.0292833612
#> income*sugar          -0.384035468   0.11965304 -3.2095755 0.0013293115
#> income*mushy           0.826450257   0.77955169  1.0601609 0.2890713878
#> incomesq*price       -29.627526252  13.80993188 -2.1453782 0.0319226238
#> age*(Intercept)        1.268858974   0.62894244  2.0174485 0.0436487312
#> age*sugar              0.051714014   0.02546546  2.0307513 0.0422802273
#> age*mushy             -1.350839886   0.66343728 -2.0361230 0.0417380079
#> child*price           11.025866514   4.11565257  2.6790081 0.0073840611
#> 
#>  Wald Test
#> 126.7789 on  13 DF, p-value: 9.13936413478121e-21 
#> 
#> Computational Details: 
#>   Solver converged with 173 iterations to a minimum at 4.5744 .
#>   Local minima check: NA
#>   stopping criterion outer loop: 1e-06
#>   stopping criterion inner loop: 1e-06
#>   Market shares are integrated with provided_by_user and 20 draws. 
#>   Method for standard errors: heteroskedastic

The arguments in greater detail:

Many of these arguments have default values. In the following setting you see a minimum of necessary arguments with an automatic generation of integration draws and just unobserved heterogeneity. The summary output informs you about the most important default values.

nevo_data2 <- BLP_data(model = nevos_model,
                      market_identifier="cdid",
                     
                      product_identifier = "product_id",
                      productData = productData,
                      integration_method = "MLHS", 
                      integration_accuracy = 20, integration_seed = 213)
#> Mean utility is initialized with 0 because of missing or invalid par_delta argument.

blp_est2 <- estimateBLP( blp_data=nevo_data2, printLevel = 1 )
#> blp_data were prepared with the following arguments:
#> BLP_data(model = nevos_model, market_identifier = "cdid", product_identifier = "product_id", 
#>     productData = productData, integration_accuracy = 20, integration_method = "MLHS", 
#>     integration_seed = 213)
#> Starting a BLP demand estimation with  2256  observations in  94  markets...
#> [integration::method  integration::amountDraws 20 ]
#> [blp::inner_tol 1e-09  blp::inner_maxit 10000 ]
#> [solver::method BFGS  solver::maxit 10000  solver::reltol 1e-06 ]
#> gmm objective: 189.9432
#> gmm objective: Inf [delta contains NaN's] 
#> gmm objective: 38181.19
#> gmm objective: 1730.558
#> gmm objective: 263.4083
#> gmm objective: 192.4396
#> gmm objective: 189.8527
#> gmm objective: 14921.45
#> gmm objective: 794.7065
#> gmm objective: 209.7249
#> gmm objective: 188.7052
#> gmm objective: 299.2339
#> gmm objective: 191.7708
#> gmm objective: 188.5727
#> gmm objective: 188.5122
#> gmm objective: 188.5029
#> gmm objective: 188.5029
#> gmm objective: 201.0545
#> gmm objective: 189.0058
#> gmm objective: 188.5229
#> gmm objective: 188.5037
#> gmm objective: 188.503
#> gmm objective: 188.5029
#> gmm objective: 188.5029
#> ------------------------------------------ 
#> Solver message: Successful convergence 
#> ------------------------------------------ 
#> Final GMM evaluation at optimal parameters: 
#> gmm objective: 188.5029
#>   theta (RC): 0.15 -0.3 0 0.14 
#>   theta (demogr.):  
#>   inner iterations: 61 
#>   gradient: 2e-04 0 -0.0204 1e-04 
#> Using the heteroskedastic asymptotic variance-covariance matrix... 
#> Extremum Check: positive

summary(blp_est2) 
#> 
#> Data information:
#> 
#>   94 market(s) with 2256 products 
#>   25 linear coefficient(s) (24 exogenous coefficients) 
#>   4 non-linear parameters related to random coefficients 
#>   0 demographic variable(s) 
#> 
#> Estimation results:
#> 
#>  Linear Coefficients
#>                          Estimate Std. Error    t value      Pr(>|t|)
#> (Intercept)            -1.7799087  0.2397708  -7.423375  1.141731e-13
#> price                 -30.0963431  1.1024558 -27.299365 4.315817e-164
#> productdummyproduct10   1.8641775  0.2406974   7.744900  9.565674e-15
#> productdummyproduct11   1.7676586  0.2248843   7.860301  3.832126e-15
#> productdummyproduct12  -0.2876883  0.1602658  -1.795070  7.264253e-02
#> productdummyproduct13   2.2491273  0.1504198  14.952338  1.503747e-50
#> productdummyproduct14   1.7844367  0.2282750   7.817049  5.407593e-15
#> productdummyproduct15   2.1642177  0.2255519   9.595210  8.374641e-22
#> productdummyproduct16   3.6877143  0.1808915  20.386330  2.211237e-92
#> productdummyproduct17   0.7941551  0.2367072   3.355010  7.936202e-04
#> productdummyproduct18   0.8806886  0.2350368   3.747024  1.789448e-04
#> productdummyproduct19   1.7652157  0.1863495   9.472608  2.729424e-21
#> productdummyproduct2    2.3645007  0.1771094  13.350512  1.176380e-40
#> productdummyproduct20   2.8136100  0.2308568  12.187687  3.615371e-34
#> productdummyproduct21   2.6849320  0.2328602  11.530232  9.289330e-31
#> productdummyproduct22   0.4781141  0.2306766   2.072659  3.820398e-02
#> productdummyproduct23   1.3807879  0.2257963   6.115192  9.644062e-10
#> productdummyproduct24   2.1776559  0.2358099   9.234795  2.587808e-20
#> productdummyproduct3    1.8011734  0.1491293  12.077934  1.381474e-33
#> productdummyproduct4    0.7697762  0.2296839   3.351459  8.038688e-04
#> 
#> ...
#> 
#>  5 estimates are omitted. They are available in the LinCoefficients generated by summary.
#> 
#>  Random Coefficients
#>                          Estimate Std. Error     t value  Pr(>|t|)
#> unobs_sd*(Intercept)  0.148175983  1.6693199  0.08876428 0.9292692
#> unobs_sd*price       -0.304298641  5.6552127 -0.05380852 0.9570877
#> unobs_sd*sugar        0.004900458  0.1276616  0.03838630 0.9693797
#> unobs_sd*mushy        0.141711614  2.0588204  0.06883146 0.9451238
#> 
#>  Wald Test
#> 0.0141 on  4 DF, p-value: 0.999975209516464 
#> 
#> Computational Details: 
#>   Solver converged with 24 iterations to a minimum at 188.5029 .
#>   Local minima check: positive
#>   stopping criterion outer loop: 1e-06
#>   stopping criterion inner loop: 1e-09
#>   Market shares are integrated with MLHS and 20 draws. 
#>   Method for standard errors: heteroskedastic

Postestimation

Standard Errors

Standard errors can be computed with three options that control for the unobserved characteristic \(\xi\), which consists of \(N\) elements. \(\Omega\) denotes the variance covariance matrix of \(\xi\).

\[\Omega = \begin{pmatrix} \Sigma_1 & 0 & \dots & 0\\ 0 & \Sigma_2 & & 0\\ \vdots & & \ddots & 0\\ 0 & 0 & 0 & \Sigma_M \\ \end{pmatrix}\]

Elasticities

The following code demonstrates the calculation of elasticities.

get_elasticities(blp_data=nevo_data,
                 blp_estimation= blp_est,
                 variable = "price",
                 products = c("cereal_1","cereal_4"),
                 market = "market_2")
#>              cereal_1    cereal_4
#> cereal_1 -1.710335908  0.00543326
#> cereal_4  0.006965469 -2.71765805

The value of the elasticity matrix in row \(j\) and column \(i\) for a variable \(x\), gives the effect of a change in product \(i\)’s characteristic \(x\) on the share of product \(j\).

Modular Examples

Further analysis like incorporating a supply side or performing a merger simulation often requires access to building blocks of the BLP algorithm. The following wrappers insure correct data inputs and access the internal functions of the algorithm.

In the following, you find an example of the contraction mapping and an evaluation of the GMM function at the starting guess:


delta_eval <- getDelta_wrap(  blp_data=nevo_data,
                              par_theta2 = theta_guesses,
                              printLevel = 4 )
#> ----------------------
#>   dist: 0.709015
#>   dist: 0.147383
#>   dist: 0.0669541
#>   dist: 0.0430535
#>   dist: 0.0324573
#>   dist: 0.0263458
#>   dist: 0.02112
#>   dist: 0.0169119
#>   dist: 0.0135664
#>   dist: 0.0109078
#>   dist: 0.00878933
#>   dist: 0.00709574
#>   dist: 0.00573767
#>   dist: 0.00464573
#>   dist: 0.00376578
#>   dist: 0.00305531
#>   dist: 0.00248075
#>   dist: 0.0020155
#>   dist: 0.00163834
#>   dist: 0.00133231
#>   dist: 0.00108382
#>   dist: 0.000881926
#>   dist: 0.000717803
#>   dist: 0.000584333
#>   dist: 0.000475754
#>   dist: 0.000387398
#>   dist: 0.000315485
#>   dist: 0.000256942
#>   dist: 0.000209276
#>   dist: 0.000170463
#>   dist: 0.000138854
#>   dist: 0.000113111
#>   dist: 9.21432e-005
#>   dist: 7.50641e-005
#>   dist: 6.11519e-005
#>   dist: 4.9819e-005
#>   dist: 4.05869e-005
#>   dist: 3.30659e-005
#>   dist: 2.69389e-005
#>   dist: 2.19473e-005
#>   dist: 1.78808e-005
#>   dist: 1.45678e-005
#>   dist: 1.18687e-005
#>   dist: 9.66966e-006
#>   dist: 7.87811e-006
#>   dist: 6.41851e-006
#>   dist: 5.22934e-006
#>   dist: 4.26049e-006
#>   dist: 3.47115e-006
#>   dist: 2.82805e-006
#>   dist: 2.31279e-006
#>   dist: 1.91861e-006
#>   dist: 1.59161e-006
#>   dist: 1.32035e-006
#>   dist: 1.09532e-006
#>   dist: 9.96355e-007


productData$startingGuessesDelta[1:6]
#> [1] -3.944367 -2.845205 -3.958199 -4.934153 -2.425356 -4.086816
delta_eval$delta[1:6]
#> cereal_1_market_1 cereal_2_market_1 cereal_3_market_1 cereal_4_market_1 
#>         -7.069730         -4.357650         -6.056847         -5.887444 
#> cereal_5_market_1 cereal_6_market_1 
#>         -3.501263         -3.079300
delta_eval$counter
#> [1] 56


gmm <- gmm_obj_wrap(  blp_data=nevo_data,
                      par_theta2 = theta_guesses,
                      printLevel = 2)
#> gmm objective: 29.3523
#>   theta (RC): 0.33 2.45 0.02 0.24 
#>   theta (demogr.): 5.48 15.89 -0.25 1.26 0 -1.2 0 0 0.2 0 0.05 -0.81 0 2.63 0 0 
#>   inner iterations: 69 
#>   gradient: 9.8431 0.3168 363.4813 16.3593 10.5995 0.7023 42.4814 -3.4753 13.4895 -2.0292 10.879 1.2831 -0.571 
#> [1] 29.3523

gmm$local_min
#> [1] 29.3523

Printed distances in the contraction mapping are maximum absolute distance between the current vector of mean utilities and the previous one.

For any \(\theta_2\), you can compute predicted shares:

shares <- getShares_wrap(  blp_data=nevo_data,
                           par_theta2 = theta_guesses, printLevel = 4)
shares[1:6]
#> cereal_1_market_1 cereal_2_market_1 cereal_3_market_1 cereal_4_market_1 
#>       0.066138546       0.026031055       0.030931817       0.005596246 
#> cereal_5_market_1 cereal_6_market_1 
#>       0.039475547       0.007812016

The gradient contains two important building blocks as explained in the appendix of Nevo (2001):

Both are used to compute the jacobian and are easy to obtain with the package as the following example demonstrates:


derivatives1 <- dstdtheta_wrap(  blp_data=nevo_data,
                                 cm_input = delta_eval,
                                 market = "market_2")
#> Evaluated at par_theta2:
#>  [1]  0.3302  2.4526  0.0163  0.2441  5.4819 15.8935 -0.2506  1.2650
#>  [9] -1.2000  0.2037  0.0511 -0.8091  2.6342
derivatives2 <- dstddelta_wrap(  blp_data=nevo_data,
                                 cm_input = delta_eval,
                                 market = "market_2")
#> Evaluated at par_theta2:
#>  [1]  0.3302  2.4526  0.0163  0.2441  5.4819 15.8935 -0.2506  1.2650
#>  [9] -1.2000  0.2037  0.0511 -0.8091  2.6342

jacobian_nevo <- getJacobian_wrap(blp_data=nevo_data,
                             par_theta2 = theta_guesses,
                             printLevel = 2)

jacobian_nevo[1:5,1:4]
#>                   unobs_sd*(Intercept) unobs_sd*price unobs_sd*sugar
#> cereal_1_market_1           -0.1029043     0.05148210      -1.689497
#> cereal_2_market_1           -0.1941521     0.03483915      -7.935020
#> cereal_3_market_1           -0.1099606     0.03125065      -1.449870
#> cereal_4_market_1           -0.1341227     0.03963801      -1.451742
#> cereal_5_market_1           -0.2273174     0.04610410      -5.765267
#>                   unobs_sd*mushy
#> cereal_1_market_1    -0.07753320
#> cereal_2_market_1    -0.06694149
#> cereal_3_market_1    -0.13773737
#> cereal_4_market_1    -0.09275354
#> cereal_5_market_1     0.04301055

References

Berry, Steven, James Levinsohn, and Ariel Pakes. 1995. “Automobile Prices in Market Equilibrium.” Econometrica.

Brunner, Daniel, Florian Heiss, Andre Romahn, and Constantin Weiser. 2017. “Reliable Estimation of Random Coefficient Logit Demand Models.” DICE Discussion Paper No 267.

Nevo, Aviv. 2001. “A Practitioner’s Guide to Estimation of Random-Coefficients Logit Models of Demand.” Journal of Economics & Management Strategy.