inst/doc/blp_intro.R

## ----setup, include = FALSE---------------------------------------------------
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)

## -----------------------------------------------------------------------------
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")

## -----------------------------------------------------------------------------
head(productData_cereal)

## -----------------------------------------------------------------------------
demographicData_cereal$income[1:4, 1:5]

demographicData_cereal$incomesq[1:4, 1:5]

demographicData_cereal$age[1:4, 1:5]

demographicData_cereal$child[1:4, 1:5]

## -----------------------------------------------------------------------------
originalDraws_cereal$constant[1:4, 1:5]

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

originalDraws_cereal$price[1:4, 1:5]

originalDraws_cereal$sugar[1:4, 1:5]

originalDraws_cereal$mushy[1:4, 1:5]

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

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

## -----------------------------------------------------------------------------
# before:
theta_guesses_cereal
theta_guesses_cereal[theta_guesses_cereal == 0] <- NA
colnames(theta_guesses_cereal) <- c("unobs_sd", "income", "incomesq", "age", "child")
rownames(theta_guesses_cereal) <- c("(Intercept)", "price", "sugar", "mushy")

# correctly named:
theta_guesses_cereal

## -----------------------------------------------------------------------------
cereal_est <- estimateBLP(
  blp_data = cereal_data,
  par_theta2 = theta_guesses_cereal,
  solver_method = "BFGS", solver_maxit = 1000, solver_reltol = 1e-6,
  standardError = "heteroskedastic",
  extremumCheck = FALSE,
  printLevel = 1
)

summary(cereal_est)

## -----------------------------------------------------------------------------
cereal_data2 <- BLP_data(
  model = nevos_model,
  market_identifier = "cdid",

  product_identifier = "product_id",
  productData = productData_cereal,
  integration_method = "MLHS",
  integration_accuracy = 20, integration_seed = 213
)

cereal_est2 <- estimateBLP(blp_data = cereal_data2, printLevel = 1)

summary(cereal_est2)

## -----------------------------------------------------------------------------
# extract parameters from output
theta1_price <- cereal_est$theta_lin["price", ]
theta2 <- matrix(NA, nrow = 4, ncol = 5)
colnames(theta2) <- c("unobs_sd", "income", "incomesq", "age", "child")
rownames(theta2) <- c("(Intercept)", "price", "sugar", "mushy")
for (i in 1:13) {
  theta2[cereal_est$indices[i, 1], cereal_est$indices[i, 2]] <- cereal_est$theta_rc[i]
}

delta_data <- data.frame(
  "product_id" = cereal_data$parameters$product_id,
  "cdid" = cereal_data$parameters$market_id_char_in,
  "startingGuessesDelta" = cereal_est$delta
)
# always use update_BLP_data() to update data object to maintain consistent data
cereal_data <- update_BLP_data(
  data_update = delta_data,
  blp_data = cereal_data
)

shareObj <- getShareInfo(
  blp_data = cereal_data,
  par_theta2 = theta2,
  printLevel = 1
)

get_elasticities(
  blp_data = cereal_data,
  share_info = shareObj,
  theta_lin = theta1_price,
  variable = "price",
  products = c("cereal_1", "cereal_4"),
  market = "market_2"
)

## -----------------------------------------------------------------------------
delta_eval <- getDelta_wrap(
  blp_data = cereal_data,
  par_theta2 = theta_guesses_cereal,
  printLevel = 4
)

productData_cereal$startingGuessesDelta[1:6]
delta_eval$delta[1:6]
delta_eval$counter

gmm <- gmm_obj_wrap(
  blp_data = cereal_data,
  par_theta2 = theta_guesses_cereal,
  printLevel = 2
)

gmm$local_min

## -----------------------------------------------------------------------------
shareObj <- getShareInfo(
  blp_data = cereal_data,
  par_theta2 = theta_guesses_cereal,
  printLevel = 4
)

shareObj$shares[1:6]

## -----------------------------------------------------------------------------
# market 2:
derivatives1 <- dstdtheta_wrap(
  blp_data = cereal_data,
  par_theta2 = theta_guesses_cereal,
  market = "market_2"
)
derivatives2 <- dstddelta_wrap(
  blp_data = cereal_data,
  par_theta2 = theta_guesses_cereal,
  market = "market_2"
)

jac_mkt2 <- -solve(derivatives2) %*% derivatives1

