Skip to contents

This vignette defines the core concepts of Value of Information (VOI) analysis and walks through how the vira package computes VOI step-by-step.

If you are new to VOI, start with the Key Concepts and Glossary below. If you want to see how the code is structured, skip to The VOI Pipeline Walkthrough.


The core question: is it worth collecting more data?

Every field ecologist eventually faces this situation: you have a management decision to make, you are uncertain about something important, and someone suggests running a survey or study first. The question is simple — is the information worth the cost?

Value of Information (VOI) analysis answers that question formally. The key idea is:

Information is only worth collecting if it could change what you would do. If you would make the same decision regardless of the survey result, the survey has zero value — no matter how uncertain you are.


Glossary

Terms used throughout these vignettes

EVPI (Expected Value of Perfect Information) The most you should ever pay for a study. Specifically: the average improvement in outcome you would get if you somehow knew the true state of the world before deciding, rather than making your best guess now. Think of it as the ceiling on any study’s worth.

EVSI (Expected Value of Sample Information) Like EVPI, but for a real, imperfect study. Always ≤\le EVPI because real studies are not perfect.

Property 1 — dominant action A situation where one action is best (or tied for best) regardless of the true state of the world. Example: “protect the parcel” is the right call whether the species is present or absent, because protection never makes things worse. When a dominant action exists, information cannot change what you should do, so EVPI = 0.

Property 2 — no safe fallback A situation where every action is the wrong choice in at least one state of the world. Example: fishing the estuary is wrong when the fish are offshore, and fishing offshore is wrong when they are in the estuary. No choice is “safe”. Here, uncertainty is genuinely costly and EVPI can be large.

Risk aversion A preference for a certain, moderate outcome over a gamble with the same expected value. A risk-averse manager would rather guarantee 500 fish than have a 50/50 chance of 200 or 800 fish (which averages to 500). We describe the degree of risk aversion with a single number γ\gamma (gamma):

  • γ=0\gamma = 0 : risk-neutral (only expected value matters)
  • γ>0\gamma > 0 : risk-averse (bad outcomes are penalised extra)
  • γ<0\gamma < 0 : risk-seeking (drawn to variance, like a gambler)

Certainty equivalent (CE) The guaranteed outcome a risk-averse manager considers just as good as an uncertain gamble. If a manager would accept 430 certain fish rather than face a 50/50 gamble of 200 or 800 fish, their certainty equivalent for that gamble is 430. EVPI under risk aversion is always expressed as the gain in CE from getting perfect information.

CRRA utility The specific mathematical formula used to model risk aversion in these vignettes. You do not need to know the formula. Think of it as a dial: turning γ\gamma up makes the manager increasingly averse to bad outcomes. The vignettes use it to ask “what if the manager cared more about avoiding disasters — how does that change the value of information?”


Running example: the chytrid frog decision table

Every case study in this package is built around a decision table (or outcome matrix): a grid showing what outcome results from each action under each possible state of the world.

We use the translocation problem from Canessa et al. (2015). A manager must decide whether to translocate frogs to a new site. The outcome depends on whether chytrid fungus is present at the destination.

V <- matrix(
  c(55,  135,   # translocate: bad if chytrid present, good if absent
    100, 100),  # no action:   safe regardless
  nrow = 2, byrow = TRUE,
  dimnames = list(
    c("translocate", "no_action"),
    c("chytrid_present", "chytrid_absent")
  )
)
p_prior <- c(0.5, 0.5)   # 50 % prior probability chytrid is present

The outcome matrix V is the central object. Row = action, column = state of the world:

V
#>             chytrid_present chytrid_absent
#> translocate              55            135
#> no_action               100            100

“No action” produces 100 frogs regardless of chytrid status — it is the safe fallback. “Translocate” is better when chytrid is absent (135 vs 100) but worse when chytrid is present (55 vs 100).

