Profiles with Ties¶
Use the ProfileWithTies
class to create a profile in which voters may submit strict weak orderings of the candidates, allowing ties, and/or in which voters do not rank all the candidates. To create a profile, specify a list of rankings, the number of candidates, the list of counts for each ranking, and possibly a candidate map (mapping candidates to their names).
from pref_voting.profiles_with_ties import ProfileWithTies
a = "a"
b = "b"
c = "c"
rankings = [
{a:1, b:1, c:1},
{a:1, b:2, c:2},
{a:1, b:2, c:3},
{a:1, b:1, c:2},
{a:1, b:1, c:1},
{a:1, b:1, c:2},
{a:1, c:1, b:2},
{c:1, b:1, a:2}
]
rcounts = [1, 2, 1, 4, 1, 2, 1, 1]
prof = ProfileWithTies(rankings, rcounts=rcounts)
prof.display()
print("")
for r,n in zip(prof.rankings, prof.rcounts):
print(f"{n} voters have the ranking {r}")
# the support of a over b is the number of voters that rank a strictly above b
print("\n")
print(f"support(a, b) = {prof.support(a, b)}")
print(f"support(a, a) = {prof.support(a, a)}")
print(f"support(b, a) = {prof.support(b, a)}")
print(f"support(a, c) = {prof.support(a, c)}")
print(f"support(c, a) = {prof.support(c, a)}")
print(f"support(b, c) = {prof.support(b, c)}")
print(f"support(c, b) = {prof.support(c, b)}")
# the margin of a over b is the number of voters who rank a strictly above b minus
# the number of voters who rank b strictly above a
print("\n")
print(f"margin(a, b) = {prof.margin(a, b)}")
print(f"margin(a, a) = {prof.margin(a, a)}")
print(f"margin(b, a) = {prof.margin(b, a)}")
print(f"margin(a, c) = {prof.margin(a, c)}")
print(f"margin(c, a) = {prof.margin(c, a)}")
print(f"margin(b, c) = {prof.margin(b, c)}")
print(f"margin(c, b) = {prof.margin(c, b)}")
# the ratio of a over b is the support of a over b divided by the support of b over a
print("\n")
print(f"ratio(a, b) = {prof.ratio(a, b)}")
print(f"ratio(a, a) = {prof.ratio(a, a)}")
print(f"ratio(b, a) = {prof.ratio(b, a)}")
print(f"ratio(a, c) = {prof.ratio(a, c)}")
print(f"ratio(c, a) = {prof.ratio(c, a)}")
print(f"ratio(b, c) = {prof.ratio(b, c)}")
print(f"ratio(c, b) = {prof.ratio(c, b)}")
+-------+-----+---+-----+-------+-----+-----+-----+
| 1 | 2 | 1 | 4 | 1 | 2 | 1 | 1 |
+-------+-----+---+-----+-------+-----+-----+-----+
| a b c | a | a | a b | a b c | a b | a c | c b |
| | b c | b | c | | c | b | a |
| | | c | | | | | |
+-------+-----+---+-----+-------+-----+-----+-----+
1 voters have the ranking ( a b c )
2 voters have the ranking a ( b c )
1 voters have the ranking a ( b c )
4 voters have the ranking a b c
1 voters have the ranking ( a b ) c
2 voters have the ranking ( a b ) c
1 voters have the ranking ( a b ) c
1 voters have the ranking ( a b ) c
support(a, b) = 4
support(a, a) = 0
support(b, a) = 1
support(a, c) = 9
support(c, a) = 1
support(b, c) = 7
support(c, b) = 1
margin(a, b) = 3
margin(a, a) = 0
margin(b, a) = -3
margin(a, c) = 8
margin(c, a) = -8
margin(b, c) = 6
margin(c, b) = -6
ratio(a, b) = 4.0
ratio(a, a) = 1
ratio(b, a) = 0.25
ratio(a, c) = 9.0
ratio(c, a) = 0.1111111111111111
ratio(b, c) = 7.0
ratio(c, b) = 0.14285714285714285
ProfileWithTies Class¶
Note
The Ranking
class used to the represent the ballots in a ProfileWithTies
is described on the [ballots](ballots) page.
- class pref_voting.profiles_with_ties.ProfileWithTies(rankings, rcounts=None, candidates=None, cmap=None)[source]¶
An anonymous profile of (truncated) strict weak orders of \(n\) candidates.
- Parameters:
rankings (list[dict[int or str: int]] or list[Ranking]) – List of rankings in the profile, where a ranking is either a
Ranking
object or a dictionary.rcounts (list[int], optional) – List of the number of voters associated with each ranking. Should be the same length as rankings. If not provided, it is assumed that 1 voters submitted each element of
rankings
.candidates (list[int] or list[str], optional) – List of candidates in the profile. If not provided, this is the list that is ranked by at least on voter.
cmap (dict[int: str], optional) – Dictionary mapping candidates (integers) to candidate names (strings). If not provided, each candidate name is mapped to itself.
- Example:
The following code creates a profile in which 2 voters submitted the ranking 0 ranked first, 1 ranked second, and 2 ranked third; 3 voters submitted the ranking 1 and 2 are tied for first place and 0 is ranked second; and 1 voter submitted the ranking in which 2 is ranked first and 0 is ranked second:
prof = ProfileWithTies([{0: 1, 1: 2, 2: 3}, {1:1, 2:1, 0:2}, {2:1, 0:2}], [2, 3, 1])
- add_unranked_candidates()[source]¶
Return a profile in which for each voter, any unranked candidate is added to the bottom of their ranking.
- candidates¶
The candidates in the profile.
- cindex_to_cand¶
Maps candidates to their index in the list of candidates and vice versa.
- cmap¶
The candidate map is a dictionary associating a candidate with the name used when displaying a candidate.
- condorcet_loser(curr_cands=None)[source]¶
Returns the Condorcet loser in the profile restricted to
curr_cands
if one exists, otherwise return None.A candidate \(c\) is a Condorcet loser if every other candidate is majority preferred to \(c\).
- condorcet_winner(curr_cands=None)[source]¶
Returns the Condorcet winner in the profile restricted to
curr_cands
if one exists, otherwise return None.The Condorcet winner is the candidate that is majority preferred to every other candidate.
- copeland_scores(curr_cands=None, scores=(1, 0, -1))[source]¶
The Copeland scores in the profile restricted to the candidates in
curr_cands
.The Copeland score for candidate \(c\) is calculated as follows: \(c\) receives
scores[0]
points for every candidate that \(c\) is majority preferred to,scores[1]
points for every candidate that is tied with \(c\), andscores[2]
points for every candidate that is majority preferred to \(c\). The defaultscores
is(1, 0, -1)
.- Parameters:
curr_cands (list[int], optional) – restrict attention to candidates in this list. Defaults to all candidates in the profile if not provided.
scores (tuple[int], optional) – the scores used to calculate the Copeland score of a candidate \(c\):
scores[0]
is for the candidates that \(c\) is majority preferred to;scores[1]
is the number of candidates tied with \(c\); andscores[2]
is the number of candidate majority preferred to \(c\). The default value isscores = (1, 0, -1)
- Returns:
a dictionary associating each candidate in
curr_cands
with its Copeland score.
- display(cmap=None, style='pretty', curr_cands=None)[source]¶
Display a profile (restricted to
curr_cands
) as an ascii table (using tabulate).- Parameters:
cmap (dict[int,str], optional) – the candidate map (overrides the cmap associated with this profile)
style (str --- "pretty" or "fancy_grid" (or any other style option for tabulate)) – the candidate map to use (overrides the cmap associated with this profile)
curr_cands (list[int], optional) – list of candidates
- Return type:
None
- Example:
from pref_voting.profiles_with_ties import ProfileWithTies prof = ProfileWithTies([{0: 1, 1: 2, 2: 3}, {1:1, 2:1, 0:2}, {2:1, 0:2}], [2, 3, 1]) prof.display() prof.display(cmap={0:"a", 1:"b", 2:"c"})
+---+-----+---+ | 2 | 3 | 1 | +---+-----+---+ | 0 | 1 2 | 2 | | 1 | 0 | 0 | | 2 | | | +---+-----+---+ +---+-----+---+ | 2 | 3 | 1 | +---+-----+---+ | a | b c | c | | b | a | a | | c | | | +---+-----+---+
- display_margin_graph(cmap=None, curr_cands=None)[source]¶
Display the margin graph of the profile (restricted to
curr_cands
) using thecmap
. SeeMarginGraph
.
- display_support_graph(cmap=None, curr_cands=None)[source]¶
Display the support graph of the profile (restricted to
curr_cands
) using thecmap
. SeeSupportGraph
.
- dominates(cand, curr_cands=None)[source]¶
Returns the list of candidates that
cand
is majority preferred to in the majority graph restricted tocurr_cands
.
- dominators(cand, curr_cands=None)[source]¶
Returns the list of candidates that are majority preferred to
cand
in the profile restricted to the candidates incurr_cands
.
- classmethod from_preflib(instance_or_preflib_file, include_cmap=False)[source]¶
Convert an preflib OrdinalInstance or file to a Profile. See
pref_voting.io.readers.from_preflib
.
- property is_truncated_linear¶
Return True if the profile only contains (truncated) linear orders.
- is_uniquely_weighted()[source]¶
Returns True if the profile is uniquely weighted.
A profile is uniquely weighted when there are no 0 margins and all the margins between any two candidates are unique.
- majority_graph()[source]¶
Returns the majority graph of the profile. See
MarginGraph
.- Example:
from pref_voting.profiles_with_ties import ProfileWithTies prof = ProfileWithTies([{0: 1, 1: 2, 2: 3}, {1:1, 2:1, 0:2}, {2:1, 0:2}], [2, 3, 1]) mg = prof.majority_graph() print(mg.edges)
[(1, 0), (1, 2), (2, 0)]
- margin(c1, c2)[source]¶
Returns the margin of candidate
c1
over candidatec2
, where the margin is the number of voters that rankc1
strictly abovec2
minus the number of voters that rankc2
strictly abovec1
.
- margin_graph()[source]¶
Returns the margin graph of the profile. See
MarginGraph
.- Example:
from pref_voting.profiles_with_ties import ProfileWithTies prof = ProfileWithTies([{0: 1, 1: 2, 2: 3}, {1:1, 2:1, 0:2}, {2:1, 0:2}], [2, 3, 1]) mg = prof.margin_graph() print(mg.edges) print(mg.margin_matrix)
[(1, 0, 1), (1, 2, 2), (2, 0, 2)] [[0, -1, -2], [1, 0, 2], [2, -2, 0]]
- property margin_matrix¶
Returns the margin matrix of the profile, where the entry at row
i
and columnj
is the margin of candidatei
over candidatej
.
- num_cands¶
The number of candidates in the profile.
- num_voters¶
The number of voters in the profile.
- plurality_scores(curr_cands=None)[source]¶
Return the Plurality Scores of the candidates, assuming that each voter ranks a single candidate in first place.
Parameters: - curr_cands: List of current candidates to consider. If None, use all candidates.
Returns: - Dictionary with candidates as keys and their plurality scores as values.
Raises: - ValueError: If any voter ranks multiple candidates in first place.
- plurality_scores_ignoring_overvotes(curr_cands=None)[source]¶
Return the Plurality scores ignoring empty rankings and overvotes.
- property ranking_types¶
Return a list of the types of rankings in the profile.
- property rankings¶
Return a list of all individual rankings in the profile.
- property rankings_as_dicts_counts¶
Returns the rankings represented as dictionaries and the counts of each ranking.
- property rankings_as_indifference_list¶
Return a list of all individual rankings as indifference lists in the profile.
- property rankings_counts¶
Returns the rankings and the counts of each ranking.
- ranks¶
The ranks that are possible in the profile.
- classmethod read(filename, file_format='preflib', csv_format='candidate_columns', cand_type=None, items_to_skip=None)[source]¶
Read a profile from a file. See
pref_voting.io.readers.read
.
- remove_candidates(cands_to_ignore)[source]¶
Remove all candidates from
cands_to_ignore
from the profile.- Parameters:
cands_to_ignore (list[int]) – list of candidates to remove from the profile
- Returns:
a profile with candidates from
cands_to_ignore
removed.- Example:
from pref_voting.profiles_with_ties import ProfileWithTies prof = ProfileWithTies([{0: 1, 1: 2, 2: 3}, {1:1, 2:1, 0:2}, {2:1, 0:2}], [2, 3, 1]) prof.display() new_prof = prof.remove_candidates([1]) new_prof.display() print(new_prof.ranks)
+---+-----+---+ | 2 | 3 | 1 | +---+-----+---+ | 0 | 1 2 | 2 | | 1 | 0 | 0 | | 2 | | | +---+-----+---+ +---+---+---+ | 2 | 3 | 1 | +---+---+---+ | 0 | 2 | 2 | | 2 | 0 | 0 | +---+---+---+ [1, 2]
- strength_matrix(curr_cands=None, strength_function=None)[source]¶
Return the strength matrix of the profile. The strength matrix is a matrix where the entry in row \(i\) and column \(j\) is the number of voters that rank the candidate with index \(i\) over the candidate with index \(j\). If
curr_cands
is provided, then the strength matrix is restricted to the candidates incurr_cands
. Ifstrength_function
is provided, then the strength matrix is computed using the strength function.
- support(c1, c2)[source]¶
Returns the support of candidate
c1
over candidatec2
, where the support is the number of voters that rankc1
strictly abovec2
.
- support_graph()[source]¶
Returns the support graph of the profile. See
SupportGraph
.- Example:
from pref_voting.profiles_with_ties import ProfileWithTies prof = ProfileWithTies([{0: 1, 1: 2, 2: 3}, {1:1, 2:1, 0:2}, {2:1, 0:2}], [2, 3, 1]) sg = prof.support_graph() print(sg.edges) print(sg.s_matrix)
[(1, 0, (3, 2)), (1, 2, (2, 0)), (2, 0, (4, 2))] [[0, 2, 2], [3, 0, 2], [4, 0, 0]]
- to_linear_profile()[source]¶
Return a linear profile from the profile with ties. If the profile is not a linear profile, then return None.
Note that the candidates in a Profile must be integers, so the candidates in the linear profile will be the indices of the candidates in the original profile.
- to_preflib_instance()[source]¶
Returns an instance of the
OrdinalInstance
class from thepreflibtools
package. Seepref_voting.io.writers.to_preflib_instance
.
- tops_scores(curr_cands=None, score_type='approval')[source]¶
Return the tops scores of the candidates.
Parameters: - curr_cands: List of current candidates to consider. If None, use all candidates. - score_type: Type of tops score to compute. Options are ‘approval’ or ‘split’.
Returns: - Dictionary with candidates as keys and their tops scores as values.
- truncate_overvotes()[source]¶
Return a new profile in which all rankings with overvotes are truncated.
- use_extended_strict_preference()[source]¶
Redefine the supports so that extended strict preferences are used. Using extended strict preference may change the margins between candidates.
- use_strict_preference()[source]¶
Redefine the supports so that strict preferences are used. Using strict preference may change the margins between candidates.
- using_extended_strict_preference¶
A flag indicating whether the profile is using extended strict preferences when calculating supports, margins, etc.
- weak_condorcet_winner(curr_cands=None)[source]¶
Returns a list of the weak Condorcet winners in the profile restricted to
curr_cands
(which may be empty).A candidate \(c\) is a weak Condorcet winner if there is no other candidate that is majority preferred to \(c\).
Note
While the Condorcet winner is unique if it exists, there may be multiple weak Condorcet winners.