一个完整的Python实现,包括ItemCF协同过滤算法的实现以及召回率、准确率、F1分数和覆盖率等评估指标的计算。将使用Pandas进行数据处理,Scikit-learn进行相似度计算,并编写函数来生成推荐列表和评估模型性能。
首先,需要准备数据。假设有一个用户-物品评分矩阵(可以是显式评分或隐式反馈),表示用户对不同酒店的喜好程度。这里可以使用Pandas来处理数据。
import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
# 假设有以下用户-酒店评分数据
data = {
'user': [1, 1, 1, 2, 2, 3, 3, 3, 4, 5],
'hotel': ['A', 'B', 'C', 'A', 'D', 'B', 'C', 'E', 'F', 'G'],
'rating': [5, 4, 3, 4, 5, 2, 4, 5, 3, 4]
}
df = pd.DataFrame(data)
# 构建用户-酒店评分矩阵
user_hotel_matrix = df.pivot(index='user', columns='hotel', values='rating').fillna(0)
在ItemCF中,通常使用余弦相似度来衡量酒店之间的相似度。
# 计算酒店之间的相似度矩阵
hotel_sim_matrix = cosine_similarity(user_hotel_matrix.T)
hotel_sim_df = pd.DataFrame(hotel_sim_matrix, index=user_hotel_matrix.columns, columns=user_hotel_matrix.columns)
接下来,需要根据用户的历史行为和酒店相似度来生成推荐列表。对于每个用户,将他之前交互过的酒店与其相似的酒店进行加权求和,得到一个预测评分,然后选择评分最高的几个酒店作为推荐结果。
def recommend_hotels(user_id, user_hotel_matrix, hotel_sim_df, top_n=5):
# 获取用户已经评分过的酒店
user_ratings = user_hotel_matrix.loc[user_id].copy()
rated_hotels = user_ratings[user_ratings > 0].index
# 初始化推荐分数
recommendations = pd.Series(0, index=user_hotel_matrix.columns)
for hotel in rated_hotels:
# 找到与当前酒店相似的其他酒店
similar_hotels = hotel_sim_df[hotel].drop(hotel).sort_values(ascending=False)
# 更新推荐分数
for sim_hotel, similarity in similar_hotels.items():
if user_ratings[sim_hotel] == 0: # 只考虑用户未评分的酒店
recommendations[sim_hotel] += similarity * user_ratings[hotel]
# 排除用户已经评分过的酒店
recommendations.drop(rated_hotels, errors='ignore', inplace=True)
# 返回推荐列表
return recommendations.sort_values(ascending=False).head(top_n).index.tolist()
# 为用户1生成推荐
recommended_hotels = recommend_hotels(1, user_hotel_matrix, hotel_sim_df, top_n=3)
print("Recommended hotels for user 1:", recommended_hotels)
为了评估推荐系统的性能,可以使用召回率(Recall)、准确率(Precision)、F1分数(F1 Score)和覆盖率(Coverage)等指标。假设有一个测试集,其中包含用户的实际偏好(即用户真正喜欢但没有评分的酒店)。可以比较推荐列表与测试集中的酒店,计算这些指标。
# 假设这是用户1的真实偏好(测试集)
true_hotels = ['D', 'E']
# 计算召回率和准确率
def evaluate_recommendations(recommended_hotels, true_hotels):
num_recommended = len(recommended_hotels)
num_true = len(true_hotels)
num_hit = len(set(recommended_hotels).intersection(set(true_hotels)))
precision = num_hit / num_recommended if num_recommended > 0 else 0
recall = num_hit / num_true if num_true > 0 else 0
return precision, recall
# 计算F1分数
def f1_score(precision, recall):
if precision + recall == 0:
return 0
return 2 * (precision * recall) / (precision + recall)
# 计算覆盖率
def item_coverage(recommended_hotels, all_hotels):
return len(set(recommended_hotels)) / len(all_hotels)
# 评估用户1的推荐结果
precision, recall = evaluate_recommendations(recommended_hotels, true_hotels)
f1 = f1_score(precision, recall)
coverage = item_coverage(recommended_hotels, user_hotel_matrix.columns)
print(f"Precision: {precision:.2f}")
print(f"Recall: {recall:.2f}")
print(f"F1 Score: {f1:.2f}")
print(f"Coverage: {coverage:.2f}")
为了更全面地评估推荐系统的性能,还可以计算其他指标,如多样性(Diversity)、新颖性(Novelty)等。
多样性衡量的是推荐列表中酒店之间的差异程度。一个多样化的推荐系统可以为用户提供更广泛的选择,避免推荐过于相似的酒店。
def intra_list_diversity(recommendation_list, similarity_matrix):
n = len(recommendation_list)
if n <= 1:
return 0
diversity = 0
for i in range(n):
for j in range(i + 1, n):
diversity += 1 - similarity_matrix.loc[recommendation_list[i], recommendation_list[j]]
return 2 * diversity / (n * (n - 1))
# 计算推荐列表的多样性
diversity = intra_list_diversity(recommended_hotels, hotel_sim_df)
print(f"Diversity: {diversity:.2f}")
新颖性衡量的是推荐系统推荐的新酒店的比例。新酒店是指那些不常见或用户不太熟悉的酒店。推荐新酒店可以增加用户的兴趣和探索欲望。
# 假设有一个酒店流行度字典,表示每个酒店的历史交互次数
hotel_popularity = {'A': 10, 'B': 8, 'C': 6, 'D': 5, 'E': 4, 'F': 3, 'G': 2}
def average_popularity(recommended_hotels, hotel_popularity):
return np.mean([hotel_popularity.get(hotel, 0) for hotel in recommended_hotels])
# 计算推荐列表的平均流行度(越低越好)
novelty = average_popularity(recommended_hotels, hotel_popularity)
print(f"Novelty (Average Popularity): {novelty:.2f}")
通过上述代码,实现了一个简单的ItemCF协同过滤算法,并计算了召回率、准确率、F1分数、覆盖率、多样性和新颖性等评估指标。这些指标可以帮助更全面地了解推荐系统的性能,并根据需要进行优化。