Skip to content

Instantly share code, notes, and snippets.

@dsernst
Last active November 22, 2017 22:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dsernst/624a29e252951bbd5f773ca47edfa89c to your computer and use it in GitHub Desktop.
Save dsernst/624a29e252951bbd5f773ca47edfa89c to your computer and use it in GitHub Desktop.

Goal: An algorithm to calculate an elected legislator's "Representation Score".

Legislative agenda

We have a set of legislative bills, uniquely identified with keys like "2016-11-01-160553" or "2017-03-07-170089", that are the agenda items of a jurisdiction's legislature.

The set grows by 40 bills per week on average. As of 2017-03-12, it has 602 elements.

Each bill has a 1-week window in which it can be voted upon by the citizens in the jurisdiction via the Liquid platform.

Voter registration

Before they can vote, a citizen must have registered with the platform to prove their legal voter eligibility. This is to ensure one-person-one-vote and that all voters are legal residents of the jurisdiction.

Voting

On any bill, each citizen can vote yea, nay, or not vote.

Delegation

A citizen may have previously designated a personal delegate, who is another citizen of the jurisdiction. If a citizen does not vote on a particular bill, their delegate's position will be inherited as their own, like a proxy.

That delegate may themselves have selected a delegate, and this proxy voting power passes transitively. Thus, if Alice has delegated to Bob, and Bob has delegated to Charles, and on a particular bill Alice and Bob do not vote directly but Charles does, Charles' decision will count as 3 votes (recorded with depths of 0, 1, and 2, respectively).

This creates a delegation chain: a linked list from one citizen to their delegate. It terminates when a citizen has no delegate, or has delegated to someone already in the linked list (which would otherwise create an endless cycle).

If a citizen does not vote on a bill, nor does anyone in their delegation chain, no vote is recorded.

Tallying votes

After the 1-week window passes, the votes on a bill are tallied and summarized as such:

{
  bill_uid: '2017-03-07-170089',
  votes_yea: 25544,
  votes_nay: 29512,
}

The jurisdiction's elected legislator is presented this information about their constituents' positions.

The elected legislator then casts their vote on the bill in the legally-recognized legislative body. The platform records this position:

{
  bill_uid: '2017-03-07-170089',
  votes_yea: 25544,
  votes_nay: 29512,
  elected_rep_vote: 'yea',
}

Desired output:

A single number — e.g. 0, 65, 100 — that conveys a summary "score" of how well an elected legislator is representing their constituents. This number may be displayed as a letter grade — e.g. A, B+, F — which may be calculated the standard A > 90, 60 > F way, or may be graded on a curve among the elected legislators.

@dsernst
Copy link
Author

dsernst commented Mar 13, 2017

A naive solution is to track a number timesVotedWithConstituents, and increase it by one every time the elected representative votes the same way as the majority. Then divide this number by the total number of bills to get a percentage of times the representative is aligned with the majority of their constituents.


The problem with this is that it treats these two situations the same:

{
  bill_uid: '2017-03-07-170089',
  votes_yea: 35544,
  votes_nay: 342,
  elected_rep_vote: 'nay',
}

vs

{
  bill_uid: '2017-03-07-170041',
  votes_yea: 65,
  votes_nay: 62,
  elected_rep_vote: 'nay',
}

In both cases, the elected rep voted against the majority. But the first case displayed a much greater margin of victory (99% – 1% vs 51% – 49%), and a much higher voter turnout (35,886 total vs 127 total).

You could imagine one rep that voted with the majority in the first case but against in the second case, and another rep that did the reverse. It would seem absurd to suggest that these two representatives are doing an equal job at representing their constituents, and yet this how this naive approach would treat the two cases.

@dsernst
Copy link
Author

dsernst commented Apr 7, 2017

Latest solution:

  • votes_with_constituents: increment for every individual constituent vote aligned the same way as elected rep's vote.
  • votes_against_constituents: increment for every individual constituent vote aligned the opposite way as elected rep's vote.

image


Simulating the examples from the previous comment:

Rep Mary

{
  bill_uid: '2017-03-07-170089',
  votes_yea: 35544,
  votes_nay: 342,
  elected_rep_vote: 'yea',
}
{
  bill_uid: '2017-03-07-170041',
  votes_yea: 65,
  votes_nay: 62,
  elected_rep_vote: 'nay',
}

Which implies:

votes_with_constituents = 35544 + 62 = 35606
votes_against_constituents = 342 + 65 = 407

score = 35606 / (35606 + 407) = 0.9886985 = 98.87%

Rep Nathan

{
  bill_uid: '2017-03-07-170089',
  votes_yea: 35544,
  votes_nay: 342,
  elected_rep_vote: 'nay',
}
{
  bill_uid: '2017-03-07-170041',
  votes_yea: 65,
  votes_nay: 62,
  elected_rep_vote: 'yea',
}

Which implies:

votes_with_constituents = 342 + 65 = 407
votes_against_constituents = 35544 + 62 = 35606

score = 407 / (407 + 35606) = 0.0113015 = 1.13%


That looks much better, and still seems acceptably simple to understand & explain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment