Analyzing the 2025 SC election

Happiness

And one more: how happy are the voters with the final outcome?

ballots by happiness; 74 total
1.0   6   8.1%  *****
0.9  15  20.3%  *************
0.8  13  17.6%  ***********
0.7  18  24.3%  ***************
0.6  11  14.9%  *********
0.5   8  10.8%  *******
0.4   3   4.1%  ***

1.0 is “got everything they wanted” and 0.0 “didn’t get anything they wanted”. There are only 11 possible outcomes, so it’s not fine-grained.

This is simple at heart, but subtle and computationally expensive.

Suppose you have two total orderings of the same list. How well do they agree? A simple and principled measure is “Kendall’s tau” measure: on how many of the comb(len, 2) pairs of elements do the lists agree on the pair’s relative order in the lists? The maximum possible number of agreements is comb(len, 2), which for our 5-winner election is comb(5, 2) = 10.

But there’s a hitch: while our voters were quite expressive, relativly few STAR ballots express a total ordering, What to do about candidates ranked the same?

Massive brute force to the rescue: ballots express a partial ordering, and the number of possible topological sorts (“linear extensions”) is the number of outcomes consistent with the partial ordering given by a ballot.

So this is the actual code, skipping the lower-level bits:

def ballot_happiness(ballot):
    g = {}
    for c in scands:
        g[c] = set()
    for a, b in combinations(scands, 2):
        sa = ballot.get(a, 0)
        sb = ballot.get(b, 0)
        if sa > sb:
            g[a].add(b)
        elif sb > sa:
            g[b].add(a)
    best = max(kendall_agreement_fraction(L)
               for L in all_topological_sorts(g))
    return best

We pick the highest score of all total orderings consistent with the ballot’s partial ordering.

My favorite bot did an excellent job of pointing out the high points, so I’ll just quote it:

1 Like

The bot and I later tried to poke holes in this, and it wasn’t hard. While it’s barely visible in our 5-of-6 winners election, with a higher candidates/winners ratio it could appear to vastly overstate a voter’s “happiness”, because it restricts itself to looking at how only “the winners” were rated.

So, e.g., with 2 winners out of 10 candidates, A and B in that order, if your ballot put A over B, but at 9th and 10th place, it would say you were perfectly happy.

We soon arrived at a principled way to take the entire ballot into consideration, which would correctly say you were quite unhappy with that outcome. But it’s so much more fine-grained now that, in our election, there are 38(!) distinct “happiness levels” now. I’ll spare you.

If I find time, I’ll write code to display decile ranges instead. Suffice it for now to say that the median level was about 0.62, the max remained 1.0, and min plummeted to 0.09 (and the 2nd-lowest over twice as high).

The most unhappy ballot was … odd. It rated 3 candidates with 1 star each, and 1 candidate with 3 stars. The other two were left blank, so implicitly gave them 0 stars each. So, across all candidate pairs, it only expressed 11 preferences, only one of which matched the actual winners’ order. 1/11 ~= 0..09,

1 Like

I stayed up a bit to finish this. Changes:

  • "Happiness* is now on a scale from 0 (miserable) to 100 (delighted). This is just taking the old number, multiplying by 100, and rounding to 1 fractional digit.
  • The distribution is too fine-grained for a simple histogram to be informative. Instead ballots are grouped as evenly as possible into 10 bins. “Deciles” in the lingo.
  • It doesn’t change any conclusions for our extremely high winners/candidates election, just details. It would do very much better on elections with smaller winners/candidates ratios.

[EDIT: same data, but showing more info]
[EDIT: evened out bucket counts by breaking into statistics.quantiles() to get the actual indices it used (not exposed); and for clarity put min and mix into a different section since they’re not “deciles” at all]
[EDIT: wrote my own quantiles() that doesn’t interpolate in magical ways; I don’t like showing happiness values that aren’t in the data]
[EDIT: show low and high values in each bin - no more guessing]

Happiness deciles (into 10 roughly equal bins)