jac_mkt2[1:5, 1:4]

# all markets
jacobian_nevo <- getJacobian_wrap(
  blp_data = cereal_data,
  par_theta2 = theta_guesses_cereal,
  printLevel = 2
)

jacobian_nevo[25:29, 1:4] # compare to jac_mkt2

## -----------------------------------------------------------------------------
# add owner matix to productData
own_pre <- dummies_cars
colnames(own_pre) <- paste0("company", 1:26)
productData_cars <- cbind(productData_cars, own_pre)

# construct instruments
nobs <- nrow(productData_cars)
X <- data.frame(
  productData_cars$const, productData_cars$hpwt,
  productData_cars$air, productData_cars$mpg, productData_cars$space
)

sum_other <- matrix(NA, nobs, ncol(X))
sum_rival <- matrix(NA, nobs, ncol(X))
sum_total <- matrix(NA, nobs, ncol(X))

for (i in 1:nobs) {
  other_ind <- productData_cars$firmid == productData_cars$firmid[i] &
    productData_cars$cdid == productData_cars$cdid[i] &
    productData_cars$id != productData_cars$id[i]
  rival_ind <- productData_cars$firmid != productData_cars$firmid[i] &
    productData_cars$cdid == productData_cars$cdid[i]
  total_ind <- productData_cars$cdid == productData_cars$cdid[i]

  sum_other[i, ] <- colSums(X[other_ind == 1, ])
  sum_rival[i, ] <- colSums(X[rival_ind == 1, ])
  sum_total[i, ] <- colSums(X[total_ind == 1, ])
}

colnames(sum_other) <- paste0("IV", 1:5)
colnames(sum_rival) <- paste0("IV", 6:10)
productData_cars <- cbind(productData_cars, sum_other, sum_rival)
head(productData_cars)

