Module ranky.generator

Expand source code
#########################
#### JUDGE GENERATOR ####
#########################

import numpy as np
import random
import ranky.ranking as rk

class Generator():
    def __init__(self):
        """ Create a Generator object.
        """
        self.r = None

    def fit(self, r):
        """ Store the reference ranking.
        """
        if isinstance(r, int):
            self.r = list(range(r))
        else:
            if len(r) < 2:
                raise Exception('The reference ranking must contains at least two candidates.')
            self.r = r

    def sample(self, n=1, return_single=True, **kwargs):
        """ Sample judge according to the function.

        Args:
            n: number of samples to draw.
            return_single: if True, return a simple 1D array when n = 1.
        """
        if self.r is None:
            raise Exception('The generator must be fitted before sampling.')
        if n == 1 and return_single:
            return np.array(self._sample(**kwargs)) # return one array
        return np.array([self._sample(**kwargs) for _ in range(n)]).T # return a matrix

    def _sample(self):
        """ Sampling function to be re-written when inheriting this class.
        """
        return self.r

class SwapGenerator(Generator):
    def _sample(self, n=1, N=1, p=1):
        """ Sample n judges by swaping neighbors N times with probability p.

        Args:
            n: number of samples to draw.
            N: number swapings.
            p: probability (in ]0;1]) of disturbing on each iteration.
        """
        return neighbors_swap(self.r, N=N, p=p)

class GaussianGenerator(Generator):
    def _sample(self, n=1, loc=0, scale=1):
        """ Sample n judges by normally disturb the original ranking.

        Args:
            n: number of samples to draw.
        """
        return gaussian_noise(self.r, loc=loc, scale=scale)

################
###  NOISES  ###
################

def neighbors_swap(r, N=1, p=1):
    """ Swap random neighbors n times with probability p.

    Args:
        r: the ranking to disturb.
        n: number of iterations.
        p: probability (in ]0;1]) of disturbing on each iteration.
    """
    if (p <= 0) or (p > 1):
        raise('p must be in ]0;1]')
    _r = r.copy()
    for _ in range(N):
        i1 = np.random.randint(len(r) - 1) # uniform selection
        i2 = i1 + 1
        if np.random.randint(1/p) == 0: # probability
            _r[i1], _r[i2] = _r[i2], _r[i1] # swap neighbors
    return _r

def ranking_noise(r, method='swap', n=1, p=1):
    """ Ranking noise.

    Args:
        r: the ranking to disturb.
        method: 'swap' or 'tie'.
        n: number of iterations.
        p: probability of disturbing on each iteration in ]0;1].
    """
    if (p <= 0) or (p > 1):
        raise('p must be in ]0;1]')
    _r = r.copy()
    for _ in range(n):
        #i1, i2 = np.random.randint(len(r)), np.random.randint(len(r)) # WARNING: sometimes i1 == i2
        i1, i2 = random.sample(range(len(r)), 2)
        if np.random.randint(1/p) == 0: # probability
            if method == 'swap':
                _r[i1], _r[i2] = _r[i2], _r[i1]
            elif method == 'tie':
                _r[i1] = _r[i2]
            else:
                raise('Unknown ranking noise method: {}.'.format(method))
    return _r

def gaussian_noise(r, loc=0, scale=1):
    if not isinstance(r, np.ndarray):
        r = np.array(r)
    noise = np.random.normal(loc, scale, r.shape)
    return r + noise

Functions

def gaussian_noise(r, loc=0, scale=1)
Expand source code
def gaussian_noise(r, loc=0, scale=1):
    if not isinstance(r, np.ndarray):
        r = np.array(r)
    noise = np.random.normal(loc, scale, r.shape)
    return r + noise
def neighbors_swap(r, N=1, p=1)

Swap random neighbors n times with probability p.

Args

r
the ranking to disturb.
n
number of iterations.
p
probability (in ]0;1]) of disturbing on each iteration.
Expand source code
def neighbors_swap(r, N=1, p=1):
    """ Swap random neighbors n times with probability p.

    Args:
        r: the ranking to disturb.
        n: number of iterations.
        p: probability (in ]0;1]) of disturbing on each iteration.
    """
    if (p <= 0) or (p > 1):
        raise('p must be in ]0;1]')
    _r = r.copy()
    for _ in range(N):
        i1 = np.random.randint(len(r) - 1) # uniform selection
        i2 = i1 + 1
        if np.random.randint(1/p) == 0: # probability
            _r[i1], _r[i2] = _r[i2], _r[i1] # swap neighbors
    return _r