The prior probability that chytrid is present is 50 %. A risk-neutral manager computes:

  • EV(translocate) = 0.5 × 55 + 0.5 × 135 = 95 frogs
  • EV(no action) = 0.5 × 100 + 0.5 × 100 = 100 frogs

So the manager chooses “no action” without a test.


Notation

Throughout these vignettes we follow the ecological VOI convention of Runge et al. (2011) and Bennett et al. (2018):

Symbol Meaning R variable
ss A state of the world (e.g., chytrid present / absent) column of V
p(s)p(s) Prior probability of state ss p_prior
xkx_k The kk-th possible survey outcome row index kk
p(s∣xk)p(s \mid x_k) Posterior probability of state ss after observing outcome kk p_posterior[k, ]
p(xk)p(x_k) Marginal probability of observing outcome kk (before the survey) p_outcome[k]

The EVSI formula is:

EVSI=∑kp(xk)⋅maxaEU(a∣xk)−maxaEU(a)\mathrm{EVSI} = \sum_k p(x_k) \cdot \max_a \mathrm{EU}\bigl(a \mid x_k\bigr) \;-\; \max_a \mathrm{EU}(a)

p(xk)p(x_k) is the weight on each post-survey world; it is the marginal (pre-survey) probability that the survey returns result kk. In the health-economics VOI literature this quantity is written p(y)p(y) with yy as the data variable; both conventions are in common use.


The VOI Pipeline Walkthrough

vira computes Value of Information (VOI) as a sequence of small, inspectable steps rather than a single opaque function. This lets you:

  • Inspect intermediate results — see posteriors, chosen actions, and utility distributions before they collapse to a single number.
  • Swap in any component — use a custom objective function, a risk-averse utility, or a non-standard summariser without rewriting everything else.
  • Understand what drives VOI — by seeing where the certainty/uncertainty gap opens up, you can reason about why information is (or is not) valuable.

The six pipeline functions and what they compute:

Step Function Input → Output
0 voi_problem() Raw outcomes + beliefs → problem object
1 transform_to_utility() Outcomes → utility units
2 optimize_action() Utilities → best action per scenario
3 calculate_utility_dist() Best actions → per-outcome utility values
4 summarize_utility() Per-outcome utilities → scalar EU
5 transform_to_values() Scalar EU → certainty equivalents
6 calculate_value_info() CE certainty − CE uncertainty = VOI

Let’s walk through each step in R.

Step 0 — voi_problem(): declare the problem

voi_problem() packages the outcome matrix and prior beliefs into a single voi_problem object. For EVPI (perfect information), no posterior is needed — the function fills in the identity matrix automatically (each experiment outcome reveals exactly one state with certainty).

problem <- voi_problem(V, p_prior)
#> ℹ VOI problem: 2 actions, 2 states, 2 experiment outcomes.

At this point the object contains:

str(problem)
#> List of 4
#>  $ V          : num [1:2, 1:2] 55 100 135 100
#>   ..- attr(*, "dimnames")=List of 2
#>   .. ..$ : chr [1:2] "translocate" "no_action"
#>   .. ..$ : chr [1:2] "chytrid_present" "chytrid_absent"
#>  $ p_prior    : num [1:2] 0.5 0.5
#>  $ p_posterior: num [1:2, 1:2] 1 0 0 1
#>  $ p_outcome  : num [1:2] 0.5 0.5
#>  - attr(*, "class")= chr "voi_problem"
  • V — the (2 × 2) outcome matrix you supplied.
  • p_prior — the prior, c(0.5, 0.5).
  • p_posterior — filled automatically for EVPI: a 2 × 2 identity matrix where row 1 means “chytrid is definitely present” and row 2 means “chytrid is definitely absent”.
  • p_outcome — marginal probability of each experiment outcome, p(xk)p(x_k), set equal to p_prior for EVPI, so c(0.5, 0.5).