- lo: lowest happiness value in this bin
- hi: highest happiness value in this bin
- #: number of ballots in this bin
- %: percent of all ballots in this bin
- cum: percent of all ballots in this and earlier bins
  this generally isn't exactly a multiple of 10, but
  as close as the data allows for

   lo     hi  #      %     cum
-----  -----  -  -----  ------
  9.1   40.0  7   9.5%    9.5%
 41.7   53.8  8  10.8%   20.3%
 53.8   58.3  7   9.5%   29.7%
 60.0   62.5  8  10.8%   40.5%
 62.5   66.7  7   9.5%   50.0%
 66.7   73.3  7   9.5%   59.5%
 73.3   78.6  8  10.8%   70.3%
 78.6   84.6  7   9.5%   79.7%
 85.7   87.5  8  10.8%   90.5%
 92.3  100.0  7   9.5%  100.0%

extremes
  9.1    9.1  1   1.4%    1.4%
100.0  100.0  3   4.1%  100.0%

BTW, a very rough guide to happiness “meaning”:

  • 90–100: very happy
  • 80–89: happy
  • 70–79: moderately happy
  • 60–69: mixed
  • 50–59: mildly unhappy
  • <50: unhappy

It’s a measure of how often a ballot’s preferences matched the preferences among the final winning order. What it doesn’t count is a ballot’s preference between candidates neither of whom won a seat. While a total ordering produced by Bloc STAR (if iterated to exhaustion) does express a preference among all pairs, the actual election outcome says nothing about pairs of candidates who didn’t win seats. All that can be deduced is that everyone who did win a seat was preferred to everyone who didn’t.

IOW, your preferences between non-winning candidates don’t matter, because neither won. Trying to account for those too would distort what actually happened. It does matter, though, if you preferred a non-winning candidate to one who did win. Which rarely happened in this election. because 83% of our candidates did win.

The math said my own ballot had happiness 66.7. In fact the outcome preferences matched 10 of my 15 preferences (I used all 6 possible ratings)., and 10/15 = 66.7%. But that understates my actual happiness. Some of those expressed preferences were as thin as the width of an electron, and I wasn’t put off in the slightest when the outcome went against them. Always take numbers with some skepticism.

For related reasons, the bot and I rejected measures that try to treat number of stars as a cardinal measure of utility. If a preference you expressed is matched by the outcome, it carries the same weight whether it’s a 5-star to 0-star preference, or 3 stars to 2, same as in a STAR runoff round. Because stars aren’t a cardinal measure of utility in STAR, just a means to pick the plausibly best 2 candidates to go head-to-head in a runoff.

We agreed it was important not to guess at meaning that isn’t apparent from the ballots themselves. For another example, we also treated “not rated” exactly the same as “assigned 0 stars”. Because that’s what actual scoring does. The bot was keen to invent a different meaning, such as “left blank means they don’t care at all”. Which could be used to craft a better measure - if we knew that’s what it meant. But we don’t.

The bot cheerfully gave up on that after I pointed out that our voters were so expressive that we were already drowning in possibilities for good measures without inventing dubious new complications :wink:

1 Like

Preferences

I should have done this one at the start - it’s a fundamental characteristic of the ballots. I just didn’t think of it this way until struggling to create a principled “happiness” measure.

There were comb(6, 2) = 15 pairs of distinct candidates in this election. For each pair, a ballot did or didn’t express a preference between that pair. So the total number of preferences expressed by a ballot varies from 0 (gave all the same number of stars) through 15 (gave one each of all 6 possible star ratings).

ballots by number of preferences; 74 total
 5   7   9.5%  ******
 8   4   5.4%  ****
 9   4   5.4%  ****
11   4   5.4%  ****
12   6   8.1%  *****
13  18  24.3%  ***************
14  16  21.6%  *************
15  15  20.3%  *************

That’s a much better measure than the related , but cruder, “# of distinct ranks” measure. It’s terrific that our voters were, overall, very expressive!

This relates back to the “happiness measure”. Turns out the extremes were among our least expressive ballots.

