Majoritarian Accuracy of Majority Voting¶
This Jupyter Notebook demonstrates how the agent-based model of majority voting works by walking you through the stages of the model. The agent-based model is an adaptation of the Condorcetian framework (see Wikipedia or The Stanford Encyclopedia of Philosophy) which operationalizes the following (revised) assumptions:
- The Assumption of Plural Interests. For each agent, there exists some agent-relative measure of success or correctness – typically referred to as the agent’s interest or values.
- The Group-relative Competence Assumption. For each of the two groups (masses and elites), each member’s belief about the right alternative is true with probability greater than chance level.
- The Social Influence Assumption. (a) The initial beliefs of all voters are probabilistically independent (given the true state of the world). (b) The final beliefs of voters can be influenced by other voters.
- The Sincerity Assumption. All voters vote for the alternative they believe to be the right alternative.
In particular, an instantiation of the agent-based model, called Community
, consists of the following building blocks:
- A set of agents $N$,
- A partition of $N$ into elites $E$ and masses $M$,
- Group-relative competences $p_e$ and $p_m$ (in $[0,1]$) for elites and masses, respectively,
- For each agent $i \in N$:
- Her membership in either the elites ($E$) or the masses ($M$),
- Her individual competence $p_i\in [0,1]$ (which equals either $p_e$ or $p_m$, depending on the group she belongs to)
- Her social environment $S_i \subseteq N$.
We start with loading some packages and scripts:
%run scripts/notebook.py
1. A simple example¶
1.0 Initial stage¶
Let us start with considering a simple example of a community with only 20 agents. More explicitly, we set the parameters as follows:
- A set of agents $N=\{0, \ldots, 19\}$,
- A partition of $N$ into elites $E=\{0, \ldots, 7\}$ (hence $|E|=6$) and masses $M=\{8, \ldots, 19\}$,
- Group-relative competences $p_e=0.8$ and $p_m=0.6$ for elites and masses, respectively,
- For each agent $i \in N$:
- Her social environment $S_i \subseteq N$ (where $|S_i|=6$).
The simple community is depicted in the picture below. Let me explain the picture:
- Nodes:
- The color of the nodes represents whether they are elites or masses.
- The size is proportional to the in-degree, so that bigger nodes are more influential. In general, influential nodes are in the center of the picture.
- As a rule of thumb, the elites are more prone to be on the left-hand side of the network, while the masses are on the right-hand side.
- Edges:
- The edges represent the agents' social environments: the social environment of an agent is the set of target nodes of all outgoing edges. Accordingly, every node has out-degree 6.
- The color of the edges represents whether the target nodes are elites or masses.
- The network that is generated using preferential attachment and homophilic selection ($h$=0.7), but this is hardly visible in such small-scale communities.
All the pictures are interactive: you can move nodes around!
community_simple = Community(
number_of_nodes=20,
number_of_elites=8,
elite_competence=0.8,
mass_competence=0.6,
probability_homophilic_attachment=0.7,
)
community_simple.update_votes()
visualize(community_simple, color_type="type").show("www/community_simple_initial.html")
www/community_simple_initial.html
1.1 Opinions and social influence¶
In the first stage, the agents form their own individual opinion. Agent $i$'s individual competence $p_i$ expresses the probability that she forms the right opinion, i.e., that her beliefs about the alternative that is in her own best interest is correct. The color of the nodes represents whether their opinion favours the alternative that is in the best interest of the elites or masses.
In the second stage, the agents form their voting decision. Agent $i$'s voting decision is determined by her own opinion and the opinions of the agents in her social environment $S_i$. A node's (outgoing) edges represents its social environment and the colors of the edges represent the opinions of the target nodes.
Let's see how this goes in the simple community. Did anyone form the wrong opinion? Can you figure out why? Can you predict some of the voting decisions?
visualize(com=community_simple, color_type="opinion").show("www/community_simple_opinions.html")
www/community_simple_opinions.html
1.2 Voting decisions¶
Let us represent the voting decisions of the agents in this simple community. The color of the nodes represents whether their vote favours the alternative that is in the best interest of the elites or masses.
Let's see how this goes in the complex community. Did anyone form the wrong voting decision? Can you figure out why?
visualize(com=community_simple, color_type="vote").show("www/community_simple_votes.html")
www/community_simple_votes.html
1.3 The vote¶
The outcome is probably no surprise to you at this point, but let's see the outcome of majority voting:
votes_for_elites = sum(
[1 for node in community_simple.nodes if community_simple.network.nodes[node]["vote"] == vote_for_elites]
)
votes_for_masses = community_simple.number_of_nodes - votes_for_elites
print(f"Elites: {votes_for_elites} | Masses: {votes_for_masses}")
Elites: 13 | Masses: 7
2. A more complex example¶
2.0 Initial stage¶
Let us now consider a bigger community with 100 agents, where 30 are elites. More explicitly, we set the parameters as follows:
- A set of agents $N=\{0, \ldots, 90\}$,
- A partition of $N$ into elites $E=\{0, \ldots, 29\}$ and masses $M=\{30, \ldots, 99\}$,
- Group-relative competences $p_e=0.8$ and $p_m=0.6$ for elites and masses, respectively,
- For each agent $i \in N$:
- Her social environment $S_i \subseteq N$ (where $|S_i|=6$).
The community is depicted in the picture below. Let me explain the colors in the picture:
- Colors:
- The color of the nodes represents whether they are elites or masses.
- The colors of the edges represent the color of the target nodes.
community = Community(
number_of_nodes=100,
number_of_elites=30,
elite_competence=0.8,
mass_competence=0.6,
probability_homophilic_attachment=0.7,
)
community.update_votes()
visualize(community).show("www/community_complex_initial.html")
www/community_complex_initial.html
The network is generated by homophilic selection ($h=0.7$) and by preferential attachment. You can roughly see that the network is generated by preferential attachment because most agents have little influence, while a few have a lot of influence. You can gauge that the network is generated by homophilic selection because outgoing edges tend to have the same color as the source node.
Let us compute the number of agents that are influenced by the most influential agent:
max_in_degree = sorted(community.network.in_degree, key=lambda x: x[1], reverse=True)[0]
print(f"Node {max_in_degree[0]} has the most influence: they influence {max_in_degree[1]} others!")
Node 92 has the most influence: they influence 48 others!
2.1 Opinions and social influence¶
In the first stage, the agents form their own individual opinion. Agent $i$'s individual competence $p_i$ expresses the probability that she forms the right opinion, i.e., that her beliefs about the alternative that is in her own best interest is correct. The color of the nodes represents whether their opinion favours the alternative that is in the best interest of the elites or masses.
In the second stage, the agents form their voting decision. Agent $i$'s voting decision is determined by her own opinion and the opinions of the agents in her social environment $S_i$. A node's (outgoing) edges represents its social environment and the colors of the edges represent the opinions of the target nodes.
Let's see how this goes in the complex community. Did anyone form the wrong opinion? Can you figure out why? Can you predict some of the voting decisions?
visualize(com=community, color_type="opinion").show("www/community_complex_opinions.html")
www/community_complex_opinions.html
Given the size of the community, it is hard to see the distribution of opinions, so let's compute this:
opinions_for_elites = sum(
[1 for node in community.nodes if community.network.nodes[node]["opinion"] == vote_for_elites]
)
opinion_for_masses = community.number_of_nodes - opinions_for_elites
print(f"Opinions: Elites: {opinions_for_elites} | Masses: {opinion_for_masses}")
Opinions: Elites: 52 | Masses: 48
2.2 Voting decisions¶
Let us represent the voting decisions of the agents in this complex community. The color of the nodes represents whether their vote favours the alternative that is in the best interest of the elites or masses.
Let's see how this goes in the complex community. Did anyone form the wrong voting decision? Can you figure out why?
visualize(com=community, color_type="vote").show("www/community_complex_votes.html")
www/community_complex_votes.html
2.3 The vote¶
The outcome is probably no surprise to you at this point, but let's see the distribution of the votes:
votes_for_elites = sum(
[1 for node in community.nodes if community.network.nodes[node]["vote"] == vote_for_elites]
)
votes_for_masses = community.number_of_nodes - votes_for_elites
print(f"Votes: Elites: {votes_for_elites} | Masses: {votes_for_masses}")
Votes: Elites: 57 | Masses: 43
Let's take a step back and see how the distribution changed from the initial distribution of elites and masses via the intermediate distribution of opinions to the final distribution of votes:
print(f"Initial distribution: Elites: {community.number_of_elites} | Masses: {community.number_of_mass}\n"
f"Opinion distribution: Elites: {opinions_for_elites} | Masses: {opinion_for_masses}\n"
f"Votes distribition: Elites: {votes_for_elites} | Masses: {votes_for_masses}")
Initial distribution: Elites: 30 | Masses: 70 Opinion distribution: Elites: 52 | Masses: 48 Votes distribition: Elites: 57 | Masses: 43
3. Thanks¶
I hope this brief illustration helped to understand the inner workings of the agent-based model of majority voting. Thanks for showing interest!