The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Introduction to TheOrdinals: consensus for preference-approvals

Alessandro Albano, Maurizio Romano

Preference-approvals

A preference-approval is a pair \((\pi, A)\) where \(\pi\) is a (weak) ranking of \(n\) alternatives and \(A\) is the subset of approved alternatives. The two components must be consistent: approved alternatives are ranked above unapproved ones, and tied alternatives share the same approval status (Definition 1 of Albano and Romano, 2026).

Throughout the package a set of \(m\) preference-approvals is stored as a numeric matrix with \(2n\) columns: the first \(n\) columns hold the ranking (positions, with ties allowed) and the last \(n\) columns hold the approval indicators (1 approved, 0 not approved). For example, four voters over four alternatives:

x <- rbind(
  c(1, 2, 3, 4, 1, 1, 0, 0),
  c(2, 1, 3, 4, 1, 0, 0, 0),
  c(1, 2, 4, 3, 1, 1, 0, 0),
  c(1, 3, 2, 4, 1, 1, 1, 0)
)
x
#>      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
#> [1,]    1    2    3    4    1    1    0    0
#> [2,]    2    1    3    4    1    0    0    0
#> [3,]    1    2    4    3    1    1    0    0
#> [4,]    1    3    2    4    1    1    1    0

The consistency of a single preference-approval can be checked with is_consistent():

is_consistent(c(1, 2, 3, 4), c(1, 1, 0, 0))  # admissible
#> [1] TRUE
is_consistent(c(1, 2, 3, 4), c(0, 1, 0, 0))  # not admissible
#> [1] FALSE

Given a ranking, find_approval() enumerates the approvals compatible with it, and pa_universe() builds the whole universe of preference-approvals on \(n\) alternatives:

find_approval(c(1, 2, 2, 3))
#>   V1 V2 V3 V4 V5 V6 V7 V8
#> 1  1  2  2  3  0  0  0  0
#> 2  1  2  2  3  1  0  0  0
#> 3  1  2  2  3  1  1  1  0
#> 4  1  2  2  3  1  1  1  1
dim(pa_universe(3))
#> [1] 44  6

Distance between preference-approvals

The disagreement between two preference-approvals is measured by the family of distances \(d_\lambda\) of Erdamar et al. (2014), a convex combination of the normalised Kemeny distance on the ranking component and the normalised Hamming distance on the approval component:

\[ d_\lambda\big((\pi_1, A_1), (\pi_2, A_2)\big) = \lambda \, d_R + (1 - \lambda)\, d_A, \qquad \lambda \in [0, 1]. \]

The function pref_dist() returns the matrix of pairwise distances:

round(pref_dist(x), 3)              # lambda = 0.5
#>       1     2     3     4
#> 1 0.000 0.208 0.083 0.208
#> 2 0.208 0.000 0.292 0.417
#> 3 0.083 0.292 0.000 0.292
#> 4 0.208 0.417 0.292 0.000
round(pref_dist(x, lambda = 0.8), 3)
#>       1     2     3     4
#> 1 0.000 0.183 0.133 0.183
#> 2 0.183 0.000 0.317 0.367
#> 3 0.133 0.317 0.000 0.317
#> 4 0.183 0.367 0.317 0.000

The DIVA consensus

DIVA (Divide and Conquer for Preference-Approvals) returns the preference-approval that minimises the average distance \(d_\lambda\) to the set of voters. The result is always admissible.

res <- diva(x, algorithm = "quick")
res
#> DIVA consensus preference-approval
#>   algorithm: quick | lambda: 0.5 | search: FALSE
#>   average distance (D_lambda): 0.125
#>   number of (tied) solutions: 1
#>   ranking component | approval component:
#>   X1 X2 X3 X4 X5 X6 X7 X8
#> 1  1  2  3  4  1  1  0  0
res$d_lambda
#> [1] 0.125

French Presidential Election (2002)

The dataset french_election_2002 contains the admissible preference-approvals on the 15 candidates of the first round of the 2002 French presidential election.

data(french_election_2002)
dim(french_election_2002)
#> [1] 314  30
fc <- diva(french_election_2002, algorithm = "quick")
fc$d_lambda
#> [1] 0.2168259

The consensus ranks Lionel Jospin first; the approved candidates are those whose consensus rank is among the top positions:

n <- 15
cons <- fc$consensus[1, ]
data.frame(
  candidate = colnames(french_election_2002)[1:n],
  rank      = as.numeric(cons[1:n]),
  approved  = as.numeric(cons[(n + 1):(2 * n)])
)
#>      candidate rank approved
#> 1       Bayrou    2        0
#> 2   Besancenot    3        0
#> 3       Boutin    3        0
#> 4    Cheminade    3        0
#> 5  Chevenement    2        0
#> 6       Chirac    2        0
#> 7          Hue    3        0
#> 8       Jospin    1        1
#> 9    Laguiller    3        0
#> 10     Lalonde    3        0
#> 11      Lepage    3        0
#> 12      Le Pen    3        0
#> 13     Madelin    3        0
#> 14      Mamere    2        0
#> 15     Maigret    3        0

Sensitivity to the weighting parameter

diva_sensitivity() reports the achieved average distance over a grid of \(\lambda\), showing how the relative weight of the ranking and the approval components affects the consensus:

s <- diva_sensitivity(french_election_2002)
plot(s$lambda, s$d_lambda, type = "b", pch = 19,
     xlab = expression(lambda), ylab = expression(D[lambda]),
     main = "DIVA consensus distance vs lambda")

DIVA consensus distance as a function of lambda

Formula 1 World Championship (1950)

The dataset formula1_1950 reads the classification of each of the 7 Grands Prix of the 1950 season as a ranking of 81 drivers, with the top five finishers approved. With 81 alternatives the consensus search is heavier, so the call below is shown but not executed in this vignette:

data(formula1_1950)
diva(formula1_1950, algorithm = "quick")

References

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.