User:Lucasvb/An upgrade to the spatial model of voters: Difference between revisions
Content added Content deleted
No edit summary |
No edit summary |
||
Line 179: | Line 179: | ||
Note that there's still a distance between someone who is indifferent and anyone with a different opinion. This makes sense, as it takes effort to convince someone to care. |
Note that there's still a distance between someone who is indifferent and anyone with a different opinion. This makes sense, as it takes effort to convince someone to care. |
||
== Implementation == |
|||
The earth-mover's distance is simple to compute in a discrete case, where the distribution is defined in a number of bins. |
|||
As a first approximation, it is helpful to model the distribution as a simple trapezoidal distribution, instead of a normal distribution. |
|||
In my simulations, I've defined an integer parameter <tt>L</tt>, the resolution of one side of the belief axis. In order to make 0 a valid belief, it is best to use an odd number of bins, so the total number of bins is given by <tt>W = 2*L+1</tt>. |
|||
The following Python code generates the trapezoid distribution for a given opinion, with belief from -1 to +1, and importance from 0 to 1. |
|||
import numpy as np |
|||
from scipy.stats import wasserstein_distance |
|||
L = 5 # bin resolution (number of degrees of agreement/disagreement) |
|||
W = 2*L+1 # total number of bins, an odd number so we have a clean zero |
|||
_space = np.linspace(-1,1,W) # array with positions of the bins |
|||
# Earth-mover's distance (or Wasserstein distance) between two opinion distributions |
|||
def wdistance(dist1,dist2): |
|||
return wasserstein_distance(_space,_space,dist1,dist2) |
|||
# Generates an opinion distribution as a truncated & bounded trapezoidal distribution |
|||
# belief: from -1 to +1 |
|||
# importance: from 0 to 1 |
|||
def opinion(belief, importance): |
|||
w = (1 - importance)*(W-1) + 1 |
|||
v = (w+1)/2 - L*abs(np.linspace(-1,1,W) - belief*importance) |
|||
v[v < 0] = 0 |
|||
v[v > 1] = 1 |
|||
v /= sum(v) |
|||
return v |
|||
# Visualize distribution with text blocks |
|||
def diststr(op): |
|||
return "".join(["_▁▂▃▄▅▆▇█"[int(r/max(op)*7)] for r in op]) |
|||
# Show some distributions generated |
|||
for w in range(1,W+1): |
|||
c = 1 - (w-1)/(W-1) |
|||
for x in range(-L,L+1): |
|||
op = opinion(x/L,c) |
|||
print("(%+0.03f|%0.03f)" % (x/L,c), diststr(op)) |