def winner_distance(r1, r2, reverse=False): """ Asymmetrical winner distance. This distance is the rank of the winner of r1 in r2, normalized by the number of candidates. (rank(r1 winner)) - 1 / (n - 1) Assuming no ties. Args: r1: 1D vector representing a judge. r2: 1D vector representing a judge. reverse: If True, lower is better. """ r1, r2 = np.array(r1), np.array(r2) if reverse: w1 = np.argmin(r1) # r1 winner else: w1 = np.argmax(r1) # r1 winner return (rk.rank(r2)[w1] - 1) / (len(r2) - 1)
def kendall_w(matrix, axis=0, ties=False): """ Kendall's W coefficient of concordance. See https://en.wikipedia.org/wiki/Kendall%27s_W for more information. Args: matrix: Preference matrix. axis: Axis of judges. ties: If True, apply the correction for ties """ if ties: return kendall_w_ties(matrix, axis=axis) matrix = rk.rank(matrix, axis=1 - axis) # compute on ranks m = matrix.shape[axis] # judges n = matrix.shape[1 - axis] # candidates denominator = m**2 * (n**3 - n) rating_sums = np.sum(matrix, axis=axis) S = n * np.var(rating_sums) return 12 * S / denominator
def kendall_w_ties(matrix, axis=0): """ Kendall's W coefficient of concordance with correction for ties. The goal of this correction is to avoid having a lower score in the presence of ties in the rankings. Args: matrix: Preference matrix. axis: Axis of judges. """ if axis == 1: matrix = matrix.T m = matrix.shape[0] # judges n = matrix.shape[1] # candidates matrix = rk.rank(matrix, axis=1) # compute on ranks T = [] # correction factors, one by judge for j in range(m): _, counts = np.unique(matrix[j], return_counts=True) # tied groups correction = np.sum([(t**3 - t) for t in counts]) T.append(correction) denominator = m**2 * n * (n**2 - 1) - m * np.sum(T) sum = np.sum([r**2 for r in np.sum(matrix, axis=0)]) numerator = 12 * sum - 3 * m**2 * n * (n + 1)**2 return numerator / denominator