Business Investor Model

Published

2025-04-22

Overview

This report presents analyses and visualizations of the Business Investor Model described in Railsback & Grimm (2019). The model simulates interactions between businesses and investors to demonstrate fundamental concepts in agent-based modeling (ABM).

Model 10.4.2

Setting the Environment

Figure 10.1.1

Code
data <-
  here::here(
    "data",
    "business-investor-model-10-4-2-figure-10-1-1-table.csv"
  ) |>
  readr::read_csv(
    skip = 6,
    col_types = readr::cols(.default = "c")
  ) |>
  janitor::clean_names() |>
  dplyr::select(
    run_number,
    sensing_radius,
    mean_wealth_of_investors,
    standard_deviation_wealth_of_investors
  ) |>
  dplyr::mutate(
    dplyr::across(
      .cols = dplyr::everything(),
      .fns = as.numeric
    )
  ) |>
  dplyr::summarize(
    mean = mean(mean_wealth_of_investors, na.rm = TRUE),
    sd = mean(standard_deviation_wealth_of_investors, na.rm = TRUE),
    .by = sensing_radius
  )
Code
data
Code
data |>
  ggplot2::ggplot() +
  ggplot2::geom_point(
    mapping = ggplot2::aes(x = sensing_radius, y = mean),
    size = 3,
    shape = 19,
  ) +
  ggplot2::geom_point(
    mapping = ggplot2::aes(x = sensing_radius, y = sd),
    size = 3,
    shape = 8,
  ) +
  ggplot2::scale_x_continuous(breaks = seq(0, 10, 2)) +
  ggplot2::scale_y_continuous(
    breaks = seq(0, 700000, 100000),
    labels = ~ prettyNum(.x, big.mark = ","),
    limits = c(0, 700000)
  ) +
  ggplot2::labs(
    x = "Sensing radius",
    y = "Mean final investor wealth"
  )
#> Warning: Removed 1 row containing missing values or values outside the scale range
#> (`geom_point()`).

Figure 10.1.2

Code
data <-
  here::here(
    "data",
    "business-investor-model-10-4-2-figure-10-1-2-table.csv"
  ) |>
  readr::read_csv(
    skip = 6,
    col_types = readr::cols(.default = "c")
  ) |>
  janitor::clean_names() |>
  dplyr::select(
    run_number,
    step,
    sensing_radius,
    mean_wealth_of_investors
  ) |>
  dplyr::mutate(
    dplyr::across(
      .cols = dplyr::everything(),
      .fns = as.numeric
    )
  ) |>
  dplyr::mutate(
    sensing_radius = factor(sensing_radius, ordered = TRUE)
  ) |>

  dplyr::summarize(
    mean = mean(mean_wealth_of_investors, na.rm = TRUE),
    .by = c("step", "sensing_radius")
  )
Code
data
Code
data |>
  ggplot2::ggplot(ggplot2::aes(x = step, y = mean, color = sensing_radius)) +
  ggplot2::geom_line(linewidth = 1) +
  ggplot2::scale_x_continuous(breaks = seq(0, 50, 10)) +
  ggplot2::scale_y_continuous(
    breaks = seq(0, 700000, 100000),
    labels = ~ prettyNum(.x, big.mark = ","),
    limits = c(0, 700000)
  ) +
  ggplot2::labs(
    x = "Year",
    y = "Mean investor wealth",
    color = "Sensing radius"
  ) +
  brandr::scale_color_brand_d()

Model 11.5

Figure 12.1

Code
data <-
  here::here(
    "data",
    "business-investor-model-11-5-figure-12-1-table.csv"
  ) |>
  readr::read_csv(
    skip = 6,
    col_types = readr::cols(.default = "c")
  ) |>
  janitor::clean_names() |>
  dplyr::select(
    run_number,
    decision_time_horizon,
    mean_wealth_of_investors,
    mean_profit_of_turtles_on_patches,
    mean_risk_of_failing_of_turtles_on_patches,
    total_business_failures
  ) |>
  dplyr::mutate(
    dplyr::across(
      .cols = dplyr::everything(),
      .fns = as.numeric
    )
  ) |>
  dplyr::mutate(
    decision_time_horizon = factor(decision_time_horizon, ordered = TRUE)
  )
Code
data
Code
plot_1 <-
  data |>
  dplyr::summarize(
    mean = mean(mean_wealth_of_investors, na.rm = TRUE),
    sd = stats::sd(mean_wealth_of_investors, na.rm = TRUE),
    .by = decision_time_horizon
  ) |>
  ggplot2::ggplot(
    ggplot2::aes(
      x = decision_time_horizon,
      y = mean,
      ymin = mean - sd,
      ymax = mean + sd
    )
  ) +
  ggplot2::geom_point(shape = 19) +
  ggplot2::geom_errorbar(linewidth = 0.2) +
  ggplot2::scale_x_discrete(breaks = seq(0, 25, 5)) +
  ggplot2::scale_y_continuous(
    breaks = seq(0, 400000, 100000),
    labels = ~ prettyNum(.x, big.mark = ","),
    limits = c(0, 400000)
  ) +
  ggplot2::labs(
    x = "Time horizon (years)",
    y = "Mean final investor wealth"
  )