The single “unhappiest” voter had this kind of ballot (leaving nothing to identify who got which number of stars - the stars are sorted in increasing value, with no relation to candidate oder):

  stars: (0, 0, 1, 1, 1, 3) num preferences: 11

That’s unusual in several respects. Only 1 of their 11 preferences was respected by the outcome, so they got very little of what they sad they wanted.

On the other end, the three “perfectly happy” (got everything they said they wanted) ballots were even less expressive:

stars: (0, 0, 0, 0, 4, 5) num preferences: 9
stars: (4, 4, 4, 4, 5, 5) num preferences: 8
stars: (0, 5, 5, 5, 5, 5) num preferences: 5

A hazard of working with a bot. While correct, this was far more elaborate than was really needed. Linear extensions aren’t needed at all, or a general-purpose Kendall tau.

A given ballot expresses a fixed number of preferences, P. All that matters is how many of those match the order in the election result, but looking only at pairs is which at least one won a seat. Divide how many of those matched by P, and you’re done.

Why did the bot do this? And why did I go along? Because we’re human :wink: We did need to generate all topsorts for a careful implementation of the Ranked Pairs scoring method, and the code was already written. When the only tool you have is a hammer, every problem looks like a nail. It nagged at me, but didn’t raise alarms because results looked fine. Which they were. Neither of us realized that all topsorts yielded exactly the same happiness result.

A difference is that bots for now stop “thinking” about your problem when your chat ends. So they’ll never discover possible massive simplifications unless you bring them up yourself again later. Human collaborators remain far superior in that respect.

1 Like

I’m not sure how you can claim that someone who gave the rating 0 to 4 candidates is “perfectly happy” while at least 3 of the candidates they dislike made it to the SC.

(of course, they couldn’t have been happy with any outcome of this particular election… but I think your metric isn’t really about happiness)

2 Likes

While I’m not sure how to get across that stars in STAR are not cardinal utility values. They express relative preferences in a single election.

This ballot:

stars: (0, 0, 0, 0, 4, 5) num preferences: 9

says they preferred A (5) to B (4), and preferred both to all of the other 4. And that’s all it says. So they expressed 9 preferences in all. A happened to be picked first, and B second, so the outcome matched all of their expressed preferences.

I can only analyze what their ballot said, and they got everything they said they wanted.

Except 0 doesn’t mean “I don’t want this person at all” in STAR, You give a 0 to your least favored candidate (read the ballot instructions), even if you adore every candidate.. It was just a way of saying they have no preferences among the 4 zeroes, but prefer B over all of them “a lot”, and prefer A over B “a little”.

“Happiness” was just a suggestive name, and several times I put it in scare quotes to emphasize that.

I could call it, e.g., “achieved preference percentage”, but that’s surely related to satisfaction with outcomes, and I couldn’t think of a better measure without making dubious assumptions about what ballots “would have said if only they could have”.

If someone can dream up a better measure, I’d love to hear about it.

2 Likes

The problem here is that it’s pretty unintuitive that (0, 0, 0, 0, 4, 5) means the same as (3, 3, 3, 3, 4, 5).

I understand that’s how the voting system interprets those votes, and that the rules for how to vote explain this. But it’s not obvious, and people will choose one or the other depending on how much they dislike the “other” candidates.

If you want another analysis that might be interesting, do the votes as cast give any indication that people are understanding this point? I’m not sure how to even frame the question in a computable way, but maybe you can think of one.

2 Likes

Mostly so, but not quite. So far as preferences go, yes, absolutely the same. But absolute scores matter too, in the scoring phase. A 3 helps a candidate get into a runoff phase more than a 0 does. It’s one of the tradeoffs that makes STAR hard to “game”.

Ya, I wrestled with that too. I’m just averse to passing out 0s in any context, unless the entity being rated has no redeeming qualities. But I got over it :wink:

The first message in this topic showed that almost 2/3rds our voters did pass out at least one 0 and at least one 5 (“Ballots by span”), which is the heart of STAR’s intention. So educational efforts in advance of the election paid off (most people did “follow the instructions”).

This is bound to improve over time, as people get experience and the words “sink in”.