def ranking_noise(r, method='swap', n=1, p=1)

Ranking noise.

Args

r
the ranking to disturb.
method
'swap' or 'tie'.
n
number of iterations.
p
probability of disturbing on each iteration in ]0;1].
Expand source code
def ranking_noise(r, method='swap', n=1, p=1):
    """ Ranking noise.

    Args:
        r: the ranking to disturb.
        method: 'swap' or 'tie'.
        n: number of iterations.
        p: probability of disturbing on each iteration in ]0;1].
    """
    if (p <= 0) or (p > 1):
        raise('p must be in ]0;1]')
    _r = r.copy()
    for _ in range(n):
        #i1, i2 = np.random.randint(len(r)), np.random.randint(len(r)) # WARNING: sometimes i1 == i2
        i1, i2 = random.sample(range(len(r)), 2)
        if np.random.randint(1/p) == 0: # probability
            if method == 'swap':
                _r[i1], _r[i2] = _r[i2], _r[i1]
            elif method == 'tie':
                _r[i1] = _r[i2]
            else:
                raise('Unknown ranking noise method: {}.'.format(method))
    return _r

Classes

class GaussianGenerator

Create a Generator object.

Expand source code
class GaussianGenerator(Generator):
    def _sample(self, n=1, loc=0, scale=1):
        """ Sample n judges by normally disturb the original ranking.

        Args:
            n: number of samples to draw.
        """
        return gaussian_noise(self.r, loc=loc, scale=scale)

Ancestors

Inherited members

class Generator

Create a Generator object.

Expand source code
class Generator():
    def __init__(self):
        """ Create a Generator object.
        """
        self.r = None

    def fit(self, r):
        """ Store the reference ranking.
        """
        if isinstance(r, int):
            self.r = list(range(r))
        else:
            if len(r) < 2:
                raise Exception('The reference ranking must contains at least two candidates.')
            self.r = r

    def sample(self, n=1, return_single=True, **kwargs):
        """ Sample judge according to the function.

        Args:
            n: number of samples to draw.
            return_single: if True, return a simple 1D array when n = 1.
        """
        if self.r is None:
            raise Exception('The generator must be fitted before sampling.')
        if n == 1 and return_single:
            return np.array(self._sample(**kwargs)) # return one array
        return np.array([self._sample(**kwargs) for _ in range(n)]).T # return a matrix

    def _sample(self):
        """ Sampling function to be re-written when inheriting this class.
        """
        return self.r

Subclasses

Methods

def fit(self, r)

Store the reference ranking.

Expand source code
def fit(self, r):
    """ Store the reference ranking.
    """
    if isinstance(r, int):
        self.r = list(range(r))
    else:
        if len(r) < 2:
            raise Exception('The reference ranking must contains at least two candidates.')
        self.r = r
def sample(self, n=1, return_single=True, **kwargs)

Sample judge according to the function.

Args

n
number of samples to draw.
return_single
if True, return a simple 1D array when n = 1.
Expand source code
def sample(self, n=1, return_single=True, **kwargs):
    """ Sample judge according to the function.

    Args:
        n: number of samples to draw.
        return_single: if True, return a simple 1D array when n = 1.
    """
    if self.r is None:
        raise Exception('The generator must be fitted before sampling.')
    if n == 1 and return_single:
        return np.array(self._sample(**kwargs)) # return one array
    return np.array([self._sample(**kwargs) for _ in range(n)]).T # return a matrix
class SwapGenerator

Create a Generator object.

Expand source code
class SwapGenerator(Generator):
    def _sample(self, n=1, N=1, p=1):
        """ Sample n judges by swaping neighbors N times with probability p.

        Args:
            n: number of samples to draw.
            N: number swapings.
            p: probability (in ]0;1]) of disturbing on each iteration.
        """
        return neighbors_swap(self.r, N=N, p=p)

Ancestors

Inherited members