Nothing
test_that("the indicators group 4 examples are self-contained", {
directory <- rbiogeme_example_path( "indicators")
files <- file.path(
directory,
c(
"indicator_utils.R",
"optima.R",
"plot_b06point_elasticities.R",
"plot_b07cross_elasticities.R",
"plot_b08arc_elasticities.R"
)
)
expect_true(all(file.exists(files)))
for (file in files) expect_silent(parse(file))
})
indicator_group4_r_specification <- function(factor = 1.0, nests = NULL) {
asc_car <- biogeme_beta("asc_car", start = 0)
asc_pt <- biogeme_beta("asc_pt", start = 0, fixed = TRUE)
asc_sm <- biogeme_beta("asc_sm", start = 0)
beta_time_fulltime <- biogeme_beta("beta_time_fulltime", start = 0)
beta_time_other <- biogeme_beta("beta_time_other", start = 0)
beta_dist_male <- biogeme_beta("beta_dist_male", start = 0)
beta_dist_female <- biogeme_beta("beta_dist_female", start = 0)
beta_dist_unreported <- biogeme_beta("beta_dist_unreported", start = 0)
beta_cost <- biogeme_beta("beta_cost", start = 0)
mu_no_car <- biogeme_beta("mu_no_car", start = 1, lower = 1, upper = 2)
time_pt <- variable("TimePT")
time_car <- variable("TimeCar")
marginal_cost_pt <- variable("MarginalCostPT")
cost_car <- variable("CostCarCHF")
distance_km <- variable("distance_km")
male <- variable("Gender") == 1
female <- variable("Gender") == 2
unreported_gender <- variable("Gender") == -1
fulltime <- variable("OccupStat") == 1
not_fulltime <- variable("OccupStat") != 1
marginal_cost_scenario <- marginal_cost_pt * factor
v_pt <- asc_pt + beta_time_fulltime * (time_pt / 200) * fulltime +
beta_time_other * (time_pt / 200) * not_fulltime +
beta_cost * (marginal_cost_scenario / 10)
v_car <- asc_car + beta_time_fulltime * (time_car / 200) * fulltime +
beta_time_other * (time_car / 200) * not_fulltime +
beta_cost * (cost_car / 10)
v_sm <- asc_sm + beta_dist_male * (distance_km / 5) * male +
beta_dist_female * (distance_km / 5) * female +
beta_dist_unreported * (distance_km / 5) * unreported_gender
utilities <- list(`0` = v_pt, `1` = v_car, `2` = v_sm)
if (is.null(nests)) {
nests <- nested_nests(
choice_set = c(0, 1, 2),
nests = list(
nested_nest(mu_no_car, alternatives = c(0, 2), name = "no_car"),
nested_nest(1, alternatives = 1, name = "car")
)
)
}
prob_pt <- nested_probability(utilities, NULL, nests, 0)
prob_car <- nested_probability(utilities, NULL, nests, 1)
prob_sm <- nested_probability(utilities, NULL, nests, 2)
list(
utilities = utilities,
nests = nests,
v_pt = v_pt,
v_car = v_car,
v_sm = v_sm,
log_probability = nested_log_probability(
utilities,
NULL,
nests,
variable("Choice")
),
prob_pt = prob_pt,
prob_car = prob_car,
prob_sm = prob_sm,
direct = list(
pt_time = Derive(prob_pt, "TimePT") * time_pt / prob_pt,
pt_cost = Derive(prob_pt, "MarginalCostPT") * marginal_cost_pt / prob_pt,
car_time = Derive(prob_car, "TimeCar") * time_car / prob_car,
car_cost = Derive(prob_car, "CostCarCHF") * cost_car / prob_car,
sm_distance = Derive(prob_sm, "distance_km") * distance_km / prob_sm
),
cross = list(
pt_time = Derive(prob_pt, "TimeCar") * time_car / prob_pt,
pt_cost = Derive(prob_pt, "CostCarCHF") * cost_car / prob_pt,
car_time = Derive(prob_car, "TimePT") * time_pt / prob_car,
car_cost = Derive(prob_car, "MarginalCostPT") * marginal_cost_pt / prob_car
),
marginal_cost_scenario = marginal_cost_scenario
)
}
native_indicator_group4_specification <- function(factor = 1.0, nests = NULL) {
optima <- reticulate::import("biogeme.data.optima", convert = FALSE)
expressions <- reticulate::import("biogeme.expressions", convert = FALSE)
nests_module <- reticulate::import("biogeme.nests", convert = FALSE)
models <- reticulate::import("biogeme.models", convert = FALSE)
beta <- expressions$Beta
asc_car <- beta("asc_car", 0, NULL, NULL, 0)
asc_pt <- beta("asc_pt", 0, NULL, NULL, 1)
asc_sm <- beta("asc_sm", 0, NULL, NULL, 0)
beta_time_fulltime <- beta("beta_time_fulltime", 0, NULL, NULL, 0)
beta_time_other <- beta("beta_time_other", 0, NULL, NULL, 0)
beta_dist_male <- beta("beta_dist_male", 0, NULL, NULL, 0)
beta_dist_female <- beta("beta_dist_female", 0, NULL, NULL, 0)
beta_dist_unreported <- beta("beta_dist_unreported", 0, NULL, NULL, 0)
beta_cost <- beta("beta_cost", 0, NULL, NULL, 0)
mu_no_car <- beta("mu_no_car", 1, 1, 2, 0)
male <- optima$Gender == 1
female <- optima$Gender == 2
unreported_gender <- optima$Gender == -1
fulltime <- optima$OccupStat == 1
not_fulltime <- optima$OccupStat != 1
marginal_cost_scenario <- optima$MarginalCostPT * factor
v_pt <- asc_pt + beta_time_fulltime * (optima$TimePT / 200) * fulltime +
beta_time_other * (optima$TimePT / 200) * not_fulltime +
beta_cost * (marginal_cost_scenario / 10)
v_car <- asc_car + beta_time_fulltime * (optima$TimeCar / 200) * fulltime +
beta_time_other * (optima$TimeCar / 200) * not_fulltime +
beta_cost * (optima$CostCarCHF / 10)
v_sm <- asc_sm + beta_dist_male * (optima$distance_km / 5) * male +
beta_dist_female * (optima$distance_km / 5) * female +
beta_dist_unreported * (optima$distance_km / 5) * unreported_gender
utilities <- reticulate::dict(`0` = v_pt, `1` = v_car, `2` = v_sm)
if (is.null(nests)) {
no_car <- nests_module$OneNestForNestedLogit(
nest_param = mu_no_car,
list_of_alternatives = reticulate::r_to_py(list(0L, 2L)),
name = "no_car"
)
car <- nests_module$OneNestForNestedLogit(
nest_param = 1.0,
list_of_alternatives = reticulate::r_to_py(list(1L)),
name = "car"
)
nests <- nests_module$NestsForNestedLogit(
choice_set = reticulate::r_to_py(list(0L, 1L, 2L)),
tuple_of_nests = reticulate::tuple(no_car, car)
)
}
prob_pt <- models$nested(utilities, NULL, nests, 0L)
prob_car <- models$nested(utilities, NULL, nests, 1L)
prob_sm <- models$nested(utilities, NULL, nests, 2L)
list(
optima = optima,
models = models,
utilities = utilities,
nests = nests,
v_pt = v_pt,
v_car = v_car,
v_sm = v_sm,
log_probability = models$lognested(utilities, NULL, nests, optima$Choice),
prob_pt = prob_pt,
prob_car = prob_car,
prob_sm = prob_sm,
direct = list(
pt_time = expressions$Derive(prob_pt, "TimePT") * optima$TimePT / prob_pt,
pt_cost = expressions$Derive(prob_pt, "MarginalCostPT") * optima$MarginalCostPT / prob_pt,
car_time = expressions$Derive(prob_car, "TimeCar") * optima$TimeCar / prob_car,
car_cost = expressions$Derive(prob_car, "CostCarCHF") * optima$CostCarCHF / prob_car,
sm_distance = expressions$Derive(prob_sm, "distance_km") * optima$distance_km / prob_sm
),
cross = list(
pt_time = expressions$Derive(prob_pt, "TimeCar") * optima$TimeCar / prob_pt,
pt_cost = expressions$Derive(prob_pt, "CostCarCHF") * optima$CostCarCHF / prob_pt,
car_time = expressions$Derive(prob_car, "TimePT") * optima$TimePT / prob_car,
car_cost = expressions$Derive(prob_car, "MarginalCostPT") * optima$MarginalCostPT / prob_car
),
marginal_cost_scenario = marginal_cost_scenario
)
}
test_that("indicators b06-b08 match native elasticity calculations", {
skip_if_not(
identical(Sys.getenv("RBIOGEME_RUN_INTEGRATION"), "1"),
"Set RBIOGEME_RUN_INTEGRATION=1 to run indicator equivalence tests"
)
skip_if_not(
rbiogeme_test_configure_python(),
"Set RBIOGEME_PYTHON to a compatible native Biogeme interpreter"
)
directory <- rbiogeme_example_path( "indicators")
source(file.path(directory, "optima.R"))
data <- read.delim(
file.path(directory, "optima.dat"),
check.names = FALSE,
stringsAsFactors = FALSE
)
r_database <- optima_database(data, name = "indicators_group4_r")
r_spec <- indicator_group4_r_specification(1.0)
r_model <- biogeme_model(r_database, formula = r_spec$log_probability)
r_directory <- tempfile("rbiogeme-indicators-group4-r-")
native_directory <- tempfile("rbiogeme-indicators-group4-native-")
dir.create(r_directory, recursive = TRUE)
dir.create(native_directory, recursive = TRUE)
original_directory <- getwd()
setwd(r_directory)
on.exit(setwd(original_directory), add = TRUE)
r_fit <- estimate(
r_model,
model_name = "b02estimation_group4_r",
control = biogeme_control(
model_name = "b02estimation_group4_r",
generate_html = FALSE,
generate_yaml = FALSE,
save_iterations = FALSE
)
)
r_simulation_model <- biogeme_model(
r_database,
simulations = list(
weight = variable("normalized_weight"),
`Utility PT` = r_spec$v_pt,
`Utility car` = r_spec$v_car,
`Utility SM` = r_spec$v_sm,
`Prob. car` = r_spec$prob_car,
`Prob. public transportation` = r_spec$prob_pt,
`Prob. slow modes` = r_spec$prob_sm,
direct_elas_pt_time = r_spec$direct$pt_time,
direct_elas_pt_cost = r_spec$direct$pt_cost,
direct_elas_car_time = r_spec$direct$car_time,
direct_elas_car_cost = r_spec$direct$car_cost,
direct_elas_sm_dist = r_spec$direct$sm_distance,
cross_elas_pt_time = r_spec$cross$pt_time,
cross_elas_pt_cost = r_spec$cross$pt_cost,
cross_elas_car_time = r_spec$cross$car_time,
cross_elas_car_cost = r_spec$cross$car_cost
)
)
r_values <- as.data.frame(simulate(r_simulation_model, beta = r_fit), check.names = FALSE)
setwd(native_directory)
native_spec <- native_indicator_group4_specification(1.0)
native_database <- native_spec$optima$read_data()
native_module <- reticulate::import("biogeme.biogeme", convert = FALSE)
native_fit_object <- native_module$BIOGEME(
native_database,
native_spec$log_probability,
generate_html = FALSE,
generate_yaml = FALSE,
save_iterations = FALSE
)
native_fit_object$model_name <- "b02estimation_group4_native"
native_fit <- native_fit_object$estimate()
native_simulator <- native_module$BIOGEME(
native_database,
reticulate::dict(
weight = native_spec$optima$normalized_weight,
`Utility PT` = native_spec$v_pt,
`Utility car` = native_spec$v_car,
`Utility SM` = native_spec$v_sm,
`Prob. car` = native_spec$prob_car,
`Prob. public transportation` = native_spec$prob_pt,
`Prob. slow modes` = native_spec$prob_sm,
direct_elas_pt_time = native_spec$direct$pt_time,
direct_elas_pt_cost = native_spec$direct$pt_cost,
direct_elas_car_time = native_spec$direct$car_time,
direct_elas_car_cost = native_spec$direct$car_cost,
direct_elas_sm_dist = native_spec$direct$sm_distance,
cross_elas_pt_time = native_spec$cross$pt_time,
cross_elas_pt_cost = native_spec$cross$pt_cost,
cross_elas_car_time = native_spec$cross$car_time,
cross_elas_car_cost = native_spec$cross$car_cost
),
generate_html = FALSE,
generate_yaml = FALSE,
save_iterations = FALSE
)
native_values <- reticulate::py_to_r(native_simulator$simulate(
the_beta_values = native_fit$get_beta_values()
))
expect_identical(names(r_values), names(native_values))
expect_equal(
unname(as.matrix(r_values)),
unname(as.matrix(native_values)),
tolerance = 1e-12
)
expect_equal(
unname(coef(r_fit)),
unname(unlist(reticulate::py_to_r(native_fit$get_beta_values()), use.names = FALSE)),
tolerance = 1e-8
)
r_direct <- c(
car_time = sum(r_values$`Prob. car` * r_values$direct_elas_car_time * r_values$weight) /
sum(r_values$`Prob. car` * r_values$weight),
car_cost = sum(r_values$`Prob. car` * r_values$direct_elas_car_cost * r_values$weight) /
sum(r_values$`Prob. car` * r_values$weight),
pt_time = sum(r_values$`Prob. public transportation` * r_values$direct_elas_pt_time * r_values$weight) /
sum(r_values$`Prob. public transportation` * r_values$weight),
pt_cost = sum(r_values$`Prob. public transportation` * r_values$direct_elas_pt_cost * r_values$weight) /
sum(r_values$`Prob. public transportation` * r_values$weight),
sm_distance = sum(r_values$`Prob. slow modes` * r_values$direct_elas_sm_dist * r_values$weight) /
sum(r_values$`Prob. slow modes` * r_values$weight)
)
native_direct <- c(
car_time = sum(native_values$`Prob. car` * native_values$direct_elas_car_time * native_values$weight) /
sum(native_values$`Prob. car` * native_values$weight),
car_cost = sum(native_values$`Prob. car` * native_values$direct_elas_car_cost * native_values$weight) /
sum(native_values$`Prob. car` * native_values$weight),
pt_time = sum(native_values$`Prob. public transportation` * native_values$direct_elas_pt_time * native_values$weight) /
sum(native_values$`Prob. public transportation` * native_values$weight),
pt_cost = sum(native_values$`Prob. public transportation` * native_values$direct_elas_pt_cost * native_values$weight) /
sum(native_values$`Prob. public transportation` * native_values$weight),
sm_distance = sum(native_values$`Prob. slow modes` * native_values$direct_elas_sm_dist * native_values$weight) /
sum(native_values$`Prob. slow modes` * native_values$weight)
)
expect_equal(r_direct, native_direct, tolerance = 1e-12)
# The arc expression is a separate post-estimation scenario using the same
# base nest structure as the native b08 example.
r_after <- indicator_group4_r_specification(1.2, nests = r_spec$nests)
r_arc <- (
r_after$prob_pt - r_spec$prob_pt
) * variable("MarginalCostPT") /
(
r_spec$prob_pt *
(r_after$marginal_cost_scenario - r_spec$marginal_cost_scenario)
)
r_arc_model <- biogeme_model(
r_database,
simulations = list(
weight = variable("normalized_weight"),
`Prob. PT` = r_spec$prob_pt,
direct_elas_pt = r_arc
)
)
r_arc_values <- as.data.frame(simulate(r_arc_model, beta = r_fit), check.names = FALSE)
native_after <- native_indicator_group4_specification(1.2, nests = native_spec$nests)
native_arc_simulator <- native_module$BIOGEME(
native_database,
reticulate::dict(
weight = native_spec$optima$normalized_weight,
`Prob. PT` = native_spec$prob_pt,
direct_elas_pt = (
native_after$prob_pt - native_spec$prob_pt
) * native_spec$optima$MarginalCostPT /
(
native_spec$prob_pt *
(native_after$marginal_cost_scenario - native_spec$marginal_cost_scenario)
)
),
generate_html = FALSE,
generate_yaml = FALSE,
save_iterations = FALSE
)
native_arc_values <- reticulate::py_to_r(native_arc_simulator$simulate(
the_beta_values = native_fit$get_beta_values()
))
expect_equal(
unname(as.matrix(r_arc_values)),
unname(as.matrix(native_arc_values)),
tolerance = 1e-12
)
expect_equal(
sum(
r_arc_values$weight * r_arc_values$`Prob. PT` * r_arc_values$direct_elas_pt /
sum(r_arc_values$weight * r_arc_values$`Prob. PT`),
na.rm = TRUE
),
sum(
native_arc_values$weight * native_arc_values$`Prob. PT` * native_arc_values$direct_elas_pt /
sum(native_arc_values$weight * native_arc_values$`Prob. PT`),
na.rm = TRUE
),
tolerance = 1e-12
)
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.