1 Like

I think mechanically, “assign 0 to your least favourite, 5 to your most favourite, and spread the rest of your votes in between” is a nice easy rule to follow. But its downside is that it doesn’t fit with people’s instincts - like you, I feel like giving a 0 is making a negative judgement on a candidate, and I suspect many others feel the same.

My suspicion is that as people get more used to the idea that they can express 6 levels of preference (plus, when there’s more candidates making that many levels more meaningful!) the problem will go away. But when people only have 3 “real” levels of preference[1] spreading those 3 levels across 6 possible numbers will remain difficult.

With 6 numbers and 6 candidates, I took the simple route of giving each candidate a number, and fiddling until it felt right. That’s a very unusual (and atypically easy) situation, though. I’d hope that normally there would be more than 6 candidates.


  1. Definitely A and B, don’t mind C, D and E, don’t want F ↩︎

3 Likes

People adapt over time to the systems they use repeatedly. Under Approval, e.g, over time we got fewer “bullet ballots” (approving of exactly one candidate).

People will learn. I did my best to explain this stuff before the election, and I think that had real effect. But some core devs never saw any of that - some never look here (d.p.o.) at all. I know one who didn’t even know we had switched election methods, or voting service, until they got the email invitation to vote (which they feared was some kind of weird phishing ploy).

It needn’t be! “Honesty is the best policy” under STAR. If you truly have only 3 levels, say so. Give 5 to your most favorites, 0 to your least favorites, and pick some number of stars, relative to those, that feels best to you. Give everyone in your middle group that number of stars. Not hard. Then you’ve expressed all your actual preferences, and the “middle ground” number of stars you give affects their chances of making it into a runoff.

Me too. About 20% of our voters did use all 6 levels (see the first post in this topic).

I’d like te see two candidates for each open seat.


  1. Definitely A and B, don’t mind C, D and E, don’t want F ↩︎

1 Like

Ballot sensitivity

Does your vote matter? Not much :wink:. That’s just reality. But a surprisingly small number of ballots can matter, if you pick the right ones. In our election:

  • Nothing changes in the outcome if any single ballot is thrown out.
  • Likewise it’s all the same if any pair of ballots is thrown out.
  • But things change if 3 ballots are thrown out. There are comb(74, 3) = 64_824 ways to pick 3 ballots, and 6_675 of those ways do change the outcome if they’re ignored. 819 just slightly change the order in which the winners were picked, but 5_856 change who won.

Don’t read too much into this. It’s typical of any sequential (“one at a time”) multi-winner method that the ordering of the last winners picked is touchy. For whatever reasons, the first few winners picked are typically much stronger by any measure used. Even throwing out 4 ballots (over a million ways to do that) never changes our first three picks, or their order.

Note: this is all using the default deterministic “random” tiebreaking the starvote library uses. Not the same as what our voting service used. It was never invoked until reaching 3 ballots ignored.

2 Likes

A non-sequential method

Once there’s a purported measure of voter satisfaction with an outcome, a very different approach is to try all possible outcomes, looking for outcomes that optimize some function of that measure.

For my “happiness” measure, the obvious first thing to try is looking for outcome(s) that maximize total happiness across all ballots, across all 720 permutations of the candidates.

That gets very close to what Bloc STAR delivered, which latter permutation scores 49.67 total happiness. Only one permutation did better, at 49.73. Yup, it takes 4 digits to see the difference! The (slightly) best by this measure did change who won.

Other functions of the measure lead to some hilariously bizarre results. For example, look for outcomes that minimize the difference between max and min happiness values across ballots. Those tend to put our winner last, not because they’re increasing overall happiness, but because they’re dragging so many voters’ happiness down in order to try to make everyone as equally happy as possible.

Even if you believe that’s a worthy societal goal, it isn’t when it comes to voting :wink:

1 Like

EDIT: best to ignore this. While it works fine for our election, in has weird behavior modes for elections with materially fewer winners than candidates. At heart the code can vastly overestimate the worst outcome a given ballot can encounter, and so overestimate the “happiness level”, pushing all of them toward 100. My bot suggested after-the-fact rescaling back into 0…100. Expedient, but papering over the fundamental flaw of overestimating worst cases so badly.