Code
plot_2 <-
  data |>
  dplyr::summarize(
    mean = mean(total_business_failures, na.rm = TRUE),
    sd = stats::sd(total_business_failures, na.rm = TRUE),
    .by = decision_time_horizon
  ) |>
  ggplot2::ggplot(
    ggplot2::aes(
      x = decision_time_horizon,
      y = mean,
      ymin = mean - sd,
      ymax = mean + sd
    )
  ) +
  ggplot2::geom_point(shape = 19) +
  ggplot2::geom_errorbar(linewidth = 0.2) +
  ggplot2::scale_x_discrete(breaks = seq(0, 25, 5)) +
  ggplot2::scale_y_continuous(limits = c(0, 80)) +
  ggplot2::labs(
    x = "Time horizon (years)",
    y = "Number of failures"
  )
Code
plot_3 <-
  data |>
  dplyr::summarize(
    mean = mean(mean_profit_of_turtles_on_patches, na.rm = TRUE),
    sd = stats::sd(mean_profit_of_turtles_on_patches, na.rm = TRUE),
    .by = decision_time_horizon
  ) |>
  ggplot2::ggplot(
    ggplot2::aes(
      x = decision_time_horizon,
      y = mean,
      ymin = mean - sd,
      ymax = mean + sd
    )
  ) +
  ggplot2::geom_point(shape = 19) +
  ggplot2::geom_errorbar(linewidth = 0.2) +
  ggplot2::scale_x_discrete(breaks = seq(0, 25, 5)) +
  ggplot2::scale_y_continuous(
    breaks = seq(0, 15000, 5000),
    labels = ~ prettyNum(.x, big.mark = ","),
    limits = c(0, 15000)
  ) +
  ggplot2::labs(
    x = "Time horizon (years)",
    y = "Mean annual profit"
  )
Code
plot_4 <-
  data |>
  dplyr::summarize(
    mean = mean(
      mean_risk_of_failing_of_turtles_on_patches,
      na.rm = TRUE
    ),
    sd = stats::sd(
      mean_risk_of_failing_of_turtles_on_patches,
      na.rm = TRUE
    ),
    .by = decision_time_horizon
  ) |>
  ggplot2::ggplot(
    ggplot2::aes(
      x = decision_time_horizon,
      y = mean,
      ymin = mean - sd,
      ymax = mean + sd
    )
  ) +
  ggplot2::geom_point(shape = 19) +
  ggplot2::geom_errorbar(linewidth = 0.2) +
  ggplot2::scale_x_discrete(breaks = seq(0, 25, 5)) +
  ggplot2::scale_y_continuous(
    breaks = seq(0, 0.05, 0.01),
    labels = ~ prettyNum(.x, big.mark = ","),
    limits = c(0, 0.05)
  ) +
  ggplot2::labs(
    x = "Time horizon (years)",
    y = "Mean annual risk"
  )
Code
patchwork::wrap_plots(
  plot_1, plot_2, plot_3, plot_4,
  ncol = 2,
  axes = "collect_x"
)

Figure 12.2

Code
data <-
  here::here(
    "data",
    "business-investor-model-11-5-figure-12-2-table.csv"
  ) |>
  readr::read_csv(
    skip = 6,
    col_types = readr::cols(.default = "c")
  ) |>
  janitor::clean_names() |>
  dplyr::select(
    run_number,
    step,
    decision_time_horizon,
    mean_risk_of_failing_of_turtles_on_patches
  ) |>
  dplyr::mutate(
    dplyr::across(
      .cols = dplyr::everything(),
      .fns = as.numeric
    )
  ) |>
  dplyr::mutate(
    decision_time_horizon = factor(decision_time_horizon, ordered = TRUE)
  ) |>

  dplyr::summarize(
    mean = mean(mean_risk_of_failing_of_turtles_on_patches, na.rm = TRUE),
    .by = c("step", "decision_time_horizon")
  )
Code
data
Code
data |>
  ggplot2::ggplot(
    ggplot2::aes(
      x = step,
      y = mean,
      color = decision_time_horizon
      # linetype = decision_time_horizon
    )
  ) +
  ggplot2::geom_line(linewidth = 1) +
  ggplot2::scale_x_continuous(breaks = seq(0, 50, 10)) +
  ggplot2::scale_y_continuous(limits = c(0, 0.06)) +
  ggplot2::labs(
    x = "Time step (years)",
    y = "Mean annual risk",
    color = "Time horizon (years)"
    # linetype = "Time horizon (years)"
  ) +
  brandr::scale_color_brand_d()

License

This report is licensed under CC0 1.0 Universal, placing it in the public domain. You may freely copy, modify, distribute, and use this work, even for commercial purposes, without permission or attribution.

References

Railsback, S. F., & Grimm, V. (2019). Agent-based and individual-based modeling: A practical introduction (2nd ed.). Princeton University Press.