Source code for cornac.metrics.recom_metrics

# -*- 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