We worked at repairing that. and I have somewhat different code now, with a crisp accounting for worst possible cases. A surprise: the geometry of the space is such that it doesn’t work for 1-winner elections. Turns out that’s not a limiting case of k-winner as k approaches 1 from above. A 1-winner election only has 1 bit of “happiness”: a candidate in your top tier won, or they didn’t. End of story. Trying to create more nuance than just that is a fool’s errand.

“Happiness”, round 2

Major changes here. For example, if I give stars to 6 candidates

A:5 B:5 C:4 D:4 E:2 F:0

I’m saying I want A and B to be picked 1st and 2nd (but don’t care in which order), C and D to be picked 3rd and 4th (again regardless of order), E 5th, and F 6th.

If, say, E is picked first or second, I’m “less happy” than if E is picked third or fourth. But in all those cases, the outcome didn’t match my raw preference order, so in the current scheme simply doesn’t add 1 to the count of preference matches for E.

It’s throwing out too much info. Such a ballot defines 4 “tiers”, and their order matters to me (although not their abosolute star values).

A different measure calculates the tier structure of a ballot, and for each candidate computes the number of ranks in the outcome it’s removed from the relevant end of the “ideal rank range” the ballot’s tier structure expresses (or 0 if the candidate’s actual rank is within that range).

The higher that is, the more a ballot’s tier preferences weren’t achieved, so it’s more a measure of pain than of happiness :wink: I’ll skip details here. Computing “happiness” requires reversing the sense of it, and then, finally rescale the full range of values seen to lie in the interval [0.0, 1..0].

So no more pretention to be an “absolute” measure of anything. At least one ballot will have normalized score 0, and at least one 100. That spreads the results across the full range so you can see the differences clearly.

And a value of 50 doesn’t mean “half satisfied” - it means “halfway between the happiest and least‑happy ballots in this election.” The distribution is such that many ballots were closer to the middle than the extremes. Which isn’t surprising - the mean and median of the normalized values are very close.

Normalized "happiness" deciles (10 roughly equal-size bins)

- lo: lowest happiness value in this bin
- hi: highest happiness value in this bin
- #: number of ballots in this bin
- %: percent of all ballots in this bin
- cum: percent of all ballots in this and earlier bins
  this generally isn't exactly a multiple of 10, but
  as close as the data allows for

   lo     hi  #      %     cum
-----  -----  -  -----  ------
  0.0   11.2  7   9.5%    9.5%
 11.2   32.7  8  10.8%   20.3%
 34.5   42.1  7   9.5%   29.7%
 42.9   47.6  8  10.8%   40.5%
 47.6   50.0  7   9.5%   50.0%
 52.9   57.1  7   9.5%   59.5%
 57.1   68.6  8  10.8%   70.3%
 70.1   72.7  7   9.5%   79.7%
 73.8   80.4  8  10.8%   90.5%
 85.7  100.0  7   9.5%  100.0%

extremes
  0.0    0.0  1   1.4%    1.4%
100.0  100.0  3   4.1%  100.0%

This was the unique ballot that scored lowest:

 {'Barry Warsaw': 5,
  'Thomas Wouters': 5,
  'Gregory P. Smith': 4,
  'Pablo Galindo Salgado': 3,
  'Savannah Ostrowski': 3,
  'Donghee Na': 0,
 }

4 tiers, with “ideal rank ranges” 1-2, 3, 4-5, and 6. No candidate ended up in this ballot’s ideal range, and some quite far removed.

Is this a “better” measure? I think so, but no QED to be had with this kind of thing.

[EDIT: adding code for this measure - simple enough, but lots of steps]

