Overview
Four measures of power for each caucus in the LXVI Legislature: nominal seat percentage, Shapley-Shubik index, Banzhaf index, and empirical power derived from real roll-call voting data. Divergences between these measures reveal parties that are formally small but strategically critical — or vice versa.
Interactive: Power Distribution
Compare nominal power (seats) vs. bargaining power (Shapley/Banzhaf) by party.
Four Measures of Power
Each measure captures a different dimension of legislative influence:
| Index | Basis | What It Measures |
|---|---|---|
| Nominal | Seat count | Formal representation — percentage of seats over total |
| Shapley-Shubik | Seat distribution | Bargaining power — marginal contribution averaged across all orderings |
| Banzhaf | Seat distribution | Bargaining power — frequency of being a critical coalition member |
| Empirical | Actual votes | Real-world relevance — how often a party’s votes were actually decisive |
The key insight is comparing nominal vs. empirical power. A party with 5% of seats but an empirical power of 20% is a kingmaker: its votes are disproportionately decisive. This happens when a dominant coalition frequently needs a small party to cross the majority threshold.
Nominal Power (Seat Count)
The simplest measure: each party’s share of seats in the chamber.
nominal_power[party] = party_seats / total_seats
Seat assignment handles multi-membership — legislators belonging to more than one party across their career — by assigning each legislator to the party where they cast the most votes. Ties are broken by the most recent membership start_date.
For the Chamber of Deputies (Cámara de Diputados), the total is 500 seats. For the Senate (Senado de la República), 128 seats. These totals are derived dynamically from the database via get_total_seats(), not hardcoded.
Shapley-Shubik Index
The Shapley-Shubik index measures each party’s bargaining power by averaging its marginal contribution across all possible orderings in which a coalition could form.
Concept
A party is a pivot at position k in a permutation if the coalition of the first k parties reaches majority, but removing that party drops it below majority. The index is:
SS_i = (number of permutations where i is pivotal) / N!
Dynamic Programming Algorithm
The naive approach enumerates all N! permutations — infeasible for 13 parties. The implementation uses a DP algorithm running in O(n²W) time:
# dp[s][w] = number of subsets of size s with total weight w
# using all players EXCEPT player_i
dp = [[0] * (quota) for _ in range(n)]
dp[0][0] = 1
for p in players:
if p == player_i:
continue
w_j = weights[p]
for s in range(n - 2, -1, -1):
for w in range(max_w - w_j, -1, -1):
if dp[s][w]:
dp[s + 1][w + w_j] += dp[s][w]
# SS_i = Σ dp_i[s][w] * s! * (n-1-s)! / n!
# for w < quota and w + w_i >= quota
With 13 parties and quota ~251 (simple majority in a 500-seat chamber), this requires approximately 330K operations per player — tractable and exact (no sampling).
:::tip The DP approach was validated against the brute-force O(n!) method on 4 datasets with diff = 0.0 across all cases. :::
Banzhaf Index
The Banzhaf index counts how often each party is a critical player in winning coalitions. A player is critical if the coalition wins with them, but becomes losing without them.
Algorithm
for coalition in all_subsets(players):
if coalition_weight >= quota: # winning coalition
for player in coalition:
if coalition_weight - weights[player] < quota:
player is critical
banzhaf[party] = critical_count[party] / total_critical_count
The result is normalized: each party’s score is its share of total critical occurrences across all coalitions.
With 8 parties in the LXVI Legislature, this means 2⁸ = 256 coalitions — trivial to enumerate exhaustively.
Shapley-Shubik vs. Banzhaf
Both measure bargaining power from seat counts, but differ in their treatment of coalition formation:
| Aspect | Shapley-Shubik | Banzhaf |
|---|---|---|
| Averaging | Across all orderings (permutations) | Across all coalitions (subsets) |
| Symmetry | Considers order of joining | Ignores order |
| Values | Always sum to 1.0 | Normalized to sum to 1.0 |
In practice, they produce similar rankings but can diverge for mid-size parties in fragmented legislatures.
Empirical Power
Nominal indices assume perfect party discipline — every member votes with their caucus. Empirical power measures what actually happens in roll-call votes.
Critical Parties per Vote
For each vote event, the module identifies which parties were necessary to reach the majority threshold:
# If approved: winning coalition = parties that voted a_favor
for party in winning_coalition:
remaining = total_a_favor - party_favor
if remaining < majority_threshold:
party is "critical" for this vote
A party is critical when, without its votes, the winning side would have fallen below the required majority.
Empirical Power Index
empirical_power[party] = times_critical[party] / total_vote_events
This produces a 0.0–1.0 score reflecting how often a party’s votes were actually decisive in the outcome. A party that is always in the winning coalition but never critical gets a score near 0.0 — its votes are redundant.
Qualified Majority
The system supports both simple and qualified majority (2/3). For qualified majority votes:
mayoria_necesaria = ceil(2/3 * total_seats) # 334 for Diputados, 86 for Senado
The requirement type is read from the motion.requirement field in the database (mayoria_simple or mayoria_calificada), so the analysis adapts automatically to each vote’s rules.
Bicameral Support
The entire power analysis pipeline supports both chambers via the --camara parameter:
| Chamber | Organization ID | Seats | --camara |
|---|---|---|---|
| Diputados | O08 | 500 | diputados |
| Senado | O09 | 128 | senado |
Seat counts are derived dynamically from the database via get_total_seats(db_path, camara), which queries actual membership records rather than relying on hardcoded constants. The get_seat_counts() function normalizes mixed vote.group values (some vote events use party names like "PT", others use org IDs like "O02") before taking the maximum voter count per party, avoiding inflated numbers from cross-legislature aggregation.
Close Votes and Swing Voters
Close Votes
A vote is close when the margin between the winning and losing sides falls below a configurable threshold:
CLOSE_VOTES_THRESHOLD = 10 # configurable in config.py
close_vote = |a_favor - en_contra| < threshold
Close votes are the most consequential — they are where individual legislators have real leverage. The threshold defaults to 10 but can be adjusted in analysis/config.py.
Swing Voters
Within close votes, the module identifies swing voters: individual legislators who:
- Voted differently from their party’s majority position, AND
- Could have flipped the result with their individual vote
# A legislator is a swing voter if:
# - Their party voted 'favor', but they voted against
# - AND (a_favor_total - 1) < majority → one less vote would change outcome
Only legislators in parties with a clear majority position (>50% of attendees voting one way) are considered. Split or absent parties are excluded.
Judicial Reform Case Study
The judicial reform votes (VE04 and VE05) are analyzed as a special case because they require qualified majority (2/3):
REFORMA_JUDICIAL_VE_IDS = ["VE04", "VE05"]
mayoria_necesaria = ceil(2/3 * 500) = 334
Why It Matters
Under simple majority (251 seats), a dominant party can pass legislation unilaterally. Under qualified majority (334 seats), even the largest party needs coalition partners. This shifts the power calculus entirely:
- Small parties that have zero Shapley-Shubik power under simple majority suddenly become critical under 2/3
- The gap between nominal and empirical power widens dramatically
- Coalition strategy becomes essential
Party-by-Party Breakdown
For each judicial reform vote, the analysis produces:
| Field | Description |
|---|---|
| Party position | favor, contra, split, or ausente |
| Critical status | Whether removing this party’s votes drops the coalition below 334 |
| Margin | a_favor_total - mayoria_necesaria |
The breakdown reveals exactly which parties were kingmakers for the reform — parties whose defection would have sunk the vote.
Dissenter Analysis
Not all legislators vote with their party. The dissenter analysis identifies the top 10 legislators who most frequently break from their caucus line.
Methodology
TOP_DISSENTERS_GLOBAL = 10 # configurable in config.py
for each legislator:
for each vote_event:
if legislator's vote ≠ party's majority position:
dissent_count += 1
dissent_rate = dissent_count / total_votes
# Minimum 10 votes required for inclusion
Output
The analysis ranks legislators by dissent rate (descending), then by raw dissent count as a tiebreaker:
| Rank | Name | Party | Dissent Rate | Total Votes | Dissenting Votes |
|---|---|---|---|---|---|
| 1 | … | … | …% | … | … |
A high dissent rate can indicate ideological independence, strategic positioning, or constituency-driven voting that diverges from the party line. Cross-referencing with W-NOMINATE ideal points reveals whether dissenters cluster ideologically or vote idiosyncratically.