Source code for cornac.metrics.ranking

# -*- coding: utf-8 -*-

"""
@author: Aghiles Salah
"""
import numpy as np
from ..utils.util_functions import which_


# todo: take into account 'm' parameter
[docs]class NDCG: """Normalized Discount Cumulative Gain. Parameters ---------- m: int, optional, default: None The number of items in the top@m list, \ if None then all items are considered to compute NDCG. name: string, value: 'NDCG' Name of the measure. type: string, value: 'ranking' Type of the metric, e.g., "ranking". """ def __init__(self, m=None): self.name = 'NDCG' self.type = 'ranking' self.m = m # Compute nDCG for a single user i def compute(self, data_test, reclist): # Compute Ideal DCG for user i irankTest_i = np.array(range(1, len(which_(data_test, '>', 0)) + 1)) irankTest_i = irankTest_i + 1 irankTest_i = np.log2(irankTest_i) idcg_i = sum(np.divide(1, irankTest_i)) # Compute DCG for user i rankTest_i = np.where(np.in1d(reclist, which_(data_test, '>', 0)))[0] rankTest_i = rankTest_i + 1 + 1 # the second +1 because indices starst from 0 in python rankTest_i = np.log2(rankTest_i) dcg_i = sum(np.divide(1, rankTest_i)) # Compute nDCG for user i ndcg_i = dcg_i / idcg_i return ndcg_i
# todo: take into account 'm' parameter
[docs]class NCRR: """Normalized Cumulative Reciprocal Rank. Parameters ---------- m: int, optional, default: None The number of items in the top@m list, \ if None then all items are considered to compute NDCG. name: string, value: 'NCRR' Name of the measure. type: string, value: 'ranking' Type of the metric, e.g., "ranking". """ def __init__(self, m=None): self.name = 'NCRR' self.m = m self.type = 'ranking' # Compute nCRR for a single user i def compute(self, data_test, reclist): # Compute Ideal DCG for user i irankTest_i = np.array(range(1, len(which_(data_test, '>', 0)) + 1)) irankTest_i = irankTest_i icrr_i = sum(np.divide(1, irankTest_i)) #### Compute DCG for user i rankTest_i = np.where(np.in1d(reclist, which_(data_test, '>', 0)))[0] rankTest_i = rankTest_i + 1 # the +1 because indices starst from 0 in python crr_i = sum(np.divide(1, rankTest_i)) # Compute nDCG for user i ncrr_i = crr_i / icrr_i return ncrr_i
[docs]class MRR: """Mean Reciprocal Rank. Parameters ---------- name: string, value: 'MRR' Name of the measure. type: string, value: 'ranking' Type of the metric, e.g., "ranking". """ def __init__(self): self.name = 'MRR' self.type = 'ranking' # Compute MRR for a single user i def compute(self, data_test, reclist): rankTest_i = np.where(np.in1d(reclist, which_(data_test, '>', 0)))[0] # if rankTest_i: mrr_i = np.divide(1, (rankTest_i[0] + 1)) # +1 beacause indeces start from 0 in python # else: # mrr_i = 0 # print('Error! only users with at least one heldout item should be evaluated') return mrr_i
class MeasureAtM: def __init__(self, m=20, name=None): self.name = name self.m = m self.type = 'ranking' self.tp = None self.tp_fn = None self.tp_fp = None # Evaluate TopMlist for a single user: Precision@M, Recall@M, F-meansure@M (F1) def measures_at_m(self, data_test, reclist): data_test_bin = np.full(len(data_test), 0) data_test_bin[which_(data_test, '>', 0)] = 1 pred = np.full(len(data_test), 0) pred[reclist[range(0, self.m)]] = 1 self.tp = np.sum(pred * data_test_bin) self.tp_fn = np.sum(data_test_bin) self.tp_fp = np.sum(pred)
[docs]class Precision(MeasureAtM): """Precision@M. Parameters ---------- m: int, optional, default: 20 The number of items in the top@m list. name: string, value: 'Precision@m' Name of the measure. type: string, value: 'ranking' Type of the metric, e.g., "ranking". """ def __init__(self, m=20): MeasureAtM.__init__(self, m=m, name="Precision@" + str(m)) # Compute Precision@M for a single user i def compute(self, data_test, reclist): self.measures_at_m(data_test, reclist) prec = self.tp / self.tp_fp return prec
[docs]class Recall(MeasureAtM): """Recall@M. Parameters ---------- m: int, optional, default: 20 The number of items in the top@m list. name: string, value: 'Recall@m' Name of the measure. type: string, value: 'ranking' Type of the metric, e.g., "ranking". """ def __init__(self, m=20): MeasureAtM.__init__(self, m=m, name="Recall@" + str(m)) # Compute Precision@M for a single user i def compute(self, data_test, reclist): self.measures_at_m(data_test, reclist) rec = self.tp / self.tp_fn return rec
[docs]class FMeasure(MeasureAtM): """F-measure@M. Parameters ---------- m: int, optional, default: 20 The number of items in the top@m list. name: string, value: 'F1@m' Name of the measure. type: string, value: 'ranking' Type of the metric, e.g., "ranking". """ def __init__(self, m=20): MeasureAtM.__init__(self, m=m, name="F1@" + str(m)) # Compute Precision@M for a single user i def compute(self, data_test, reclist): self.measures_at_m(data_test, reclist) prec = self.tp / self.tp_fp rec = self.tp / self.tp_fn if (prec + rec): f1 = 2 * (prec * rec) / (prec + rec) else: f1 = 0 return f1