ballot_happiness() code
# winners: list[str] is list of winners in order picked
# scands: list[str] is global iist of all candidates, unordered
def ballot_happiness(ballot, winners):
    # Normalize ballot to include all candidates -
    # Missing candidates get score 0
    full_ballot = {c: ballot.get(c, 0) for c in scands}

    # Build tiers from the full ballot
    tiers = defaultdict(list)
    for c, s in full_ballot.items():
        tiers[s].append(c)

    sorted_scores = sorted(tiers, reverse=True)
    tier_list = [tiers[s] for s in sorted_scores]

    # Compute ideal intervals for each tier ---
    ideal_interval = {}
    start = 1
    for group in tier_list:
        end = start + len(group) - 1
        r = start, end
        for c in group:
            ideal_interval[c] = r
        start = end + 1

    # Assign actual ranks ---
    # Winners get ranks 1..k
    rank = {c: i+1 for i, c in enumerate(winners)}

    # All non-winners share the same "last place" rank
    last_rank = len(winners) + 1
    for c in scands:
        if c not in rank:
            rank[c] = last_rank

    # Compute displacement for each candidate ---
    total_disp = 0
    for c in scands:
        r = rank[c]
        s, e = ideal_interval[c]
        total_disp += s - r if r < s else r - e if r > e else 0

    # Maximum possible displacement for normalization.
    # The largest rank in the ballot's tier structure is
    # len(tiers).
    # The largest rank among all candidates is
    # last_rank (len(winners) + 1).
    N = max(len(tiers), last_rank)
    max_disp = sum(
        max(s - 1, N - e)
        for (s, e) in ideal_interval.values()
    )

    if max_disp == 0:
        return 1.0
    result = 1.0 - (total_disp / max_disp)
    assert 0.0 <= result <= 1.0
    return result
1 Like

It would be interesting to consider the effect of tweaks that have no mathematical effect of the calculations but could have psychological effects. For instance, what you’re saying suggests there may be a psychological difference between 0 and 1. So what if the scores were 1-6 instead of 0-5?

You could also imagine an interface that just has six un-numbered, unlabeled “slots” or “tiers” arranged vertically, and says something like “Drag the candidates into the regions, putting candidates higher if you like them more. Put candidates you have an equal opinion of in the same region.” This has the same effect as a numerical ranking, but doesn’t require people to see or think about numbers at all.

3 Likes

Ballots by signature

This came up while investigating “happiness” measures. Each ballot groups candidates into equivalence classes, by the number of stars a candidate got. From highest number of stars to lowest, the “signature” is a tuple of the size of those classes.

So, e.g., if you gave 5 stars to 2 candidates, 3 stars to 3 candidates, and 0 stars to the last, the “signature” would be (2, 3, 1). The magnitude of the number of stars doesn’t matter to this, just “highest to lowest” order. sum(sig) is always 6.

In combinatorics, the number of possible sigs is the number of “compositions of 6”, 2^{6-1} = 32, and our ballots coverered a suprisingly large number of the possibilities.

ballots by signature; 74 total
(1, 1, 1, 1, 1, 1)  15  20.3%  *************
(1, 1, 1, 1, 2)      6   8.1%  *****
(1, 1, 1, 2, 1)      1   1.4%  *
(1, 1, 1, 3)         2   2.7%  **
(1, 1, 2, 1, 1)      2   2.7%  **
(1, 1, 2, 2)         1   1.4%  *
(1, 1, 4)            1   1.4%  *
(1, 2, 1, 1, 1)      3   4.1%  ***
(1, 2, 1, 2)         3   4.1%  ***
(1, 2, 2, 1)         4   5.4%  ****
(1, 3, 2)            2   2.7%  **
(1, 5)               1   1.4%  *
(2, 1, 1, 1, 1)      4   5.4%  ****
(2, 1, 1, 2)         4   5.4%  ****
(2, 1, 2, 1)         2   2.7%  **
(2, 2, 1, 1)         4   5.4%  ****
(2, 2, 2)            2   2.7%  **
(2, 4)               2   2.7%  **
(3, 1, 1, 1)         2   2.7%  **
(3, 1, 2)            1   1.4%  *
(3, 2, 1)            1   1.4%  *
(3, 3)               1   1.4%  *
(4, 1, 1)            2   2.7%  **
(4, 2)               2   2.7%  **
(5, 1)               6   8.1%  *****

