Skip to content

Commit 1e43a46

Browse files
Merge pull request #155 from RPVote/precinct_extraction
extract_rxc_precinct function
2 parents 72bab16 + 76e3533 commit 1e43a46

6 files changed

Lines changed: 213 additions & 2 deletions

File tree

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package: eiCompare
22
Type: Package
33
Title: Compares Different Ecological Inference Methods
4-
Version: 3.0.4
4+
Version: 3.0.5
55
Authors@R:
66
c(person(given = "Loren",
77
family = "Collingwood",

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export(ei_rc_good_table)
1515
export(ei_reg_bayes_conf_int)
1616
export(ei_rxc)
1717
export(elect_algebra)
18+
export(extract_rxc_precinct)
1819
export(fips_extract)
1920
export(get_multi_barreled_surnames)
2021
export(get_special_character_surnames)

NEWS.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1+
# eiCompare 3.0.5
2+
3+
## added function 11/11/25
4+
5+
* included extract_rxc_precinct() function to extract precinct level estimates from ei_rxc()
6+
17
# eiCompare 3.0.4
28

39
## Package changes
4-
10+
* added rpv_normalize() function
11+
* removed wru dependency
512
* incorporated rpv_coef_plot() and rpv_toDF() functions from eiExpand package
613
* edited ei_iter() to have flexible CI parameters (default is 0.95) using bayestestR for calculation and updated column naming, and to use reproducible parallel processing (.inorder=TRUE)
714
* edited ei_rxc() with repdocuible parallel processing and changed column naming to fit ei_iter()

R/extract_rxc_precinct.R

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#' Extract Precinct-Level Estimates from ei.MD.bayes Object
2+
#'
3+
#' Extracts precinct-specific ecological inference estimates from ei_rxc() output.
4+
#' Uses exact string matching to handle variation column names
5+
#'
6+
#' @param eivote `ei_rxc()` output object containing `stat_objects`
7+
#' @param cand_cols Character vector of candidate column names (e.g., `c("pct_cand_A", "pct_cand_B")`)
8+
#' @param race_cols Character vector of race column names (e.g., `c("pct_black", "pct_white")`)
9+
#' @param dat Original data frame used in `ei_rxc()` call
10+
#' @param precinct_id Column name for precinct identifier (must exist in `dat`)
11+
#'
12+
#' @return Data frame with precinct IDs and race×candidate estimate columns
13+
#'
14+
#' @details
15+
#' The function extracts `md_out$draws$Beta` from the `ei_rxc()` output, which contains
16+
#' MCMC draws for each precinct-race-candidate combination. Beta column names follow
17+
#' the format `"beta.race_name.cand_name.precinct_idx"`. The function computes posterior
18+
#' means across MCMC iterations for each precinct.
19+
#'
20+
#' Output columns follow `expand.grid(cand, race)` ordering, with column names formatted
21+
#' as `paste0(race, cand)` (e.g., `"pct_blackpct_cand_A"`).
22+
#'
23+
#' @examples
24+
#' \donttest{
25+
#'
26+
#' # library(eiCompare)
27+
#' # data(gwinnett_ei)
28+
#' #
29+
#' # gwinnett_ei$precinct <- 1:nrow(gwinnett_ei)
30+
#' #
31+
#' # eivote <- ei_rxc( #this will take some time
32+
#' # data = gwinnett_ei,
33+
#' # cand_cols = c("kemp", "abrams", "metz"),
34+
#' # race_cols = c("white", "black", "other"),
35+
#' # totals_col = "turnout",
36+
#' # seed = 12345
37+
#' #)
38+
#'
39+
#' # # Extract precinct-level estimates
40+
#' # precinct_results <- extract_rxc_precinct(
41+
#' # eivote = eivote,
42+
#' # cand_cols = c("kemp", "abrams"),
43+
#' # race_cols = c("white", "black", "other"),
44+
#' # dat = gwinnett_ei,
45+
#' # precinct_id = "precinct"
46+
#' #)
47+
#'
48+
#' #head(precinct_results)
49+
#' }
50+
#'
51+
#' @export
52+
extract_rxc_precinct <- function(eivote, cand_cols, race_cols, dat, precinct_id) {
53+
54+
# Extract md_out object from ei_rxc wrapper
55+
eiMD_object <- eivote$stat_objects[[1]]
56+
57+
# Extract Beta matrix (MCMC iterations × beta parameters)
58+
Beta <- eiMD_object$draws$Beta
59+
60+
# Check that precinct_id column exists in dat
61+
if(!precinct_id %in% colnames(dat)) {
62+
stop(paste0("Column '", precinct_id, "' not found in dat. ",
63+
"Available columns: ", paste(colnames(dat), collapse = ", ")))
64+
}
65+
66+
n_precincts <- nrow(dat)
67+
beta_colnames <- colnames(Beta)
68+
69+
# Initialize result matrix (precincts × race-candidate combinations)
70+
result_matrix <- matrix(NA,
71+
nrow = n_precincts,
72+
ncol = length(race_cols) * length(cand_cols))
73+
74+
# Loop through race-candidate combinations and extract precinct estimates
75+
col_idx <- 1
76+
for(race in race_cols) {
77+
for(cand in cand_cols) {
78+
79+
# Build expected prefix pattern for exact matching
80+
# Format: beta.race.cand.precinct_number
81+
expected_prefix <- paste0("beta.", race, ".", cand, ".")
82+
83+
# Find Beta columns matching this race-candidate pair
84+
matching_cols <- grep(paste0("^", gsub("\\.", "\\\\.", expected_prefix)),
85+
beta_colnames,
86+
value = FALSE)
87+
88+
# Validation - should have exactly n_precincts matches
89+
if(length(matching_cols) != n_precincts) {
90+
stop(paste0("Column matching error for race='", race, "', cand='", cand,
91+
"': found ", length(matching_cols), " columns but expected ",
92+
n_precincts, " precincts"))
93+
}
94+
95+
# Extract precinct indices and reorder to match dat row order
96+
precinct_nums <- sub(expected_prefix, "", beta_colnames[matching_cols])
97+
precinct_order <- order(as.numeric(precinct_nums))
98+
matching_cols_ordered <- matching_cols[precinct_order]
99+
100+
# Calculate mean across MCMC iterations for each precinct
101+
result_matrix[, col_idx] <- colMeans(Beta[, matching_cols_ordered])
102+
col_idx <- col_idx + 1
103+
}
104+
}
105+
106+
# Create column names (race + candidate, matching expand.grid order)
107+
col_names_df <- expand.grid(cand = cand_cols, race = race_cols)
108+
col_names <- paste0(col_names_df$race, col_names_df$cand)
109+
110+
# Convert to data frame with column names
111+
result_df <- as.data.frame(result_matrix)
112+
colnames(result_df) <- col_names
113+
114+
# Attach precinct IDs from original data as first column
115+
result_df <- cbind(dat[, precinct_id, drop = FALSE], result_df)
116+
117+
return(result_df)
118+
}

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,27 @@
1313

1414
## News
1515

16+
# eiCompare 3.0.5
17+
18+
## New function
19+
20+
* included extract_rxc_precinct() function to extract precinct level estimates from ei_rxc()
21+
22+
# eiCompare 3.0.4
23+
24+
## Package changes
25+
* added add_rpv_normalize() function
26+
* removed wru dependency
27+
* incorporated rpv_coef_plot() and rpv_toDF() functions from eiExpand package
28+
* edited ei_iter() to have flexible CI parameters (default is 0.95) using bayestestR for calculation and updated column naming, and to use reproducible parallel processing (.inorder=TRUE)
29+
* edited ei_rxc() with repdocuible parallel processing and changed column naming to fit ei_iter()
30+
* Fixed summary.eiCompare() print behavior
31+
* Added viridis to imports for color visualiztion and updated RoxygenNote to 7.3.2
32+
33+
### eiCompare 3.0.3
34+
35+
Updated
36+
1637
### eiCompare 3.0.2
1738

1839
#### Package changes

man/extract_rxc_precinct.Rd

Lines changed: 64 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)