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.

Open Interactive Chart →

Four Measures of Power

Each measure captures a different dimension of legislative influence:

IndexBasisWhat It Measures
NominalSeat countFormal representation — percentage of seats over total
Shapley-ShubikSeat distributionBargaining power — marginal contribution averaged across all orderings
BanzhafSeat distributionBargaining power — frequency of being a critical coalition member
EmpiricalActual votesReal-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:

AspectShapley-ShubikBanzhaf
AveragingAcross all orderings (permutations)Across all coalitions (subsets)
SymmetryConsiders order of joiningIgnores order
ValuesAlways sum to 1.0Normalized 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:

ChamberOrganization IDSeats--camara
DiputadosO08500diputados
SenadoO09128senado

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:

  1. Voted differently from their party’s majority position, AND
  2. 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:

FieldDescription
Party positionfavor, contra, split, or ausente
Critical statusWhether removing this party’s votes drops the coalition below 334
Margina_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:

RankNamePartyDissent RateTotal VotesDissenting 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.