Mean Average Precision (@k) や Mean Reciprocal Rank (@k) という、レコメンドのオフライン評価で使われる指標があるのですが、scikit-learn では計算できなさげだったので、ChatGPT先生に書いてもらいました。
ちなみにMAPの説明はここが分かりやすかった。
mAP (mean average precision) for Recommender systems and Object detection algorithms
Before we start, I would like to point out this blog is my understanding of the other blogs and source code that I have mentioned under the…
MAPのコード
import numpy as np
def map_at_k(y_true, y_scores, k=None):
"""
Computes Mean Average Precision at K (MAP@K)
Parameters:
y_true: np.ndarray of shape (n_samples, n_labels)
Binary indicator matrix of relevant items (1 if relevant, 0 otherwise)
y_scores: np.ndarray of shape (n_samples, n_labels)
Predicted scores for each label
k: int or None, default=None
Number of top elements to consider. If None, considers all elements.
Returns:
float: MAP@K score
"""
n_samples, n_labels = y_true.shape
avg_precisions = []
for i in range(n_samples):
# Sort indices by score in descending order
sorted_indices = np.argsort(y_scores[i])[::-1]
if k is not None:
sorted_indices = sorted_indices[:k]
relevant = y_true[i][sorted_indices]
# Compute AP@K
num_hits = 0.0
score = 0.0
for j, rel in enumerate(relevant):
if rel == 1:
num_hits += 1.0
score += num_hits / (j + 1.0)
# Avoid division by zero
relevant_count = np.sum(y_true[i])
if relevant_count == 0:
avg_precisions.append(0.0) # No relevant items, AP is 0
else:
avg_precisions.append(score / min(relevant_count, k if k is not None else n_labels))
return np.mean(avg_precisions)
# Example usage
y_true = np.array([[0, 0, 1, 1], [0, 0, 0, 0]]) # 2nd sample has no relevant items
y_scores = np.array([[0.1, 0.4, 0.35, 0.8], [0.2, 0.3, 0.5, 0.1]])
k = None
print("MAP@{}:".format(k), map_at_k(y_true, y_scores, k))
MRRのコード
import numpy as np
def mean_reciprocal_rank_at_k(y_true, y_scores, k=None):
"""
Computes Mean Reciprocal Rank at K (MRR@K)
Parameters:
y_true: np.ndarray of shape (n_samples, n_labels)
Binary indicator matrix of relevant items (1 if relevant, 0 otherwise)
y_scores: np.ndarray of shape (n_samples, n_labels)
Predicted scores for each label
k: int or None, default=None
Number of top elements to consider. If None, considers all elements.
Returns:
float: MRR@K score
"""
n_samples, n_labels = y_true.shape
reciprocal_ranks = []
for i in range(n_samples):
sorted_indices = np.argsort(y_scores[i])[::-1] # Sort by predicted scores
if k is not None:
sorted_indices = sorted_indices[:k]
relevant = y_true[i][sorted_indices]
# Find the rank of the first relevant item
rank = np.where(relevant == 1)[0]
if rank.size > 0:
reciprocal_ranks.append(1.0 / (rank[0] + 1)) # Convert to 1-based index
else:
reciprocal_ranks.append(0.0) # No relevant items found
return np.mean(reciprocal_ranks)
# Example usage
y_true = np.array([[0, 0, 1, 1], [0, 0, 0, 1]])
y_scores = np.array([[0.1, 0.4, 0.35, 0.8], [0.2, 0.3, 0.5, 0.9]])
k = 3
print("MRR@{}:".format(k), mean_reciprocal_rank_at_k(y_true, y_scores, k))
コメント