Key concept. EVPI imagines an oracle that tells you the true state before you decide. Each row of p_posterior is the belief you’d hold if the oracle gave you that message. For EVPI those rows are degenerate (one-hot); for EVSI they are the Bayesian updates from a real survey.

Step 1 — transform_to_utility(): map outcomes to preferences

This step applies a utility function to every cell of V, producing U. Under risk neutrality (the default) outcomes equal utilities, so U = V.

problem <- problem |> transform_to_utility()
#> ℹ Utility: identity (risk-neutral).
problem$U
#>             chytrid_present chytrid_absent
#> translocate              55            135
#> no_action               100            100

The matrix is unchanged because we have not specified a utility function. If we later pass a CRRA utility function here, this is the only step that changes — everything downstream is identical.

Why does this step exist? Risk preferences operate on outcomes before they are averaged. A 50 % chance of 55 frogs and a 50 % chance of 135 frogs is not equivalent to 95 frogs for a risk-averse manager. Separating utility transformation from probability-weighting makes the distinction explicit.

Step 2 — optimize_action(): find the best action in each scenario

For every row of p_posterior (i.e. every possible experiment outcome), this step asks: “If I held these beliefs, which action would I choose?”

It also finds the best action under the prior — the choice you’d make without any survey.

problem <- problem |> optimize_action()
#> ℹ Optimizing: action changes in 1/2 experiment outcomes.
cat("Best action without survey:  ", problem$a_uncertainty, "\n")
#> Best action without survey:   2 2
cat("Best action after outcome 1: ", problem$a_certainty[1],
    "(chytrid present)\n")
#> Best action after outcome 1:  2 (chytrid present)
cat("Best action after outcome 2: ", problem$a_certainty[2],
    "(chytrid absent)\n")
#> Best action after outcome 2:  1 (chytrid absent)

Action index 2 = “no action”; action index 1 = “translocate”. So:

  • Without a survey — we choose “no action” (EV: 0.5×100 + 0.5×100 = 100 > 0.5×55 + 0.5×135 = 95).
  • If told chytrid is present — still “no action” (100 > 55).
  • If told chytrid is absent — switch to “translocate” (135 > 100).

The survey is worth something because it changes our action in one out of the two scenarios. If both posteriors led to the same action, VOI would be zero.

A formatted summary of this is available via decision_table():

decision_table(problem)
#> 
#> ── Decision table ──
#> 
#>       action chytrid_present chytrid_absent EV_prior best_action?
#>  translocate              55            135       95             
#>    no_action             100            100      100          YES

Step 3 — calculate_utility_dist(): evaluate chosen actions across states

Now we know which action to take in each scenario. This step evaluates the expected utility of that action under the corresponding posterior beliefs.

For experiment outcome kk (with posterior 𝐩k\mathbf{p}_k and chosen action aka_k):

Ucert(k)=∑sU[ak,s]⋅pk[s]U_{\text{cert}}^{(k)} = \sum_s U[a_k, s] \cdot p_k[s]

And for the no-survey action a0a_0:

Uunc(k)=∑sU[a0,s]⋅pk[s]U_{\text{unc}}^{(k)} = \sum_s U[a_0, s] \cdot p_k[s]

problem <- problem |> calculate_utility_dist()
#> ℹ Utility dist: certainty mean = 117.5, uncertainty mean = 100.
cat("EU under certainty  (per outcome):", problem$U_certainty, "\n")
#> EU under certainty  (per outcome): 100 135
cat("EU under uncertainty (per outcome):", problem$U_uncertainty, "\n")
#> EU under uncertainty (per outcome): 100 100
  • Outcome 1 (chytrid present, prob = 0.5): both actions give the same EU because “no action” is optimal in both the with- and without-survey scenario — no gain here.
  • Outcome 2 (chytrid absent, prob = 0.5): certainty gives 135 (translocate) vs uncertainty gives 100 (no action) — this is where the gap opens up.

Step 4 — summarize_utility(): collapse to a scalar