# To show similarities between implementations of other authors,
# the variable "const" is used, although constants are considered by default.
blps_model <- as.formula("share ~  0 + const + price + hpwt + air + mpg + space |
                        0 + const + hpwt + air + mpg + space |
                        0 + price + const + hpwt + air + mpg |
                        0 + IV1 + IV2 + IV3 + IV4 + IV5 + IV6 + IV7 + IV8 + IV9 + IV10")

car_data <- BLP_data(
  model = blps_model,
  market_identifier = "cdid",
  product_identifier = "id",
  additional_variables = paste0("company", 1:26), # check reordering works
  productData = productData_cars,
  blp_inner_tol = 1e-9,
  blp_inner_maxit = 5000,
  integration_method = "MLHS",
  integration_accuracy = 50, integration_seed = 48
)

## -----------------------------------------------------------------------------
set.seed(121)
theta_guesses <- matrix(rnorm(5))
rownames(theta_guesses) <- c("price", "const", "hpwt", "air", "mpg")
colnames(theta_guesses) <- "unobs_sd"


car_est <- estimateBLP(
  blp_data = car_data,
  par_theta2 = theta_guesses,
  solver_method = "BFGS", solver_maxit = 1000, solver_reltol = 1e-6,
  extremumCheck = FALSE, printLevel = 0
)

summary(car_est)

## -----------------------------------------------------------------------------
## Pre-Merger data
own_pre <- as.matrix(car_data$data$additional_data[, paste0("company", 1:26)])
delta_pre <- car_est$delta
theta1_price <- car_est$theta_lin["price", ]
theta2_price <- car_est$theta_rc["unobs_sd*price"]
theta2_all <- matrix(car_est$theta_rc)
rownames(theta2_all) <- c("price", "const", "hpwt", "air", "mpg")
colnames(theta2_all) <- "unobs_sd"

## update mean utility in data ( always use update_BLP_data() to update data object to maintain consistent data )
delta_data <- data.frame(
  "id" = car_data$parameters$product_id,
  "cdid" = car_data$parameters$market_id,
  "delta" = delta_pre
)
car_data_updated <- update_BLP_data(
  data_update = delta_data,
  blp_data = car_data
)

## -----------------------------------------------------------------------------
## calculate sij
shareObj <- getShareInfo(
  blp_data = car_data_updated,
  par_theta2 = theta2_all,
  printLevel = 0
)

## computation of marginal costs
market_id <- car_data$parameters$market_id
nmkt <- length(unique(market_id))
markups <- numeric(length(market_id))

sh <- shareObj$shares
prices_pre <- car_data$data$X_rand[, "price"]


for (i in 1:nmkt) {
  mkt_ind <- market_id == i
  share_i <- sh[ mkt_ind ]
  price_pre_i <- prices_pre[ mkt_ind ]
  scalar_i <- matrix(1 / share_i) %*% matrix(price_pre_i, nrow = 1)
  elasticities_i <- get_elasticities(
    blp_data = car_data_updated,
    share_info = shareObj,
    theta_lin = theta1_price,
    variable = "price",
    market = i,
    printLevel = 0
  )

  derivatives_i <- elasticities_i / scalar_i # partial derivatives of shares wrt price
  own_pre_i <- own_pre[ mkt_ind, ]
  own_prod_pre_i <- own_pre_i %*% t(own_pre_i) # if element (i,j) equals 1, that means that prod i and j are produced by same firm
  markups[mkt_ind] <- c(-solve(t(derivatives_i) * own_prod_pre_i) %*% share_i)
}
marg_cost <- prices_pre - markups

## -----------------------------------------------------------------------------
# Merger between company 16 and 19 (i.e. GM and Chrysler)
prices_post <- numeric(2217)
own_post <- cbind(
  own_pre[, 1:15],
  own_pre[, 16] + own_pre[, 19],
  own_pre[, 17:18],
  own_pre[, 20:26]
)

## ---- eval = FALSE------------------------------------------------------------
#  foc_bertrand_mkt <- function(par, own_prod, blp_data, mkt, marg_cost, theta_lin, theta_rc) {
#    # argument par: candidate for post merger prices
#    # arguments own_prod, blp_data, mkt, marg_cost, theta_lin, theta_rc: see previous code blocks
#  
#    # post merger updates: update the BLP_data object for market i
#    tmp <- data.frame(
#      "id" = blp_data$parameters$product_id,
#      "cdid" = blp_data$parameters$market_id,
#      "delta" = blp_data$data$delta,
#      "price" = blp_data$data$X_rand[, "price"]
#    )
#  
#    market_ind <- blp_data$parameters$market_id == mkt
#    delta_old <- blp_data$data$delta
#    prices_pre <- blp_data$data$X_rand[, "price"]
#    tmp$price[ market_ind ] <- par
#    tmp$delta[ market_ind ] <- delta_old[market_ind] - prices_pre[market_ind] * theta_lin + par * theta_lin
#  
#  
#    new_blp_data <- update_BLP_data(
#      blp_data = blp_data,
#      data_update = tmp
#    )
#  
#    ShareObj <- getShareInfo(
#      blp_data = new_blp_data,
#      par_theta2 = theta_rc,
#      printLevel = 0
#    )
#  
#    implied_shares <- as.matrix(ShareObj$shares[market_ind])
#  
#    elasticities_post_mkt <- get_elasticities(
#      blp_data = new_blp_data,
#      share_info = ShareObj,
#      theta_lin = theta_lin,
#      variable = "price",
#      market = mkt,
#      printLevel = 0
#    )
#  
#    scalar_mkt <- matrix(1 / implied_shares) %*% matrix(par, nrow = 1)
#    derivatives_mkt <- elasticities_post_mkt / scalar_mkt
#  
#    markups_post <- c(-solve(t(derivatives_mkt) * own_prod) %*% implied_shares)
#    differences <- par - marg_cost[market_ind] - markups_post
#  
#    return(differences)
#  }

## ----eval=FALSE---------------------------------------------------------------
#  library(nleqslv) # to solve non linear first order conditions
#  for (i in 1:nmkt) {
#    mkt_ind <- market_id == i
#    own_post_i <- own_post[ mkt_ind, ]
#    own_prod_post_i <- own_post_i %*% t(own_post_i)
#    price_pre_i <- prices_pre[ mkt_ind ]
#  
#    solution <- nleqslv(
#      x = price_pre_i, foc_bertrand_mkt, # startingguesses: price_pre_i
#      own_prod = own_prod_post_i,
#      blp_data = car_data_updated,
#      mkt = i,
#      marg_cost = marg_cost,
#      theta_lin = theta1_price,
#      theta_rc = theta2_all
#    )
#  
#    prices_post[ market_id == i ] <- solution$x
#  }

Try the BLPestimatoR package in your browser

Any scripts or data that you put into this service are public.

BLPestimatoR documentation built on Dec. 3, 2022, 5:07 p.m.