User:Lucasvb/An upgrade to the spatial model of voters: Difference between revisions

no edit summary
No edit summary
No edit summary
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.
 
== 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))
295

edits