| Title: | Calculate vs-SOVs and SOVs for Assemblies with D-Dimensional Voting |
| Version: | 1.0.3 |
| Description: | Calculates vote-specific and traditional Shapley-Owen power indices (vs-SOVs and SOVs) for spatial voting games in one to four dimensions. Evaluates voter influence through an a posteriori analysis of relative preferences. Supports weighted voting and various voting thresholds. Compatible with ideal point estimates from NOMINATE, Optimal Classification, and 'MCMCpack'. The method builds on Bibina and Dougherty (2025) <doi:10.2139/ssrn.6324519>. |
| License: | MIT + file LICENSE |
| Encoding: | UTF-8 |
| RoxygenNote: | 7.3.3 |
| Imports: | dplyr, openxlsx, tibble, tidyr |
| Suggests: | testthat (≥ 3.0.0), withr |
| Config/testthat/edition: | 3 |
| URL: | https://github.com/spatial-voting-lab/sov |
| BugReports: | https://github.com/spatial-voting-lab/sov/issues |
| NeedsCompilation: | no |
| Packaged: | 2026-03-31 19:09:49 UTC; emmab |
| Author: | Keith Dougherty [aut], Emma Bibina [aut, cre] |
| Maintainer: | Emma Bibina <emma.bibina@uga.edu> |
| Repository: | CRAN |
| Date/Publication: | 2026-04-04 09:10:02 UTC |
Traditional Shapley-Owen Values
Description
This function calculates traditional Shapley-Owen values (SOVs) from package estimated inputs.
Usage
sov(
estimates = NULL,
av = NULL,
weight_nom = FALSE,
absolute = FALSE,
vw = NULL,
q = NULL,
pr = 0.5001,
nPoints1 = 360,
nPoints2 = 360,
dec = 3,
out_dir = NULL,
print_results = FALSE
)
Arguments
estimates |
Estimation results from oc, wnom, or MCMCpack. |
av |
Attendance vector coded attend=1, "not attend"=NA. |
weight_nom |
If TRUE use weights estimated from wnom output, if FALSE use vector of 1's. ... For wnom only. |
absolute |
If TRUE, q is a scalar of yeas needed to pass proposal. If FALSE, pr is the proportion of yeas need to pass a proposal among voters attending. |
vw |
Vector of weights for each voter (default 1 for each member, applied later). |
q |
The quota of yeas need to pass a proposal under absolute k-majority rule (scalar, default absolute.maj(vw) applied later). |
pr |
The proportion of yea votes needed to pass a proposal among voters attending for simple k-majority rule (scalar, default: 0.5001). |
nPoints1 |
The number of points sampled along the azimuth (the first spherical coordinate the azimuth). Sampled from 0 to 2*pi. |
nPoints2 |
The number of points sampled along the inclination (the second and third spherical coordinate). Sampled from 0 to 2*pi. |
dec |
The number of decimal places reported for vs-sovs. |
out_dir |
The path to the output directory. This is used only when |
print_results |
If TRUE, print results to an excel file in out_dir; if FALSE, don't print results. In both cases, results are returned. |
Value
A list with data frames containing ideal points, number of pivots, name of pivots for each direction sampled, and SOVs for each voter.
Examples
## --- Ideals: 5 voters in 2D -----------------------------------------------
i1 <- c( 0.7, 0.7)
i2 <- c(-0.5, 0.5)
i3 <- c(-0.7, -0.7)
i4 <- c( 0.5, -0.5)
i5 <- c( 0.0, 0.0)
ideals <- rbind(i1, i2, i3, i4, i5)
rownames(ideals) <- paste0("i", 1:5)
colnames(ideals) <- c("coord1D","coord2D")
# Build a minimal WNOM-like 'estimates' object for sov() identification
spreads <- rbind(c( 1, 0), c( 0, 1), c(-1, 0))
midpoints <- rbind(c( 0.10, 0.00), c( 0.00, -0.10), c( 0.05, 0.00))
rownames(spreads) <- rownames(midpoints) <- paste0("RC", 1:3)
colnames(spreads) <- colnames(midpoints) <- c("dim1","dim2")
leg <- data.frame(
coord1D = ideals[, 1],
coord2D = ideals[, 2],
GMP = 0.5,
CC = 0.5,
row.names = rownames(ideals),
check.names = FALSE
)
rc <- data.frame(
GMP = rep(0.5, nrow(midpoints)),
midpoint1D = midpoints[, 1],
midpoint2D = midpoints[, 2],
spread1D = spreads[, 1],
spread2D = spreads[, 2],
row.names = rownames(midpoints),
check.names = FALSE
)
weights <- c(1, 1)
estimates <- list(legislators = leg, rollcalls = rc, weights = weights)
class(estimates) <- "nomObject"
# Attendance: exclude i5
av <- c(1, 1, 1, 1, NA); names(av) <- rownames(ideals)
vw <- rep(1, nrow(ideals))
out_sov <- sov(
estimates = estimates,
av = av,
absolute = FALSE,
pr = 0.5001,
vw = vw,
nPoints1 = 72,
nPoints2 = 72,
dec = 3,
print_results = FALSE
)
out_sov$pivot_summary
out_sov$pivot_by_angle
### Plotting (2D): label with SOVs (no normals needed here) ###
if (interactive()) {
sov_labels2d <- setNames(out_sov$pivot_summary$sov, out_sov$pivot_summary$name)
sov::plot_sov_geometry(ideals, label_values = sov_labels2d, digits = 3)
}
Traditional Shapley-Owen Values with User Inputs
Description
This function calculates traditional Shapley-Owen values (SOVs) from data provided by the user.
Usage
sov_user(
ideals = NULL,
av = NULL,
absolute = FALSE,
vw = NULL,
q = NULL,
pr = 0.5001,
nPoints1 = 360,
nPoints2 = 360,
dec = 3,
out_dir = NULL,
print_results = FALSE
)
Arguments
ideals |
Matrix of ideal points (legislators x dimensions) |
av |
Attendance vector coded attend=1, "not attend"=NA. |
absolute |
If TRUE, q is a scalar of yeas needed to pass proposal. If FALSE, pr is the proportion of yeas need to pass a proposal among voters attending. |
vw |
Vector of weights for each voter (default 1 for each member, applied later). |
q |
The quota of yeas need to pass a proposal under absolute k-majority rule (scalar, default absolute.maj(vw) applied later ). |
pr |
The proportion of yea votes needed to pass a proposal among voters attending for simple k-majority rule (scalar, default: 0.5001). |
nPoints1 |
the number of points sampled along the azimuth (the first spherical coordinate the azimuth). Sampled from 0 to 2*pi. |
nPoints2 |
the number of points sampled along the inclination (the second and third spherical coordinate). Sampled from 0 to 2*pi. |
dec |
The number of decimal places reported for vs-sovs. |
out_dir |
The path to the output directory. This is used only when |
print_results |
If TRUE, print results to an excel file in out_dir; if FALSE, don't print results. In both cases, results are returned. |
Value
A list with data frames containing ideal points, number of pivots, name of pivots for each direction sampled, and SOVs for each voter.
Examples
# Traditional SOVs in 2D
# Note: You supply only ideal points and an attendance vector (i.e., who is
# always present), not roll-call votes.
# Ideals: 5 voters in 2D
i1 <- c( 0.7, 0.7)
i2 <- c(-0.5, 0.5)
i3 <- c(-0.7, -0.7)
i4 <- c( 0.5, -0.5)
i5 <- c( 0.0, 0.0)
ideals <- rbind(i1, i2, i3, i4, i5)
rownames(ideals) <- paste0("i", 1:5)
colnames(ideals) <- c("coord1D","coord2D")
# Attendance: 1 = included, NA = excluded
# Example: exclude i5 from the analysis
av <- c(1, 1, 1, 1, NA)
## --- Equal voting weights ---------------------------------------------------
vw <- rep(1, nrow(ideals))
## --- Traditional SOV (simple majority among the four voters included) ------
out_sov <- sov_user(
ideals = ideals,
av = av,
absolute = FALSE, # simple k-majority among included voters
pr = 0.5001,
vw = vw,
nPoints1 = 72, # 360 degrees divided into 72 equal sized increments
nPoints2 = 72,
dec = 3
)
# aggregate results by member
out_sov$pivot_summary
# Directions examined (normals) and pivot names by direction:
out_sov$pivot_by_angle
### Plotting (2D): label with SOVs (no normals needed) ###
if (interactive()) {
sov_labels2d <- setNames(out_sov$pivot_summary$sov, out_sov$pivot_summary$name)
sov::plot_sov_geometry(ideals, label_values = sov_labels2d, digits = 3)
}
Internal imports
Description
Internal imports
Vote-Specific Shapley-Owen Values
Description
This function calculates vote-specific Shapley-Owen values (vs-SOVs) from package estimated inputs.
Usage
vs_sov(
estimates = NULL,
weight_nom = FALSE,
absolute = FALSE,
vw = NULL,
q = NULL,
pr = 0.5001,
votes = NULL,
dec = 3,
out_dir = NULL,
print_results = FALSE
)
Arguments
estimates |
Estimation results from oc, wnom, or mcmcPack. |
weight_nom |
If TRUE use weights estimated from wnom output, if FALSE use vector of 1's. ... For wnom only. |
absolute |
If TRUE, q is a scalar of yeas needed to pass proposal. If FALSE, pr is the proportion of yeas need to pass a proposal among voters attending. |
vw |
Vector of weights for each voter (default 1 for each member, applied later). |
q |
The quota of yeas need to pass a proposal under absolute k-majority rule (scalar, default absolute.maj(vw) applied later ). |
pr |
The proportion of yea votes needed to pass a proposal among voters attending for simple k-majority rule (scalar, default: 0.5001). |
votes |
Vote matrix (legislators x rollcalls) coded yea=1, nay=0, and 9="attend but abstain". All other values should be NA. |
dec |
The number of decimal places reported for vs-sovs. |
out_dir |
The path to the output directory. This is used only when |
print_results |
If TRUE, print results to an excel file in out_dir; if FALSE, don't print results. In both cases, results are returned. |
Value
A list with data frames containing ideal points, vs-SOVs for each voter, number of pivots, name of pivot(s) for each roll call, and normal vectors and angles for each roll call.
Examples
# VS-SOVs in 2D using W-NOMINATE OUTPUT
# vs_sov() needs an "estimates" object from OC, WNOMINATE, or MCMCpack.
# Below is a minimal WNOMINATE-like object built from 2D ideals
# and three roll calls.
# Ideals: 5 voters in 2D
i1 <- c( 0.7, 0.7)
i2 <- c(-0.5, 0.5)
i3 <- c(-0.7, -0.7)
i4 <- c( 0.5, -0.5)
i5 <- c( 0.0, 0.0)
ideals <- rbind(i1, i2, i3, i4, i5)
rownames(ideals) <- paste0("i", 1:5)
colnames(ideals) <- c("coord1D","coord2D")
# Fabricate a minimal WNOM-like object called estimates
# Spreads pick the normal directions; midpoints place the cutplane.
spreads <- rbind(
c( 1, 0), # RC1: normal along +x
c( 0, 1), # RC2: normal along +y
c(-1, 0) # RC3: normal along -x
)
midpoints <- rbind(
c( 0.10, 0.00), # RC1 cut near the origin on x
c( 0.00, -0.10), # RC2 cut slightly below origin on y
c( 0.05, 0.00) # RC3 cut near the origin on x
)
rownames(spreads) <- rownames(midpoints) <- paste0("RC", 1:3)
# Legislators must include coord1D/coord2D plus GMP and CC fields.
# These help the function identify the type of estimate.
leg <- data.frame(
coord1D = ideals[, 1],
coord2D = ideals[, 2],
GMP = 0.5,
CC = 0.5,
row.names = rownames(ideals),
check.names = FALSE
)
# Roll calls must include GMP and the WNOM fields midpoint\*D and spread\*D.
rc <- data.frame(
GMP = rep(0.5, nrow(midpoints)),
midpoint1D = midpoints[, 1],
midpoint2D = midpoints[, 2],
spread1D = spreads[, 1],
spread2D = spreads[, 2],
row.names = rownames(midpoints),
check.names = FALSE
)
# Dimensional weights (first must be 1); here both dimensions are equal.
weights <- c(1, 1)
# Minimal WNOM-like object
estimates <- list(
legislators = leg,
rollcalls = rc,
weights = weights
)
class(estimates) <- "nomObject" # not required, but reasonable
# Votes: 1=yea, 0=nay, 9=attend-no-vote, NA=absent
votes <- cbind(
RC1 = c(1, 0, 0, 1, 9), # include one '9' to illustrate attendance w/o voting
RC2 = c(1, 1, 0, 0, 0),
RC3 = c(0, 1, 1, 0, 0)
)
rownames(votes) <- rownames(ideals)
# Equal voting weights
vw <- rep(1, nrow(ideals))
# VS-SOV from WNOM-like estimates (simple majority among attendees)
out_vs <- vs_sov(
estimates = estimates,
votes = votes,
absolute = FALSE, # simple k-majority
pr = 0.5001,
vw = vw,
dec = 3
)
# aggregate results by member
out_vs$pivot_summary
# Pivot names by roll call:
out_vs$pivot_by_rc
# Normals and angles (derived from spreads & midpoints):
out_vs$nv_and_angles
### Plotting (2D): one figure with ALL normals derived from 'spreads' ###
if (interactive()) {
vs_labels2d <- setNames(out_vs$pivot_summary$vs_sov, out_vs$pivot_summary$name)
sov::plot_sov_geometry(ideals, normals = normals, label_values = vs_labels2d, digits = 3)
}
Vote-Specific Shapley-Owen Values with User Inputs
Description
This function calculates vote-specific Shapley-Owen Values (vs-SOVs) from data provided by the user.
Usage
vs_sov_user(
ideals = NULL,
normals = NULL,
midpoints = NULL,
absolute = FALSE,
vw = NULL,
q = NULL,
pr = 0.5001,
votes = NULL,
dec = 3,
out_dir = NULL,
print_results = FALSE
)
Arguments
ideals |
Matrix of ideal points (legislators x dimensions) |
normals |
Matrix of normal vectors (rollcalls x dimensions) |
midpoints |
Matrix of Midpoints (rollcalls x dimensions), i.e. intersection of the cutplane and the unobserved normal vector |
absolute |
If TRUE, q is a scalar of yeas needed to pass proposal. If FALSE, pr is the proportion of yeas need to pass a proposal among voters attending. |
vw |
Vector of weights for each voter (default 1 for each member, applied later). |
q |
The quota of yeas need to pass a proposal under absolute k-majority rule (scalar, default absolute.maj(vw) applied later ). |
pr |
The proportion of yea votes needed to pass a proposal among voters attending for simple k-majority rule (scalar, default: 0.5001). |
votes |
Vote matrix (legislators x rollcalls) coded yea=1, nay=0, and 9="attend but abstain". All other values should be NA. |
dec |
The number of decimal places reported for vs-sovs. |
out_dir |
The path to the output directory. This is used only when |
print_results |
If TRUE, print results to an excel file in out_dir; if FALSE, don't print results. In both cases, results are returned. |
Value
A list with data frames containing ideal points, vs-SOVs for each voter, number of pivots, name of pivot(s) for each roll call, and normal vectors and angles for each roll call.
Examples
#############################################################################
##### ##### 1D Example. Start with Inputs ##### #####
## --- Ideals: 3 voters in 1D -----------------------------------------------
i1 <- 0.7
i2 <- 0.0
i3 <- -0.7
ideals <- cbind(coord1D = c(i1, i2, i3))
rownames(ideals) <- paste0("i", 1:3)
## --- Normals: 2 roll calls (x+, x-) ---------------------------------------
nv1 <- 1 # points to the right
nv2 <- -1 # points to the left
normals <- cbind(dim1 = c(nv1, nv2))
rownames(normals) <- paste0("RC", 1:2)
## --- Votes: 1=yea, 0=nay, 9=attend-no-vote, NA=absent ---------------------
votes <- cbind(
RC1 = c(1, 0, 0), # i1 yea, i2 nay, i3 nay
RC2 = c(0, 1, 1) # i1 nay, i2 yea, i3 yea
)
rownames(votes) <- rownames(ideals)
## --- Equal voting weights --------------------------------------------------
vw <- rep(1, nrow(ideals))
##### EX1: Vote-specific SOV (simple majority among attendees in 1D) #####
out_simple <- vs_sov_user(
ideals = ideals,
normals = normals,
votes = votes,
absolute = FALSE, # simple k-majority
pr = 0.5001, # strict majority of attendees
vw = vw,
dec = 3
)
# Aggregate results
out_simple$pivot_summary
out_simple$pivot_by_rc
out_simple$nv_and_angles
#############################################################################
##### ##### 2D Examples. Start with Inputs ##### #####
## --- Ideals: 5 voters in 2D -----------------------------------------------
i1 <- c( 0.7, 0.7)
i2 <- c(-0.5, 0.5)
i3 <- c(-0.7, -0.7)
i4 <- c( 0.5, -0.5)
i5 <- c( 0.0, 0.0)
ideals <- rbind(i1, i2, i3, i4, i5)
rownames(ideals) <- paste0("i", 1:5)
colnames(ideals) <- c("coord1D","coord2D")
## --- Normals: 3 roll calls (x+, y+, x-) -----------------------------------
nv1 <- c( 1, 0)
nv2 <- c( 0, 1)
nv3 <- c(-1, 0)
normals <- rbind(nv1, nv2, nv3)
rownames(normals) <- paste0("RC", 1:3)
## --- Votes: 1=yea, 0=nay, 9=attend but did not vote -----------------------
votes <- cbind(
RC1 = c(1,0,0,1,9),
RC2 = c(1,1,0,0,0),
RC3 = c(0,1,1,0,0)
)
rownames(votes) <- rownames(ideals)
## --- Equal voting weights ---------------------------------------------------
vw <- rep(1, nrow(ideals))
##### EX2: Simple majority (2D) -- 50 percent + epsilon among attendees #####
out_simple <- vs_sov_user(
ideals = ideals,
normals = normals,
votes = votes,
absolute = FALSE,
pr = 0.5001,
vw = vw,
dec = 3
)
out_simple$pivot_summary
out_simple$pivot_by_rc
out_simple$nv_and_angles
### Plotting (2D): one figure with ALL normals overlaid ###
if (interactive()) {
vs_labels2d <- setNames(out_simple$pivot_summary$vs_sov, out_simple$pivot_summary$name)
sov::plot_sov_geometry(ideals, normals = normals, label_values = vs_labels2d, digits = 3)
}