def run(_K, _recommended_artists): # Initialize variables to hold performance measures avg_prec = 0 # mean precision avg_rec = 0 # mean recall df_a_file = FileCache("DF_age", _K, _recommended_artists) df_c_file = FileCache("DF_country", _K, _recommended_artists) df_g_file = FileCache("DF_gender", _K, _recommended_artists) # For all users in our data (UAM) no_users = UAM.shape[0] no_artists = UAM.shape[1] for u in range(0, no_users): # Get seed user's artists listened to u_aidx = np.nonzero(UAM[u, :])[0] if NF >= len(u_aidx) or u == no_users - 1: continue # Split user's artists into train and test set for cross-fold (CV) validation fold = 0 kf = cross_validation.KFold( len(u_aidx), n_folds=NF) # create folds (splits) for 5-fold CV for train_aidx, test_aidx in kf: # for all folds if VERBOSE: print "User: "******", Fold: " + str(fold) + ", Training items: " + str( len(train_aidx)) + ", Test items: " + str( len(test_aidx) ), # the comma at the end avoids line break # Call recommend function copy_UAM = UAM.copy( ) # we need to create a copy of the UAM, otherwise modifications within recommend function will effect the variable ############################################### ## Combine CB and CF together so we get a HF ## ############################################### dict_rec_aidx_DF_A = df_a_file.read_for_hybrid(u, fold) dict_rec_aidx_DF_C = df_c_file.read_for_hybrid(u, fold) dict_rec_aidx_DF_G = df_g_file.read_for_hybrid(u, fold) # @JPEER check in group if that solution is fair enough if len(dict_rec_aidx_DF_A) == 0 or len( dict_rec_aidx_DF_C) == 0 or len(dict_rec_aidx_DF_G) == 0: continue # Fuse scores given by CF and by CB recommenders # First, create matrix to hold scores per recommendation method per artist scores = np.zeros(shape=(3, no_artists), dtype=np.float32) # Add scores from CB and CF recommenders to this matrix for aidx in dict_rec_aidx_DF_A.keys(): scores[0, aidx] = dict_rec_aidx_DF_A[aidx] for aidx in dict_rec_aidx_DF_C.keys(): scores[1, aidx] = dict_rec_aidx_DF_C[aidx] for aidx in dict_rec_aidx_DF_G.keys(): scores[2, aidx] = dict_rec_aidx_DF_G[aidx] # Apply aggregation function (here, just take arithmetic mean of scores) scores_fused = np.mean(scores, axis=0) # Sort and select top K_HR artists to recommend sorted_idx = np.argsort(scores_fused) sorted_idx_top = sorted_idx[-_recommended_artists:] # Put (artist index, score) pairs of highest scoring artists in a dictionary dict_rec_aidx = {} for i in range(0, len(sorted_idx_top)): dict_rec_aidx[sorted_idx_top[i]] = scores_fused[ sorted_idx_top[i]] # Distill recommended artist indices from dictionary returned by the recommendation functions rec_aidx = dict_rec_aidx.keys() if VERBOSE: print "Recommended items: ", len(rec_aidx) # Compute performance measures correct_aidx = np.intersect1d( u_aidx[test_aidx], rec_aidx) # correctly predicted artists # TP - True Positives is amount of overlap in recommended artists and test artists # FP - False Positives is recommended artists minus correctly predicted ones TP = len(correct_aidx) FP = len(np.setdiff1d(rec_aidx, correct_aidx)) # Precision is percentage of correctly predicted among predicted # Handle special case that not a single artist could be recommended -> by definition, precision = 100% if len(rec_aidx) == 0: prec = 100.0 else: prec = 100.0 * TP / len(rec_aidx) # Recall is percentage of correctly predicted among all listened to # Handle special case that there is no single artist in the test set -> by definition, recall = 100% if len(test_aidx) == 0: rec = 100.0 else: rec = 100.0 * TP / len(test_aidx) # add precision and recall for current user and fold to aggregate variables avg_prec += prec / (NF * no_users) avg_rec += rec / (NF * no_users) # Output precision and recall of current fold if VERBOSE: print("\tPrecision: %.2f, Recall: %.2f" % (prec, rec)) # Increase fold counter fold += 1 f1_score = 2 * ((avg_prec * avg_rec) / (avg_prec + avg_rec)) # Output mean average precision and recall if VERBOSE: print("\nMAP: %.2f, MAR %.2f, F1 Scrore: %.2f" % (avg_prec, avg_rec, f1_score)) print("%.3f, %.3f" % (avg_prec, avg_rec)) print("K neighbors " + str(K)) print("Recommendation: " + str(_recommended_artists)) data = {} data['f1_score'] = f1_score data['avg_prec'] = avg_prec data['avg_rec'] = avg_rec data['recommended'] = False return data
def run(_K, _recommended_artists): avg_prec = 0 avg_rec = 0 no_users = UAM.shape[0] no_artists = UAM.shape[1] cf_file = FileCache("CF", _K, _recommended_artists) cb_file = FileCache("CB_Wiki", _K, _recommended_artists) pb_file = FileCache("PB", 1, _recommended_artists) recommended_artists = {} for u in range(0, no_users): # Get seed user's artists listened to u_aidx = np.nonzero(UAM[u, :])[0] if NF >= len(u_aidx) or u == no_users - 1: continue # Split user's artists into train and test set for cross-fold (CV) validation fold = 0 kf = cross_validation.KFold( len(u_aidx), n_folds=NF) # create folds (splits) for 5-fold CV for train_aidx, test_aidx in kf: # for all folds # Show progress if VERBOSE: print "User: "******", Fold: " + str(fold) + ", Training items: " + str( len(train_aidx)) + ", Test items: " + str( len(test_aidx) ), # the comma at the end avoids line break # Call recommend function copy_UAM = UAM.copy( ) # we need to create a copy of the UAM, otherwise modifications within recommend function will effect the variable dict_rec_aidx_CB = cb_file.read_for_hybrid( u, fold) #recommend_CB(AAM, u_aidx[train_aidx], _K) dict_rec_aidx_PB = pb_file.read_for_hybrid( u, fold ) #recommend_PB(copy_UAM, u_aidx[train_aidx], _recommended_artists) dict_rec_aidx_CF = cf_file.read_for_hybrid( u, fold ) #recommend_CF(copy_UAM, u_aidx[train_aidx], _recommended_artists) # @JPEER check in group if that solution is fair enough if len(dict_rec_aidx_CB) == 0 or len(dict_rec_aidx_PB) == 0 or len( dict_rec_aidx_CF) == 0: continue # Fuse scores given by CB and by PB recommenders # First, create matrix to hold scores per recommendation method per artist scores = np.zeros(shape=(3, no_artists), dtype=np.float32) # Add scores from CB and CF recommenders to this matrix for aidx in dict_rec_aidx_CB.keys(): scores[0, aidx] = dict_rec_aidx_CB[aidx] for aidx in dict_rec_aidx_PB.keys(): scores[1, aidx] = dict_rec_aidx_PB[aidx] for aidx in dict_rec_aidx_CF.keys(): scores[2, aidx] = dict_rec_aidx_CF[aidx] # Convert scores to ranks ranks = np.zeros(shape=(3, no_artists), dtype=np.int16) # init rank matrix for m in range(0, scores.shape[0]): # for all methods to fuse aidx_nz = np.nonzero( scores[m])[0] # identify artists with positive scores scores_sorted_idx = np.argsort( scores[m, aidx_nz] ) # sort artists with positive scores according to their score # Insert votes (i.e., inverse ranks) for each artist and current method for a in range(0, len(scores_sorted_idx)): ranks[m, aidx_nz[scores_sorted_idx[a]]] = a + 1 # Sum ranks over different approaches ranks_fused = np.sum(ranks, axis=0) # Sort and select top K_HR artists to recommend sorted_idx = np.argsort(ranks_fused) sorted_idx_top = sorted_idx[-_recommended_artists:] # Put (artist index, score) pairs of highest scoring artists in a dictionary dict_rec_aidx = {} for i in range(0, len(sorted_idx_top)): dict_rec_aidx[sorted_idx_top[i]] = ranks_fused[ sorted_idx_top[i]] # Distill recommended artist indices from dictionary returned by the recommendation functions rec_aidx = dict_rec_aidx.keys() if VERBOSE: print "Recommended items: ", len(rec_aidx) # Compute performance measures correct_aidx = np.intersect1d( u_aidx[test_aidx], rec_aidx) # correctly predicted artists # True Positives is amount of overlap in recommended artists and test artists TP = len(correct_aidx) # False Positives is recommended artists minus correctly predicted ones FP = len(np.setdiff1d(rec_aidx, correct_aidx)) # Precision is percentage of correctly predicted among predicted # Handle special case that not a single artist could be recommended -> by definition, precision = 100% if len(rec_aidx) == 0: prec = 100.0 else: prec = 100.0 * TP / len(rec_aidx) # Recall is percentage of correctly predicted among all listened to # Handle special case that there is no single artist in the test set -> by definition, recall = 100% if len(test_aidx) == 0: rec = 100.0 else: rec = 100.0 * TP / len(test_aidx) # add precision and recall for current user and fold to aggregate variables avg_prec += prec / (NF * no_users) avg_rec += rec / (NF * no_users) # Output precision and recall of current fold if VERBOSE: print("\tPrecision: %.2f, Recall: %.2f" % (prec, rec)) # Increase fold counter fold += 1 # Output mean average precision and recall if VERBOSE: print("\nMAP: %.2f, MAR %.2f" % (avg_prec, avg_rec)) print("%.3f, %.3f" % (avg_prec, avg_rec)) f1_score = 2 * ((avg_prec * avg_rec) / (avg_prec + avg_rec)) data = {} data['avg_prec'] = avg_prec data['avg_rec'] = avg_rec data['f1_score'] = f1_score data['recommended'] = False return data
def run(_K, _recommended_artists): """ Function to run an evaluation experiment """ # Initialize variables to hold performance measures avg_prec = 0 # mean precision avg_rec = 0 # mean recall cb_file = FileCache("CB_Wiki", _K, _recommended_artists) cf_file = FileCache("CF", _K, _recommended_artists) # For all users in our data (UAM) no_users = UAM.shape[0] for u in range(0, no_users): # Get seed user's artists listened to # u_aidx = np.nonzero(UAM[u, :])[0] u_aidx = np.nonzero(UAM[u, :])[0] if NF >= len(u_aidx) or u == no_users - 1: continue # Split user's artists into train and test set for cross-fold (CV) validation fold = 0 # create folds (splits) for 10-fold CV kf = cross_validation.KFold(len(u_aidx), n_folds=NF) # For all folds for train_aidx, test_aidx in kf: if VERBOSE: print "User: "******", Fold: " + str(fold) + ", Training items: " + str( len(train_aidx)) + ", Test items: " + str( len(test_aidx)), # Create a copy of the UAM, otherwise modifications within recommend function will effect the variable copy_UAM = UAM.copy() # Call recommend function rec_aidx_CF = cf_file.read_for_hybrid( u, fold) # recommend_CF(copy_UAM, u, u_aidx[train_aidx]) rec_aidx_CB = cb_file.read_for_hybrid( u, fold) # recommend_CB(AAM, u_aidx[train_aidx], _K) # @JPEER check in group if that solution is fair enough if len(rec_aidx_CF) == 0 or len(rec_aidx_CB) == 0: continue # Return the sorted, unique values that are in both of the input arrays. rec_aidx = np.intersect1d(rec_aidx_CB, rec_aidx_CF) if VERBOSE: print "Items CB: " + str(len(rec_aidx_CB)) print "Items CF: " + str(len(rec_aidx_CF)) print "Recommended items: " + str(len(rec_aidx)) print "Predicted to be: " + str(_recommended_artists) ################################ # Compute performance measures # ################################ # Correctly predicted artists correct_aidx = np.intersect1d(u_aidx[test_aidx], rec_aidx) # TP - True Positives is amount of overlap in recommended artists and test artists # FP - False Positives is recommended artists minus correctly predicted ones TP = len(correct_aidx) FP = len(np.setdiff1d(rec_aidx, correct_aidx)) # Precision is percentage of correctly predicted among predicted # Handle special case that not a single artist could be recommended -> by definition, precision = 100% if len(rec_aidx) == 0: prec = 100.0 else: prec = 100.0 * TP / len(rec_aidx) # Recall is percentage of correctly predicted among all listened to # Handle special case that there is no single artist in the test set -> by definition, recall = 100% if len(test_aidx) == 0: rec = 100.0 else: rec = 100.0 * TP / len(test_aidx) # add precision and recall for current user and fold to aggregate variables avg_prec += prec / (NF * no_users) avg_rec += rec / (NF * no_users) # Output precision and recall of current fold if VERBOSE: print("\tPrecision: %.2f, Recall: %.2f" % (prec, rec)) # Increase fold counter fold += 1 f1_score = 2 * ((avg_prec * avg_rec) / (avg_prec + avg_rec)) # Output mean average precision and recall if VERBOSE: print("MAP: %.3f, MAR: %.3f, F1 Score: %.3f" % (avg_prec, avg_rec, f1_score)) print("K neighbors: " + str(_K)) print("Recommendations: " + str(_recommended_artists)) data = {} data['avg_prec'] = avg_prec data['avg_rec'] = avg_rec data['f1_score'] = f1_score data['recommended'] = False return data