This step takes the per-outcome EU vectors and weights them by p_outcome — the marginal probability p(xk)p(x_k) of each experiment outcome — to produce a single number for each condition.

EUcert=∑kUcert(k)⋅p(xk)\mathrm{EU}_{\text{cert}} = \sum_k U_{\text{cert}}^{(k)} \cdot p(x_k)EUunc=∑kUunc(k)⋅p(xk)\mathrm{EU}_{\text{unc}} = \sum_k U_{\text{unc}}^{(k)} \cdot p(x_k)

problem <- problem |> summarize_utility()
#> ℹ Summary: EU certainty = 117.5, EU uncertainty = 100.
cat("EU certainty:   ", problem$EU_certainty, "\n")
#> EU certainty:    117.5
cat("EU uncertainty: ", problem$EU_uncertainty, "\n")
#> EU uncertainty:  100
cat("Raw gap (utility units):", problem$EU_certainty - problem$EU_uncertainty, "\n")
#> Raw gap (utility units): 17.5

The raw gap is already 17.5. Under risk neutrality, utility = value, so this is also the EVPI in frog units.

Step 5 — transform_to_values(): back to outcome units (certainty equivalents)

Under risk neutrality this step is a no-op: EV = EU. Under risk aversion, the inverse utility function converts the scalar EU back into the certainty equivalent — the guaranteed frog count the manager would accept in place of the gamble.

problem <- problem |> transform_to_values()
#> ℹ Inverse transform: identity (utility = value units).
cat("CE certainty:   ", problem$EV_certainty, "frogs\n")
#> CE certainty:    117.5 frogs
cat("CE uncertainty: ", problem$EV_uncertainty, "frogs\n")
#> CE uncertainty:  100 frogs

Step 6 — calculate_value_info(): subtract to get VOI

VOI=EVcert−EVunc\mathrm{VOI} = \mathrm{EV}_{\text{cert}} - \mathrm{EV}_{\text{unc}}

problem <- problem |> calculate_value_info()
#> ✔ VOI = 17.5 (original units (certainty equivalent)).
cat("EVPI:", problem$value_info, problem$voi_units, "\n")
#> EVPI: 17.5 original units (certainty equivalent)

The EVPI of 17.5 frogs matches Canessa et al. (2015). It is worth paying up to 17.5 frogs-worth of survey cost to learn the disease status before deciding.


Full pipeline at a glance

All six steps can be chained without storing intermediate objects:

voi_problem(V, p_prior) |>
  transform_to_utility()      |>   # Step 1: outcomes → utilities
  optimize_action()           |>   # Step 2: best action per scenario
  calculate_utility_dist()    |>   # Step 3: EU of chosen actions
  summarize_utility()         |>   # Step 4: collapse to scalar
  transform_to_values()       |>   # Step 5: back to outcome units
  calculate_value_info()           # Step 6: certainty gap = VOI
#> ℹ VOI problem: 2 actions, 2 states, 2 experiment outcomes.
#> ℹ Utility: identity (risk-neutral).
#> ℹ Optimizing: action changes in 1/2 experiment outcomes.
#> ℹ Utility dist: certainty mean = 117.5, uncertainty mean = 100.
#> ℹ Summary: EU certainty = 117.5, EU uncertainty = 100.
#> ℹ Inverse transform: identity (utility = value units).
#> ✔ VOI = 17.5 (original units (certainty equivalent)).
#> 
#> ── VOI Problem ──
#> 
#> • Actions: 2
#> • States: 2
#> • Experiment outcomes: 2
#> • Best action (no survey): no_action
#> • VOI (original units (certainty equivalent)): 17.5

Why risk aversion matters for VOI

A risk-neutral manager cares only about the average outcome. A risk-averse manager also cares about variability — they dislike bad outcomes more than they enjoy equally good ones.

This changes the value of information in two important ways:

When there is a safe fallback (Property 1): A risk-averse manager locks onto the safe action even more strongly. Because “no action” guarantees 100 frogs, a risk-averse manager prefers it even more than a risk-neutral one would. Information becomes less valuable as risk aversion increases — the manager is happy with the safe floor and has no need to gamble.

When there is no safe fallback (Property 2): Every action exposes the manager to bad outcomes in some states. Risk aversion makes those bad outcomes feel even worse — so the manager is even more eager to learn the true state before deciding. Information becomes more valuable as risk aversion increases.

Pipeline under risk aversion

Under risk aversion, only Steps 1 and 5 in the pipeline change. Step 1 bends the utility scale; Step 5 applies the inverse to recover certainty equivalents. Steps 2–4 and 6 are identical:

rp <- risk_preference("CRRA", param = 1, val_min = 0, val_max = 200,
                       outcome_name = "frogs", maximize = TRUE)
fns <- use_risk_preference(rp)

voi_problem(V, p_prior) |>
  transform_to_utility(fns$utility)     |>   # Step 1: CRRA utility
  optimize_action()                     |>   # Steps 2-4: unchanged
  calculate_utility_dist()              |>
  summarize_utility()                   |>
  transform_to_values(fns$inv_utility)  |>   # Step 5: back to frogs via inverse
  calculate_value_info()
#> ℹ VOI problem: 2 actions, 2 states, 2 experiment outcomes.
#> ℹ Utility: values mapped through utility function.
#> ℹ Optimizing: action changes in 1/2 experiment outcomes.
#> ℹ Utility dist: certainty mean = -0.5431, uncertainty mean = -0.6931.
#> ℹ Summary: EU certainty = -0.5431, EU uncertainty = -0.6931.
#> ℹ Inverse transform: CE certainty = 116.1895, CE uncertainty = 100.
#> ✔ VOI = 16.1895 (original units (certainty equivalent)).
#> 
#> ── VOI Problem ──
#> 
#> • Actions: 2
#> • States: 2
#> • Experiment outcomes: 2
#> • Best action (no survey): no_action
#> • VOI (original units (certainty equivalent)): 16.1895

The EVPI under risk aversion is lower than 17.5 frogs because the safe “no action” choice (100 frogs regardless of state) is increasingly attractive to a risk-averse manager, leaving less room for information to help.


What changes for EVSI and EVPXI?

The pipeline is identical. Only voi_problem() changes:

VOI type p_posterior p_outcome
EVPI identity matrix (auto-filled) p_prior (auto-filled)
EVSI Bayesian posteriors from survey Survey outcome probs p(xk)p(x_k)
EVPXI Posteriors from partial information source Source outcome probs p(xk)p(x_k)

Once voi_problem() is constructed, Steps 1–6 are unchanged. See vignettes 3 (EVSI) and 4 (EVPXI) for fully worked examples.


Where to go next

Vignette Scenario Key lesson
1. Key Concepts and the VOI Pipeline Translocation under uncertainty Introduction to the core concepts and 6-step R pipeline
2. Calculating EVPI Chytrid frog translocation Fast EVPI calculation using calculate_evpi(); sensitivity to risk aversion
3. Calculating EVSI Chytrid frog translocation EVSI pipeline with imperfect surveys; comparison to EVPI
4. EVPXI — Runge et al. (2011) Whooping crane management Partial EVPI per hypothesis; ranking which uncertainties drive the decision
5. Elicitation, Sensitivity, and Validation Risk preference elicitation Bayesian adaptive elicitation; how elicitation uncertainty propagates into VOI; robot-agent calibration
6. Bennett et al. (2018) Species protection (single parcel and multispecies) Property 1 per unit; budget forces Property 2; extinction risk under risk aversion
7. Validation against Davis et al. (2019) TURF fishery social-ecological model EVPXI pipeline validated against published MATLAB results; machine-epsilon agreement
8. Mäntyniemi et al. (2009) Herring stock recruitment Property 2: no safe option →\rightarrow large EVPI, grows with risk aversion