These show preference patterns across voters.

By eyeball, a lot of voters had a single favorite (1 in the first position), and 6 ballots said “anyone but this one” (signature (5, 1))..

1 Like

I’m not aware of any research on this, but agree it would be interesting to see some! 0 screams “worthless” :frowning:.

That’s partly how “Condorcet ballots” work: purely ordinal preferences, nothing about scores. Some require imposing a total order (equal preferences not allowed) across candidates, others do allow ties.

I don’t believe it’s possible to “out-think” this stuff. People can and do surprise.

I’ll note that Amazon’s lowest possible product rating is 1 star, presumably informed by millions of dollars worth of research - or by an offhand whim of Bezos :wink:. In context, though, Amazon shoppers learned to read “1 star” as meaning “worthless”.

3 Likes

I asked a bot, and its reading of more web pages I’ll ever read :wink: came up with this:

So it’s about minimizing potentially adverse consequences of a voter not assigning a rating at all. Another very human failure mode is to assume “not marked” means “no opinion”. And in some voting systems it does mean that. But not in STAR. Blank means “least preferred”, and they don’t want people who do think it means “no opinion” artificially inflating a candidate’s total score.

1 Like

Size of equivalence classes

So how many of each size are there?

equivalence classes by size; 309 total
1  219  70.9%  *******************************************
2   66  21.4%  *************
3   10   3.2%  **
4    7   2.3%  **
5    7   2.3%  **

So “almost all” equivalence classes had no more than 2 candidates. Another way of seeing that our voters were very expressive, taking advantage of the possibility to express nuance. That’s a Good Thing™ :smiley:,

1 Like

“Happiness”, round 3

In the background, my bot & I continued hammering on a “really good” measure. That’s been involved but satisfying. We now have a measure that’s uniform, mathematically sound, and seems to behave smoothly and “intuitively” regardless of the number of candidates or winners, including on seemingly pathological cases like “bullet ballots”.

But that’s not what this is about.. Here we’re trying the other direction. The richness of the geometries we’ve been digging into is mostly due to considering the order in which Bloc STAR picks winners. That’s part of the election outcome record too, and it at least matters to me. For example, I’m inarguably happier if a scheme picks my very favorite first instead of last.

But I’m an election nerd, and I’m sure many people don’t care about order at all - just “who won in the end?”. Of course it’s possible to quantify results on that basis too.

ballots by simple outcome happiness; 74 total
 80.0  34  45.9%  ****************************
100.0  40  54.1%  *********************************

Amazingly uninformative, eh? That’s because it’s a 5-of-6 winner election. No matter what the outcome was, every ballot was guaranteed in advance that at least 4 of its most-favored candidates would win a seat. So every ballot gets at least 80% of what it said it wanted if ordering is ignored.

The only way you can get less than 100% is if your ballot gave its lowest number of stars to a single candidate who wasn’t the candidate who actually didn’t win. Then, and only then, you didn’t get a final winner you said you wanted. Can’t say which one, but it’s certain: since your unique least-favored did win, one of your 5 most-favored did not. Specifically, the candidate who actually lost is in your 5-most favored then, but didn’t win

If you gave more than one candidate the lowest number of stars, all but one of them must win anyway. In which case, they’re among “your most favored 5” too.

EDIT: since a later post went into more detail about 'ideal rank intervals", now I’ll include the code to compute “order-independent outcome happiness”. It’s not a fundamentally different approach than ideal intervals, but rather a simple application _of _ the latter: for how many winners does their ideal rank interval intersect with (1, num_winners)? Those are exactly the ones the ballot “wanted to win a seat”.

    def simple_happiness(self, winners):
        nwin = len(winners)
        if nwin != self.nseats:
            raise ValueError(
                f"Expected {self.nseats} winners, got {nwin}")
        hits = sum(self.ideal_interval[w][0] <= nwin
                   for w in winners)
        result = hits / nwin
        assert 0.0 <= result <= 1.0
        return result
1 Like