Monte Carlo Simulation: Jin and Vasserman (2021)
3/24/2023
1 Generate Data for Choice Model
First we generate data in the following procedure.
- Generate \(\lambda_{imt}\). \(\lambda_{imt}\) is one of the most significant variables that represents consumer’s risk (observable for consumers but not econometrician)
- Generate choice in \(t = 0\) according to the choice model. In \(t = 0\), consumers have four options: the firm with and without monitoring, competitor 1 and 2.
- Generate realization of cost (claims count, severity and monitoring score) in \(t = 0\) according to the cost model.
- Generate choice in \(t = 1\) based on renewal prices realized by claims and scores. Now consumers have three options: the firm, competitor 1 and 2.
1.1 Generate \(\lambda\)
- The rate parameter, \(\lambda_{imt}\) of Poisson distributed claims count, has mean \(\mu_{\lambda, imt}\) and an additive error \(\varepsilon_{\lambda, i}\) which is log-normally distributied with spread \(\sigma_{\lambda}\)
- We assume that \(\mu_{\lambda, imt} = \theta_{\lambda1}x_{1, imt} + \cdots + \theta_{\lambda4}x_{4, imt}\)
rm(list = ls())
<- 10^3
N <- 1
T <- 4
D
# set the seed
set.seed(1)
## True Parameters
<- 0.1
sigma_lambda <- c(-3, -0.5, 1, -1, 1, -0.5)
theta_lambda
## Covariates
<- rep(0, 4)
mu_x_t0 <- rep(0, 4)
mu_x_t1 <- diag(0.25, 4)
sigma_x
<- mvrnorm(N, mu_x_t0, sigma_x)
X_t0 <- 0.5*X_t0 + 0.5*mvrnorm(N, mu_x_t1, sigma_x)
X_t1
<- X_t0 %>%
X rbind(X_t0) %>%
rbind(X_t1) %>%
rbind(X_t1)
colnames(X) <- c(paste("x", 1:4, sep = "_"))
<- expand.grid(i = 1:N, m = 0:1, t = 0:1) %>%
X_lambda ::as_tibble() %>%
tibblecbind(X)
## mu_lambda
<- X_lambda %>%
mu_lambda ::mutate(mu_lambda = theta_lambda[1]
dplyr+ theta_lambda[2]*x_1 + theta_lambda[3]*x_2
+ theta_lambda[4]*x_3 + theta_lambda[5]*x_4
+ theta_lambda[6]*ifelse(m == 1 & t == 0, 1, 0))
## epsilon_lambda
<- expand.grid(i = 1:N) %>%
epsilon_lambda ::as_tibble() %>%
tibble::mutate(epsilon_lambda = rnorm(N, 0, sigma_lambda))
dplyr
## lambda
<- mu_lambda %>%
lambda ::left_join(epsilon_lambda, by = c("i")) %>%
dplyr::mutate(lambda = exp(mu_lambda + epsilon_lambda)) dplyr
- The distribution of generated \(\lambda\) is as follows
## Visualize
<- lambda %>%
g_lambda ggplot(aes(x = lambda)) +
geom_histogram(binwidth = 0.01)
plot(g_lambda)
- We also check opt-in drivers tend to have lower risk
## Visualize lambda and monitoring opt-in
<- lambda %>%
g_lambda_monitoring ::mutate(monitoring = ifelse(m == 1, "Monitored", "Unmonitored")) %>%
dplyrggplot(aes(x = monitoring, y = lambda)) +
geom_boxplot() +
scale_y_continuous(limits=c(0, 0.1))
plot(g_lambda_monitoring)
1.2 Generate (Expectation of) Monitoring Score and Out-of-Pocket
- Then, we generate expectation of monitoring score and severity, which is necessary for expectation of out-of-pocket, \(e(C, y_{d})\) and renewal price multiplier \(R_{idt}(C, s)\).
- Score \(s\) follows log-normal distribution with an individual mean \(\mu_{s, i}\) and precision \(\sigma_{s}\)
- Assuming that \(\mu_{s, i} = \theta_{s, 1} + \theta_{s, 2}\log(\lambda_{i}) + \theta_{s, 3}x_{1, i} + \theta_{s, 4}x_{2, i}\), the expectation of score is given by \(\exp(\mu_{s, i} + \frac{\sigma_{s}^{2}}{2})\)
- Out-of-pocket (OOP), is that consumers have to pay when an accident occurs due to deductible and/or policy limit
- We assume that every plan has only policy limit
- In the paper, for simplicity, consumers only consider the possibility of one claim occurrence per term in expectation
- Then, expectation of OOP is given by:
\[ \begin{align} E[e(C, y_{d})] &= \Pr(C = 1) \times \int_{y_{0}}^{\infty} (x - y_{0})a_{l} l_{0}^{a_{l}} x^{- a_{l} - 1}dx \\ &= \lambda \exp(-\lambda) \times \left\{ \frac{l_{0}^{a_{l}}}{a_{l} - 1} y_{0}^{-a_{l} + 1} \right\} \end{align} \]
## Generate expectations of score
<- c(-3, -0.5, 2, 1)
theta_score <- 0.25
sigma_score
<- lambda %>%
score ::filter(t == 0, m == 1) %>%
dplyr::mutate(mu_score = theta_score[1] + theta_score[2]*log(lambda)
dplyr+ theta_score[3]*x_1 + theta_score[4]*x_2,
E_score = exp(mu_score + sigma_score^2 / 2)) %>%
::select(i, m, t, mu_score, E_score)
dplyr
## Visualize Score
<- score %>%
g_mu_score ggplot(aes(x = mu_score)) +
geom_histogram(binwidth = 0.1)
plot(g_mu_score)
## Expectation of Out-of-Pocket
<- 1000
policy_limit <- 500
l0 <- 2.5
a_l
<- lambda %>%
E_oop ::mutate(prob_C1 = lambda * exp(-lambda),
dplyrE_oop = prob_C1 * (l0^(a_l)/(a_l - 1))*policy_limit^(-a_l + 1),
E_oop_sq = prob_C1 * ((2 * l0^(a_l)) / ((a_l - 1) * (a_l - 1))) * policy_limit^(-a_l + 2)) %>%
::select(i, m, t, E_oop, E_oop_sq)
dplyr
## Visualize OOP
<- E_oop %>%
g_oop ggplot(aes(x = E_oop)) +
geom_histogram(binwidth = 0.5)
plot(g_oop)
1.3 Generate Choice in \(t = 0\)
- In the paper, consumer’s realized choice utility is modeled as follows:
\[ \begin{align} u_{idt}(C, s) &= u_{\gamma}(w_{it} + h_{idt}(C, s)) \\ h_{idt}(C, s) &= -p_{idt} - \mathbf{1}_{d, t-1} \cdot \psi_{idt} - e(C, y_{d}) - p_{idt} \cdot R_{idt}(C, s) \\ \text{where } \psi_{idt} &= \mathbf{1}_{d, t-1} \cdot \eta_{0} + \mathbf{1}_{f_{d}, t-1} \cdot \eta_{it} + \mathbf{1}_{m_{d}} \cdot \mathbf{1}_{t=0} \cdot \xi_{it} \end{align} \]
- At each period \(t\), consumer \(i\) chooses \(d\) so as to maximize her expected utility:
\[ \begin{align} d_{it} &= \mathop{\rm argmax}\limits_{d \in D_{it}} \left\{ v_{idt} + \varepsilon_{idt} \right\} \\ \text{where } v_{idt} &= \mathbb{E}_{C, s}[u_{idt}(C, s)] = \mathbb{E}[h_{idt}] -\frac{\gamma}{2}\mathbb{E}[h_{idt}^{2}] \end{align} \]
- Thus, we start with generating each component of \(h_{idt}\).
<- c(15, 3, 2, 3, -2)
price_par_t0_d1 <- c(15, 3, 2, 3, -2)
price_par_t0_d2 <- c(15, 1, 3, 2, -2)
price_par_t0_d3 <- c(15, 4, 5, 1, -2)
price_par_t0_d4
<- function(choice_t0, D, price_par_t0){
price_gen_d <- choice_t0 %>%
output ::filter(d == D) %>%
dplyr::mutate(price =
dplyr1] +
price_par_t0[2]*x_1 +
price_par_t0[3]*x_2 +
price_par_t0[4]*x_3 +
price_par_t0[5]*m +
price_par_t0[rnorm(N, 1, 1)) %>%
::select(i, d, t, m, f, price)
dplyr
}
## Generate Price
<- function(choice_t0,
price_gen_t0
price_par_t0_d1, price_par_t0_d2,
price_par_t0_d3, price_par_t0_d4){
<- price_gen_d(choice_t0, 1, price_par_t0_d1) %>%
price rbind(price_gen_d(choice_t0, 2, price_par_t0_d2)) %>%
rbind(price_gen_d(choice_t0, 3, price_par_t0_d3)) %>%
rbind(price_gen_d(choice_t0, 4, price_par_t0_d4))
<- choice_t0 %>%
output ::left_join(price, by = c("i", "d", "t", "m", "f"))
dplyr
return(output)
}
## Generate Prior Firm
<- expand.grid(i = 1:N) %>%
prior_firm_t0 ::as_tibble() %>%
tibble::mutate(prior_firm = sample(1:3, size = N, replace = T, prob = c(0.4, 0.35, 0.25)))
dplyr
## True Parameters
### Inertia
<- c(5, 1, 2, 2)
eta_f <- c(1, -2.5)
xi
### Renewal Price
<- c(20, 5, 3)
alpha_m0 <- c(20, 5, 3, -1)
alpha_m1 <- 20
beta
### Risk Aversion
<- 10^(-4)
risk_aversion
## Generate Choice
<- expand.grid(i = 1:N, d = 1:D, t = 0) %>%
choice_t0 ::as_tibble() %>%
tibble::mutate(m = ifelse(d == 1, 1, 0),
dplyrf = dplyr::case_when(
<= 2 ~ 1,
d == 3 ~ 2,
d == 4 ~ 3)) %>%
d ::left_join(lambda, by = c("i", "m", "t")) %>%
dplyr::left_join(score, by = c("i", "m", "t")) %>%
dplyr::left_join(E_oop, by = c("i", "m", "t")) %>%
dplyrprice_gen_t0(price_par_t0_d1, price_par_t0_d2, price_par_t0_d3, price_par_t0_d4) %>%
::left_join(prior_firm_t0, by = c("i")) %>%
dplyr::mutate(inertia = eta_f[1] + eta_f[2]*x_1 + eta_f[3]*x_2 + eta_f[4]*x_3,
dplyrmonitoring_disutility = xi[1] + xi[2]*log(lambda),
demand_friction = ifelse(f == prior_firm, 0, inertia) +
ifelse(d == 1, monitoring_disutility, 0)) %>%
::mutate(E_R_s = ifelse(m == 0,
dplyr1] + alpha_m0[2]*x_1 + alpha_m0[3]*x_2) / beta,
(alpha_m0[1] + alpha_m1[2]*x_1 + alpha_m1[3]*x_2 + alpha_m1[4]*E_score) / beta),
(alpha_m1[E_R_s_sq = E_R_s / beta,
E_R_C = 0.98 * exp(-lambda) + 1.2 * (1 - exp(-lambda)),
E_R_C_sq = 0.98^2 * exp(-lambda) + 1.2^2 * (1 - exp(-lambda)),
E_renewal_price = price * E_R_s * E_R_C,
E_renewal_price_sq = price^2 * E_R_s_sq * E_R_C_sq) %>%
::mutate(h = - price - demand_friction - E_oop - E_renewal_price,
dplyrh_sq = price^2 - demand_friction^2 + E_oop_sq + E_renewal_price_sq
+ 2*price*demand_friction + 2*price*E_oop + 2*price*E_renewal_price
+ 2*demand_friction*E_oop + 2*demand_friction*E_renewal_price
+ 2*E_oop*E_renewal_price)
# draw idiosyncratic shocks
<- evd::rgev(dim(choice_t0)[1])
e_t0
<- cbind(choice_t0, e_t0) %>%
choice_t0 ::mutate(v = h - (risk_aversion / 2)*h_sq,
dplyru = v + e_t0) %>%
::group_by(i, t) %>%
dplyr::mutate(choice = ifelse(u == max(u), 1, 0)) %>%
dplyr::ungroup()
dplyr
summary(choice_t0)
<- choice_t0 %>%
summarize_choice ::group_by(d) %>%
dplyr::summarise(share = mean(choice))
dplyr
summarize_choice
- The figure shows generated prices of each plan.
- Monitoring plan provided by firm 1 is slightly lower than other plans, representing the opt-in discount
## Visualize Price in t = 0
<- choice_t0 %>%
g_price_t0 ::mutate(plan = dplyr::case_when(d == 1 ~ "Firm1 Monitoring",
dplyr== 2 ~ "Firm1 No Monitoring",
d == 3 ~ "Firm2",
d == 4 ~ "Firm3")) %>%
d ggplot(aes(x = price, fill = plan)) +
geom_histogram(position = "identity", alpha = 0.6, binwidth = 0.25)
plot(g_price_t0)
- The following figure shows the expectation of \(R_{idt}(s)\), which implies that monitored consumers tend to have smaller expected renewal prices, incentivizing them to opt-in
## Visualize E_R_s in t = 0
<- choice_t0 %>%
g_E_R_s_t0 ::filter(f == 1) %>%
dplyr::mutate(plan = dplyr::case_when(m == 1 ~ "Monitoring",
dplyr== 0 ~ "No Monitoring")) %>%
m ggplot(aes(x = E_R_s, fill = plan)) +
geom_histogram(position = "identity", alpha = 0.6, binwidth = 0.01)
plot(g_E_R_s_t0)
1.4 Generate Realization of Cost in \(t = 0\)
- Since consumer’s choice is path-dependent, i.e. price in next period depends on claims and monitoring score, we need to generate realization of costs in \(t = 0\)
- Claim occurs according to Poisson distribution with mean \(\lambda\)
- The monitoring score \(s\) is drawn according to a log-normal distribution with mean \(\mu_{s, i}\) and precision \(\sigma_{s}\)
- Note that we do not need to generate realization of severity since it does not affect consumer’s choice in \(t = 1\)
## Claims Count
<- choice_t0 %>%
cost_t0 ::filter(choice == 1) %>%
dplyr::mutate(claims = rpois(N, lambda = lambda))
dplyr
## Severity
# max_claims <- max(cost_t0$claims)
#
# claims_mat <- matrix(rep(0, N * max_claims), nrow = N)
# severity <- matrix(l0*runif(N * max_claims)^(-1/a_l), nrow = N)
#
# colnames(severity) <- paste("sev_", 1:max_claims, sep = "")
#
# cost_t0 <- cbind(cost_t0, severity)
## Monitoring Score
<- cost_t0 %>%
cost_t0 ::mutate(score = rlnorm(N, mu_score, sigma_score),
dplyrscore = ifelse(m == 1, score, 1),
log_score = log(score)) %>%
::select(i, claims, matches("sev."), score, log_score) dplyr
## Visualize realized claims count
<- cost_t0 %>%
g_realized_claims_count ggplot(aes(x = claims)) +
geom_histogram(binwidth = 0.5)
plot(g_realized_claims_count)
- The following figure shows realized monitoring scores (in logarithm) for opt-in drivers
## Visualize realized score
<- cost_t0 %>%
g_realized_score ::filter(score != 1) %>%
dplyrggplot(aes(x = log_score)) +
geom_histogram(binwidth = 0.25)
plot(g_realized_score)
1.5 Generate Choice in \(t = 1\)
## Prior Choice and Firm
<- choice_t0 %>%
prior_firm_t1 ::filter(choice == 1) %>%
dplyr::mutate(prior_choice = d * choice,
dplyrprior_firm = f * choice) %>%
::select(i, prior_choice, prior_firm)
dplyr
### Prior Price
<- choice_t0 %>%
prior_price_t1 ::left_join(prior_firm_t1, by = c("i")) %>%
dplyr::mutate(prior_price = price,
dplyrflg = dplyr::case_when(prior_choice == 1 & d != 2 ~ 1,
> 1 & d != 1 ~ 1,
prior_choice TRUE ~ 0)) %>%
::filter(flg == 1) %>%
dplyr::select(i, f, prior_price) %>%
dplyr::arrange(i)
dplyr
## Choice in t = 1
<- expand.grid(i = 1:N, d = 1:(D - 1), t = 1) %>%
choice_t1 ::as_tibble() %>%
tibble::mutate(m = 0,
dplyrf = d) %>%
::left_join(prior_firm_t1, by = c("i")) %>%
dplyr::left_join(prior_price_t1, by = c("i", "f")) %>%
dplyr::left_join(lambda, by = c("i", "m", "t")) %>%
dplyr::left_join(E_oop, by = c("i", "m", "t")) %>%
dplyr::left_join(cost_t0, by = c("i")) %>%
dplyr::mutate(gamma_alpha = ifelse(score == 1,
dplyr1] + alpha_m0[2]*x_1 + alpha_m0[3]*x_2,
alpha_m0[1] + alpha_m1[2]*x_1 + alpha_m1[3]*x_2 + alpha_m1[4]*score)) %>%
alpha_m1[::mutate(R_s = rgamma(N * (D - 1), gamma_alpha, beta),
dplyrR_C = ifelse(claims == 0, 0.98, 1.2),
price = prior_price * R_s * R_C) %>%
::mutate(inertia = eta_f[1] + eta_f[2]*x_1 + eta_f[3]*x_2 + eta_f[4]*x_3,
dplyrdemand_friction = ifelse(d == prior_firm, 0, inertia)) %>%
::mutate(E_R_s = ifelse(m == 0,
dplyr1] + alpha_m0[2]*x_1 + alpha_m0[3]*x_2) / beta,
(alpha_m0[1] + alpha_m1[2]*x_1 + alpha_m1[3]*x_2 + alpha_m1[4]*E_score) / beta),
(alpha_m1[E_R_s_sq = E_R_s / beta,
E_R_C = 0.98 * exp(-lambda) + 1.2 * (1 - exp(-lambda)),
E_R_C_sq = 0.98^2 * exp(-lambda) + 1.2^2 * (1 - exp(-lambda)),
E_renewal_price = price * E_R_s * E_R_C,
E_renewal_price_sq = price^2 * E_R_s_sq * E_R_C_sq) %>%
::mutate(h = - price - demand_friction - E_oop - E_renewal_price,
dplyrh_sq = price^2 - demand_friction^2 + E_oop_sq + E_renewal_price_sq
+ 2*price*demand_friction + 2*price*E_oop + 2*price*E_renewal_price
+ 2*demand_friction*E_oop + 2*demand_friction*E_renewal_price
+ 2*E_oop*E_renewal_price) %>%
::arrange(i)
dplyr
# draw idiosyncratic shocks
<- evd::rgev(dim(choice_t1)[1])
e_t1
<- cbind(choice_t1, e_t1) %>%
choice_t1 ::mutate(v = h - (risk_aversion / 2)*h_sq,
dplyru = v + e_t1) %>%
::group_by(i, t) %>%
dplyr::mutate(choice = ifelse(u == max(u), 1, 0)) %>%
dplyr::ungroup()
dplyr
summary(choice_t1)
<- choice_t1 %>%
summarize_choice_t1 ::group_by(d) %>%
dplyr::summarise(share = mean(choice))
dplyr
summarize_choice_t1
## Visualize Price in t = 1
<- choice_t1 %>%
g_price_t1 ::mutate(plan = dplyr::case_when(d == 1 ~ "Firm1",
dplyr== 2 ~ "Firm2",
d == 3 ~ "Firm3"),
d prior_plan = dplyr::case_when(prior_choice == 1 ~ "Firm1 Monitoring",
== 2 ~ "Firm1 No Monitoring",
prior_choice == 3 ~ "Firm2",
prior_choice == 4 ~ "Firm3")) %>%
prior_choice ggplot(aes(x = price, fill = prior_plan)) +
geom_histogram(position = "identity", alpha = 0.6, binwidth = 0.25)
plot(g_price_t1)
## Visualize Realized R_s in t = 1
<- choice_t1 %>%
g_R_s_t1 ::mutate(plan = dplyr::case_when(d == 1 ~ "Firm1",
dplyr== 2 ~ "Firm2",
d == 3 ~ "Firm3"),
d prior_plan = dplyr::case_when(prior_choice == 1 ~ "Firm1 Monitoring",
== 2 ~ "Firm1 No Monitoring",
prior_choice == 3 ~ "Firm2",
prior_choice == 4 ~ "Firm3")) %>%
prior_choice ggplot(aes(x = R_s, fill = prior_plan)) +
geom_histogram(position = "identity", alpha = 0.4, binwidth = 0.025)
plot(g_R_s_t1)
1.6 Merge Choice Data
<- choice_t0 %>%
df_t0 ::select(i, d, t, m, f, x_1, x_2, x_3, x_4, price, prior_firm, choice)
dplyr<- choice_t1 %>%
df_t1 ::select(i, d, t, m, f, x_1, x_2, x_3, x_4, price, prior_firm, choice, claims, score, R_s, R_C)
dplyr
<- dplyr::bind_rows(df_t0, df_t1) %>%
df ::arrange(t, i, d) dplyr