Source code for embedded_voting.ratings_from_embeddings.ratings_from_embeddings_correlated
import numpy as np
from embedded_voting.ratings.ratings import Ratings
from embedded_voting.embeddings.embeddings import Embeddings
from embedded_voting.ratings_from_embeddings import RatingsFromEmbeddings
from embedded_voting.ratings.ratings_generator_uniform import RatingsGeneratorUniform
[docs]class RatingsFromEmbeddingsCorrelated(RatingsFromEmbeddings):
"""
Generate ratings from embeddings and from a matrix where each embedding dimension gives a rating to each candidate.
`ratings_automatic[voter, candidate]` is computed as the average of `ratings_dim_candidate[:, candidate]`, weighted
by the squares of `emdeddings[voter, :]`. In particular, for each `voter` belonging to group `i` (in the sense that
their embedding is the i-th vector of the canonical basis), then `ratings_automatic[voter, candidate]` is equal to
`ratings_dim_candidate[i, candidate]`.
`ratings_random[voter, candidate]` is computed as a uniform random number between `minimum_random_rating` and
`maximum_random_rating`.
Finally, `ratings` is the barycenter: `coherence * ratings_automatic + (1 - coherence) * ratings_random`.
Parameters
----------
coherence: float
Between 0 and 1, indicates the degree of coherence between voters having similar embeddings.
If 0, the ratings are purely random. If 1, the ratings are automatically deduced
from `embeddings` and `ratings_dim_candidate`.
ratings_dim_candidate: np.ndarray or list
An array with shape :attr:`n_dim`, :attr:`n_candidates`. The coefficient
`ratings_dim_candidate[dim, candidate]` is the score given by the group represented by the dimension `dim`
to the `candidate`. By default, it is set at random with a uniform distribution in the interval
[`minimum_random_rating`, `maximum_random_rating`].
n_dim: int
The number of dimension of the embeddings. Used to generate `ratings_dim_candidate` if it is not specified.
n_candidates: int
The number of candidates. Used to generate `ratings_dim_candidate` if it is not specified.
minimum_random_rating: float
Minimum rating for the random part.
maximum_random_rating: float
Maximum rating for the random part.
clip: bool
If true, the final ratings are clipped in the interval [`minimum_random_rating`, `maximum_random_rating`].
Examples
--------
>>> np.random.seed(42)
>>> embeddings = Embeddings(np.array([[0, 1], [1, 0], [1, 1]]), norm=True)
>>> generator = RatingsFromEmbeddingsCorrelated(coherence=.5, ratings_dim_candidate=np.array([[.8,.4],[.1,.7]]))
>>> generator(embeddings)
Ratings([[0.23727006, 0.82535715],
[0.76599697, 0.49932924],
[0.30300932, 0.35299726]])
"""
def __init__(self, coherence=0, ratings_dim_candidate=None, n_dim=None, n_candidates=None,
minimum_random_rating=0, maximum_random_rating=1, clip=False):
if ratings_dim_candidate is None:
ratings_dim_candidate = (
np.random.rand(n_dim, n_candidates) * (maximum_random_rating - minimum_random_rating)
+ minimum_random_rating
)
else:
if n_dim is not None and n_dim != ratings_dim_candidate.shape[0]:
raise ValueError("n_dim should be omitted or equal to ratings_dim_candidate.shape[0].")
if n_candidates is not None and n_candidates != ratings_dim_candidate.shape[1]:
raise ValueError("n_candidates should be omitted or equal to ratings_dim_candidate.shape[1].")
ratings_dim_candidate = np.array(ratings_dim_candidate)
n_dim, n_candidates = ratings_dim_candidate.shape
# Store variables
self.coherence = coherence
self.ratings_dim_candidate = ratings_dim_candidate
self.n_dim = n_dim
self.minimum_random_rating = minimum_random_rating
self.maximum_random_rating = maximum_random_rating
self.clip = clip
super().__init__(n_candidates)
def __call__(self, embeddings, *args):
"""
This method generate ratings from the embeddings, possibly with a random component.
Parameters
----------
embeddings : Embeddings
Return
------
ratings : Ratings
"""
embeddings = Embeddings(embeddings, norm=True)
ratings_automatic = embeddings ** 2 @ self.ratings_dim_candidate
ratings_random = RatingsGeneratorUniform(
n_voters=embeddings.n_voters,
minimum_rating=self.minimum_random_rating,
maximum_rating=self.maximum_random_rating
)(self.n_candidates)
ratings = self.coherence * ratings_automatic + (1 - self.coherence) * ratings_random
if self.clip:
ratings = np.clip(ratings, self.minimum_random_rating, self.maximum_random_rating)
return Ratings(ratings)