推荐系统评价指标及代码实现

评价指标

指标意义计算方法
用户满意度最重要的指标用户调查或在线实验,如问卷、“满意”按钮、点击率、停留时间、转化率等
预测准确度最重要的系统离线指标根据离线用户行为数据集进行评测,如评分预测使用均方根误差(RMSE)或平均绝对误差(MAE)、TopN推荐使用准确率(Precision)/召回率(recall)
覆盖率对物品长尾的发掘能力定义不同,如推荐出的物品占总物品的比例、信息熵、基尼指数
多样性物品两两之间的不相似性根据相似度定义,如内容相似度、协同过滤相似度
新颖性从没见过的推荐最简单方法是过滤掉有过行为的物品,或是流行度低的物品
惊喜度从没见过但令人满意的推荐目前无公认定义
信任度增加与推荐系统的交互问卷调查

离线优化目标:最大化预测准确度,使覆盖率>A,多样性>B,新颖性>C



公式及代码

1. 用户满意度

采用用户调查或在线实验,如问卷、“满意”按钮、点击率、停留时间、转化率等。



2. 预测准确度

评分预测

用户 u u u,物品 i i i r u i r_{ui} rui为实际评分, r u i ′ r_{ui}^{'} rui为预测评分

均方根误差
RMSE = ∑ u , i ∈ T ( r u i − r u i ′ ) 2 ∣ T ∣ \text{RMSE}=\sqrt{\frac{\sum_{u,i\in T}{\left( r_{ui}-r_{ui}^{'} \right) ^2}}{|T|}} RMSE=Tu,iT(ruirui)2

平均绝对误差
MAE = ∑ u , i ∈ T ∣ r u i − r u i ′ ∣ T \text{MAE}=\frac{\sum_{u,i\in T}{|r_{ui}-r_{ui}^{'}|}}{T} MAE=Tu,iTruirui

均方根误差(RMSE)对系统评测更苛刻,越小越好。

import math


def RMSE(records):
    '''均方根误差'''
    return math.sqrt(sum([(rui - pui) * (rui - pui) for u, i, rui, pui in records]) / len(records))


def MAE(records):
    '''平均绝对误差'''
    return sum([abs(rui - pui) for u, i, rui, pui in records]) / len(records)


if __name__ == '__main__':
    user = ['a', 'b', 'c']
    item = ['Python深度学习', '疯狂Java讲义', 'C++ Primer']
    records = [['a', 'Python深度学习', 4.3, 5], ['a', '疯狂Java讲义', 4.7, 5], ['a', 'C++ Primer', 4.1, 5],
               ['b', 'Python深度学习', 4.0, 5], ['b', '疯狂Java讲义', 3.8, 5], ['b', 'C++ Primer', 4.2, 5],
               ['c', 'Python深度学习', 4.1, 5], ['c', '疯狂Java讲义', 3.0, 5], ['c', 'C++ Primer', 4.9, 5], ]
    print(RMSE(records))  # 1.015983376941878
    print(MAE(records))  # 0.8777777777777778

TopN推荐

TopN推荐更符合实际应用,一般通过准确率/召回率曲线

推荐列表 R ( u ) R(u) R(u),行为列表 T ( u ) T(u) T(u)

召回率
Recall = ∑ u ∈ U ∣ R ( u ) ∩ T ( u ) ∣ ∑ u ∈ U ∣ T ( u ) ∣ \text{Recall}=\frac{\sum_{\text{u}\in \text{U}}{|R\left( u \right) \cap T\left( u \right) |}}{\sum_{u\in U}{|T\left( u \right) |}} Recall=uUT(u)uUR(u)T(u)

准确率
Precision = ∑ u ∈ U ∣ R ( u ) ∩ T ( u ) ∣ ∑ u ∈ U ∣ R ( u ) ∣ \text{Precision}=\frac{\sum_{\text{u}\in \text{U}}{|R\left( u \right) \cap T\left( u \right) |}}{\sum_{u\in U}{|\text{R}\left( u \right) |}} Precision=uUR(u)uUR(u)T(u)

from matplotlib import pyplot as plt


def Recommend(user, N=10):
    '''推荐算法'''
    return ['Python深度学习', '疯狂Java讲义', 'C++ Primer',
            '数学之美', '利用Python进行数据分析', '浪潮之巅',
            '鸟哥的Linux私房菜', '机器学习', '高性能MySQL', '统计学习方法'][:N]


def PrecisionRecall(records, N=10):
    '''准确率和召回率'''
    hit = 0
    precision = 0
    recall = 0
    for user, items in records.items():
        rank = Recommend(user, N)
        hit += len(list(set(rank).intersection(set(items))))
        precision += N
        recall += len(items)
    return [hit / precision, hit / recall]


if __name__ == '__main__':
    records = {'a': ['Python深度学习', '疯狂Java讲义', 'C++ Primer'],
               'b': ['Python深度学习', '数学之美'],
               'c': ['利用Python进行数据分析', '浪潮之巅', 'C++ 机器学习'],
               }
    x = []
    y = []
    for N in range(1, 11):
        Precision, Recall = PrecisionRecall(records, N)
        x.append(Recall)
        y.append(Precision)

    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.xlabel("召回率(Recall)")
    plt.ylabel("准确率(Precision)")
    plt.plot(x, y)
    plt.show()

在这里插入图片描述



3. 覆盖率

推荐出的物品占总物品的比例

用户集合 U U U,给每个用户推荐长度为 N N N的列表 R ( u ) R(u) R(u)
Coverage = ∣ ⋃ u ∈ U R ( u ) ∣ ∣ I ∣ \text{Coverage}=\frac{|\bigcup_{\text{u}\in \text{U}}{R\left( u \right)}|}{|I|} Coverage=IuUR(u)

I = ['Python深度学习', '疯狂Java讲义', 'C++ Primer',
     '数学之美', '利用Python进行数据分析', '浪潮之巅',
     '鸟哥的Linux私房菜', '机器学习', '高性能MySQL', '统计学习方法']


def Coverage(records):
    '''覆盖率'''
    total = []
    for user, items in records.items():
        total += items
    return len(total) / len(I)


if __name__ == '__main__':
    records = {'a': ['Python深度学习', '疯狂Java讲义', 'C++ Primer'],
               'b': ['Python深度学习', '数学之美'],
               'c': ['利用Python进行数据分析', '浪潮之巅', 'C++ 机器学习'],
               }
    print(Coverage(records))  # 0.8

信息熵

H = − ∑ i = 1 n p ( i ) log ⁡   p ( i ) H=-\sum_{i=1}^n{p\left( i \right) \log\text{\ }p\left( i \right)} H=i=1np(i)log p(i)

基尼指数

i j i_{j} ij是按物品流行度 p p p从小到大排序的第 j j j个物品
G = 1 n − 1 ∑ j = 1 n ( 2 j − n − 1 ) p ( i j ) G=\frac{1}{n-1}\sum_{j=1}^n{\left( 2j-n-1 \right) p\left( i_j \right)} G=n11j=1n(2jn1)p(ij)

from operator import itemgetter


def GiniIndex(p):
    j = 1
    n = len(p)
    G = 0
    for item, weight in sorted(p.items(), key=itemgetter(1)):
        G += (2 * j - n - 1) * weight
    return G / float(n - 1)


if __name__ == '__main__':
    records = {'Python深度学习': 0.37,
               '疯狂Java讲义': 0.32,
               'C++ Primer': 0.38,
               '数学之美': 0.43,
               '利用Python进行数据分析': 0.54,
               '浪潮之巅': 0.40,
               '鸟哥的Linux私房菜': 0.07,
               '机器学习': 0.33,
               '高性能MySQL': 0.22,
               '统计学习方法': 0.10}
    print(GiniIndex(records))  # -3.16

备注:以上公式和GiniIndex()均出自《推荐系统实践》,个人感觉是错的。

更正如下:
在这里插入图片描述
A A A B B B为面积
G = A A + B G=\frac{A}{A+B} G=A+BA

import numpy as np
from matplotlib import pyplot as plt
from scipy.interpolate import make_interp_spline


def GiniIndex(p):
    '''基尼系数'''
    cum = np.cumsum(sorted(np.append(p, 0)))
    sum = cum[-1]
    x = np.array(range(len(cum))) / len(p)
    y = cum / sum
    B = np.trapz(y, x=x)
    A = 0.5 - B
    G = A / (A + B)
    '''绘图'''
    plt.rcParams['font.sans-serif'] = ['SimHei']
    fig, ax = plt.subplots()
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')
    ax.spines['bottom'].set_position(('data', -0))
    ax.spines['left'].set_position(('data', 0))
    plt.xticks([0, 1.0])
    plt.yticks([1.0])
    plt.axis('scaled')
    x_smooth = np.linspace(x.min(), x.max(), 100)
    y_smooth = make_interp_spline(x, y)(x_smooth)
    ax.plot(x_smooth, y_smooth, color='black')
    ax.plot(x, x, color='black')
    ax.plot([0, 1, 1, 1], [0, 0, 0, 1], color='black')
    ax.fill_between(x, y)
    ax.fill_between(x, x, y, where=y <= x)
    ax.set_xlabel('物品')
    ax.set_ylabel('流行度')
    plt.show()
    return G


if __name__ == '__main__':
    records = {'Python深度学习': 0.37,
               '疯狂Java讲义': 0.32,
               'C++ Primer': 0.38,
               '数学之美': 0.43,
               '利用Python进行数据分析': 0.54,
               '浪潮之巅': 0.40,
               '鸟哥的Linux私房菜': 0.07,
               '机器学习': 0.33,
               '高性能MySQL': 0.22,
               '统计学习方法': 0.10}
    print(GiniIndex(list(records.values())))  # 0.2424050632911393

在这里插入图片描述
马太效应,即强者更强,弱者更弱。推荐系统初衷是让各种物品能展示给对应的感兴趣人群,但主流推荐算法如协同过滤算法具有马太效应。 G 1 G1 G1为初始用户行为计算的流行度的基尼系数, G 2 G2 G2为推荐列表计算的基尼系数,若 G 2 > G 1 G2>G1 G2>G1,则该推荐算法具有马太效应。



4. 多样性

Diversity ( R ( u ) ) = 1 − ∑ i , j ∈ R ( u ) , i ≠ j s ( i , j ) 1 2 ∣ R ( u ) ∣ ( ∣ R ( u ) ∣ − 1 ) \text{Diversity}\left( R\left( u \right) \right) =1-\frac{\sum_{i,j\in R\left( u \right) ,i\ne j}{s\left( i,j \right)}}{\frac{1}{2}|R\left( u \right) |\left( |R\left( u \right) |-1 \right)} Diversity(R(u))=121R(u)(R(u)1)i,jR(u),i=js(i,j)



5. 新颖性

过滤掉有过行为的物品,或是流行度低的物品。



6. 惊喜度

略。



7. 信任度

略。



参考文献

  1. 推荐系统实践
  2. 基尼系数的计算方法与计算案例
  3. 推荐系统那点事儿
  4. 推荐系统指标评测——覆盖率与基尼系数的算法与应用
  5. 基尼系数如何计算? - 知乎
  6. matplotlib.pyplot.fill
<think>好的,用户需要推荐系统算法评价指标代码实现,使用Python或其他语言的示例。首先,我需要确定常见的评价指标有哪些,比如准确率、召回率、F1值、RMSE、MAE、AUC、NDCG等。然后,我得回忆这些指标的计算方法,并考虑如何在代码实现。 接下来,用户可能希望看到具体的代码示例,所以我要选择几个关键指标来展示。比如,准确率和召回率适用于分类问题,而RMSE和MAE适用于评分预测。AUC和NDCG可能更复杂一些,但也是推荐系统中常用的指标。 然后,我需要检查这些指标实现是否正确。例如,准确率是正确推荐数除以总推荐数,召回率是正确推荐数除以用户实际喜欢的项目数。对于RMSE,需要计算预测评分与实际评分之间的均方根误差。MAE则是平均绝对误差。 对于AUC,可能需要计算ROC曲线下的面积,可以通过sklearn库中的函数来实现。而NDCG则需要考虑排名位置和折扣因子,需要逐步计算每个位置的折损累计增益,再归一化处理。 还要考虑用户可能需要不同语言的代码,但Python是最常用的,所以优先提供Python示例,并提到其他语言如Java或R的实现可能依赖特定库。 然后,我需要引用相关的资料,比如提到协同过滤中的评价指标实现,或者参考已有的代码示例,如用户提供的引用中的车牌识别代码结构,虽然内容不同,但代码结构可能有参考价值。 最后,生成相关问题,帮助用户进一步探索,比如如何选择指标、处理冷启动问题,或者比较不同指标的优缺点。确保问题与推荐系统评价相关,并引导用户深入思考。</think>以下为您提供推荐系统常用评价指标Python实现示例及说明: ### 一、分类评价指标 ```python # 准确率 & 召回率 def precision_recall(y_true, y_pred, k=10): common = set(y_true) & set(y_pred[:k]) precision = len(common) / k recall = len(common) / len(y_true) return precision, recall # F1-Score def f1_score(precision, recall): return 2 * (precision * recall) / (precision + recall + 1e-8) ``` ### 二、评分预测指标 ```python import numpy as np # RMSE(均方根误差) def rmse(y_true, y_pred): return np.sqrt(np.mean((np.array(y_true) - np.array(y_pred))**2)) # MAE(平均绝对误差) def mae(y_true, y_pred): return np.mean(np.abs(np.array(y_true) - np.array(y_pred))) ``` ### 三、排序评价指标 ```python from sklearn.metrics import roc_auc_score # AUC计算 y_score = [0.8, 0.6, 0.4, 0.3] # 预测得分 y_true = [1, 1, 0, 0] print(f"AUC: {roc_auc_score(y_true, y_score)}") # NDCG(归一化折损累计增益) def ndcg(y_true_rank, k=10): dcg = sum(np.divide([2**r -1 for r in y_true_rank[:k]], np.log2(np.arange(2, k+2)))) idcg = sum(np.divide([2**r -1 for r in sorted(y_true_rank, reverse=True)[:k]], np.log2(np.arange(2, k+2)))) return dcg / (idcg + 1e-8) ``` ### 四、其他语言实现提示 1. **Java**:使用Apache Commons Math库实现RMSE/MAE 2. **R语言**:利用`recommenderlab`包中的评估函数 3. **Spark**:调用MLlib的RegressionMetrics/RankingMetrics类 推荐系统评估时需注意:离线评估应保留时间窗口划分数据,在线评估可采用A/B测试[^1]。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XerCis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值