ei_summary_random: Compute ecological inference summaries with random voter...

View source: R/ei_summary_random.R

ei_summary_randomR Documentation

Compute ecological inference summaries with random voter aggregation

Description

Randomly assigns voters to artificial units and computes ecological inference summaries, ignoring the geographic boundaries of real precincts. This allows assessing how sensitive the results are to the specific way voters are grouped — a concern known in the literature as the Modifiable Areal Unit Problem (MAUP).

Usage

ei_summary_random(
  elections,
  data = NULL,
  source = NULL,
  format = c("lphom", "eipack"),
  n_units = NULL,
  unit_size = NULL,
  size_range = NULL,
  seed = NULL
)

Arguments

elections

Character vector of race codes (e.g. c("PRE", "USS")). All codes must be keys in election_catalog.See ei_summary().

data

Optional data.frame. If provided, must contain columns COUNTY, PRECINCT, and all codes in elections. If NULL (default), data are loaded automatically via get_election_data().

source

Character string or NULL. Data source override; see get_county_data(). Ignored when data is provided.

format

Character. Output format for the margins element:

  • "lphom" (default): a named list of data.frames, one per race. Compatible with lphom and related packages.

  • "eipack": a single wide data.frame with all races side by side (columns named ⁠<RACE>_<OPTION>⁠, e.g. PRE_R, PRE_D).

n_units

Integer or NULL. Number of random units to create. NULL (default) uses the same number of precincts as in the data. When unit_size or size_range is also supplied, see the precedence rules in the Details section.

unit_size

Integer or NULL. Fixed number of voters per unit. If N (the number of eligible voters) is not an exact multiple of unit_size, a smaller residual unit containing the remaining voters is created. Takes precedence over size_range and n_units; both are ignored with a warning if unit_size is specified.

size_range

Integer vector of length 2, c(min, max), or NULL. When used alone (without n_units), units are created by drawing sizes uniformly from ⁠[min, max]⁠ until all N voters are assigned; the last unit may be smaller than min. When used with n_units, the effective interval is the largest symmetric range around the required mean (N / n_units) that fits within ⁠[min, max]⁠; the last unit absorbs the residual. Takes precedence over n_units. Ignored when unit_size is specified.

seed

Integer or NULL. Random seed passed to set.seed() before shuffling voters, enabling reproducible results. NULL (default) uses the current random state.

Details

The total number of votes for each option is identical to that returned by ei_summary() on the same data — only the distribution of votes across units changes.

The function returns a standard ei_summary object, fully compatible with to_lphom(), to_eipack(), and subset_elections(). The randomisation parameters are stored in meta$random for reproducibility and auditing.

To repeat the randomisation n times (e.g. for a sensitivity analysis), call the function inside lapply(), varying seed each time:

results <- lapply(1:100, function(i)
  ei_summary_random(c("PRE", "USS"), data = d, seed = i))

Value

An object of class "ei_summary" with the same structure as ei_summary(), which contains the components: margins, joint_precinct, joint_total and meta; see ei_summary() for details. To document the randomisation the meta component includes, in addition to the fields elections, counties, n_precincts, n_voters, opt_levels, format, precinct_info, created_at the field random, with the following components:

method

Character string describing the aggregation method used and the resulting unit structure.

n_units

Integer. Number of random units created.

unit_sizes

Integer vector of length n_units. Size (number of voters) of each unit. Always sums to meta$n_voters.

seed

The seed supplied to seed, or NULL if none.

n_units_arg

Value of the n_units argument as supplied by the user.

unit_size_arg

Value of the unit_size argument as supplied by the user.

size_range_arg

Value of the size_range argument as supplied by the user.

Argument precedence

When multiple sizing arguments are supplied simultaneously, they are resolved in this order (highest to lowest priority):

  1. unit_size — fixed size per unit; n_units and size_range are ignored with a warning.

  2. size_range — random sizes within bounds; if n_units is also supplied, the effective sampling interval is the largest symmetric interval around the required mean (N / n_units) that fits within ⁠[min, max]⁠. The last unit absorbs the residual and may fall slightly outside the effective interval. A warning is issued if the required mean falls outside ⁠[min, max]⁠, in which case all units are assigned approximately equal sizes.

  3. n_units — number of units; sizes are drawn proportionally from the real precinct size distribution.

  4. Default (no sizing argument) — same number of units as real precincts; sizes match the real precinct size distribution; voters are randomly shuffled across units.

Universe

As in ei_summary(), only voters non-NA in all elections simultaneously are included (the intersection universe). The randomisation is applied to this universe, not to the full dataset. The meta$n_voters field of the returned object always refers to this intersection count.

Relationship to ei_summary()

ei_summary_random() produces an object of the same class and structure as ei_summary(), and is fully compatible with to_lphom(), to_eipack(), and subset_elections(). The only difference is that voters are grouped into random units rather than real (geographic) precincts. To compare random and real aggregations directly, run both functions on the same data object:

d    <- get_election_data(c("PRE", "STS35"))
real <- ei_summary(c("PRE", "STS35"), data = d)
rnd  <- ei_summary_random(c("PRE", "STS35"), data = d, seed = 1)

See Also

ei_summary(), subset_elections(), to_lphom(), to_eipack(), get_election_data()

Examples

# Using the built-in example dataset
obj <- ei_summary(c("PRE", "USS"), data = example_ballots)
print(obj)
summary(obj)


# Default: same number and size distribution as real precincts
obj <- ei_summary_random(c("PRE", "STS35"), seed = 42)

# 200 units with sizes proportional to the real precinct distribution
obj <- ei_summary_random(c("PRE", "STS35"), n_units = 200, seed = 42)

# Fixed size of 500 voters per unit (residual unit if N not divisible)
obj <- ei_summary_random(c("PRE", "STS35"), unit_size = 500, seed = 42)

# Random size between 200 and 800 voters per unit
obj <- ei_summary_random(c("PRE", "STS35"),
                         size_range = c(200, 800), seed = 42)

# 200 units with random sizes between 100 and 600
obj <- ei_summary_random(c("PRE", "STS35"),
                         n_units = 200, size_range = c(100, 600),
                         seed = 42)

# Sensitivity analysis: 100 random aggregations
results <- lapply(1:100, function(i)
  ei_summary_random(c("PRE", "USS"), seed = i))



eiballots documentation built on Sept. 26, 2026, 5:06 p.m.