Python 人工智能实战:推荐算法
1.背景介绍
Recommender System主要基于用户的商品或服务进行推荐。它通过分析用户的浏览行为(如淘宝)、购买记录(如网易云音乐)以及兴趣爱好(如哔哩哔哩)等数据来为用户提供符合其使用习惯的商品或服务。Recommender System常见于电商网站(如淘宝)、音乐平台(如网易云音乐)以及视频网站(如哔哩哔哩)等场景中。它属于一种新型的信息过滤和个性化推荐工具,并通过挖掘用户间的相似性及其喜好倾向来将那些尚未被明确针对性推广的商品和服务进行精准定位与展示。如今,Recommender System已成为互联网发展的重要领域之一。
在当今互联网环境下, 建构与部署推
荐系统都面临着巨大的挑战. 当今社会面临着海量数据, 多样化的数据类型以及高维特征空间等复杂情况, 准确且实时地构建这样的系统显得尤为困难. 基于以上分析, 本文旨在探讨如何设计并实现一套适用于实际生产环境中的简单推荐算法.
简单来说,推荐系统可以分为两步:
候选池构建:基于用户的使用习惯与偏好,在海量的历史行为数据中筛选出具有商业价值的商品与服务
个性化推荐:基于用户的特定需求偏好,在候选商品和服务中筛选出优质项目进行推荐。
该推荐系统主要应用于电子商务、金融、社交网络、视频、音乐等领域。
2.核心概念与联系
2.1 协同过滤(Collaborative Filtering)
协作推荐算法是一种典型的基于用户的推荐方法,在实际应用中多用于分析用户行为特征并据此生成个性化服务方案。其核心在于通过建立完善的用户行为数据模型来实现精准匹配与信息筛选,在不同应用场景下主要依据不同的核心考量可将该类算法划分为三类:一种是存储在内存中的协同过滤方法;另一种是建立在预定义模型基础上的具体实现;第三种则是综合运用多种技术手段进行协同过滤的方法。
2.1.1 用户-商品关系矩阵
为了更好地确定一种用户与商品之间的关系矩阵形式,在此基础之上假设存在两类典型的关系模式:
互动关系通常被定义为User-Item Interactions的形式。具体而言,则是基于用户的评价和购买行为。这些信息通常以数值形式记录。例如,在评分系统中,假设用户U对商品I给出了五星评分,则其交互记录可表示为Rui=5;如果用户U购买了商品I,则相应的交互标记是Riu=1;而如果用户U既未给出评分也未进行购买行为,则相应的标记是Ruiu=0。
- 相似关系(User-User Similarities)。即两个用户之间存在共同的兴趣爱好。可以用用户的相似度来衡量这种关系强度。例如,在推荐系统中,假设用户的U和V都喜欢科幻小说,则他们的相似度计算公式为cosθ=1;
那么,用户-商品关系矩阵便可以定义如下:
| I1 | I2 | I3 | ... | In | |
|---|---|---|---|---|---|
| UserA | Ruia1 | Ruia2 | Ruia3 | ... | RuiaN |
| UserB | Ruib1 | Ruib2 | Ruib3 | ... | RuibN |
| . | . | . | . | . | . |
| . | . | . | . | . | . |
| . | . | . | . | . | . |
| UserZ | Ruiz1 | Ruiz2 | Ruiz3 | ... | RuizN |
其中
2.1.2 基于用户的推荐方法
接下来就可以采用以用户行为为基础的推荐系统来为用户推荐商品主要采用以下这些策略
该种方法认为这一现象具有显著的影响。其基本思路是通过计算用户U的邻居集合,并识别出这些邻居对商品评价最高的一类并将其推荐给用户U
-
基于评分机制的协同过滤方法(Rating-based Collaborative Filtering Method):该方法旨在通过分析用户对商品的评价来进行个性化推荐。首先通过分析相似用户的评分类信息来预测用户U对未评分类商品的潜在兴趣。接着按照各商品被预测为感兴趣程度排序,在结果中选取排名靠前的K种商品向用户U展示。
-
主要依据召回能力的协同过滤法(Recall-Oriented Collaborative Filtering Method):类似于之前的策略,在此方法中仅关注相关商品
协同过滤技术基于矩阵分解(Matrix Factorization-based Collaborative Filtering Method):即通过将用户的商品偏好关系矩阵分解为两个低维矩阵来实现推荐系统的核心功能。其中第一个低维向量P代表用户的商品偏好信息(Preference Information),另一个低维向量Q则反映了各商品的整体特征(Overall Item Features)。通过计算这两个向量的点积可以得到用户对所有商品的评分估计(Rating Estimates),并按照评分从高到低排序后推荐给用户的最高评分的商品(Top Recommended Items)
2.1.3 基于物品的推荐方法
除了以用户为中心的推荐方式外(除了基于用户的推荐方法之外),还有一种基于物品特征的推荐方法(还有基于物品的推荐方法),即通过向那些与之兴趣相符的商品进行推荐以实现直接匹配(即直接推荐给用户最感兴趣的商品)。其核心理念在于通过分析用户的购买历史(分析用户之前的购买行为)来识别其偏好(找出他对哪些商品比较感兴趣),进而识别出他对于哪些商品表现出浓厚兴趣(然后针对这些感兴趣的商品进行推荐)。这种模式无需收集或处理任何用户数据(这种方法不需要用户的任何信息),因为它只是根据商品间的关系网络构建与传播机制(它的基本思想是分析用户之前的购买行为)从而为其推送相应商品集合以满足需求(这种方法只需要根据商品之间的关联关系来推荐)。这种模式已经证明具有良好的推广价值(目前这种方法已经非常成功)。
3.核心算法原理和具体操作步骤以及数学模型公式详细讲解
3.1 基础知识
3.1.1 奇异值分解(SVD)
奇异值分解(Singular Value Decomposition, SVD)是一种在矩阵运算领域中被广泛采用的技术手段,在线性代数中具有重要的理论价值和应用前景。它能够将任何一个原始矩阵分解为三个独立的矩阵相乘的结果,并且这种分解方式在数据降维、噪声去除以及信息提取等方面展现出显著的优势。
假设有矩阵A具有尺寸m×n,则其中m代表行数、n代表列数。为了执行奇异值分解(SVD),首先对矩阵A进行零均值化处理(zero mean normalization),即通过从每一列中减去其平均值来实现。这样的处理能够有效减少由于各列间数值差异过大而产生的负面影响。
随后可将该矩陣A進行奇異值分懈為三個矩陣之積的形式:A = U D V^T。其中U為一個m \times m階單位正交矩陣;具體而言,其列向量u_i滿足\sum u_{i,j}^2 = 1;D則為一個m \times n階矩陣,其對角線元素d_1 \geq d_2 \geq \dots \geq d_k(k為奇異值數目);V則為一個n \times n階單位正交矩陣,其列向量v_j滿足\sum v_{j,l}^2 = 1。進一步地,若A為一個m \times n矩陣,則可推論出: U為m \times m, D為m \times n, V為n \times n,並滿足關係式: AV = UD,\quad UA = VD 其中,AV表示左乘以V得到UD,UA則表示左乘以U得到VD。
最终我们可以利用矩阵乘法运算来估计缺失值。假设矩阵A中的某元素位于第i行第j列且缺失,则该元素可表示为U[i][l]与sqrt(d[l])相乘后再与V[l][j]相乘的结果之和(l从1到k),其中k代表奇异值的数量
3.1.2 感知机(Perceptron)
Perceptron这一概念是由英国科学家罗纳德·费舍尔于1957年首次提出的。它属于监督学习范畴,并用于对数据进行二分类处理。其输入为特征向量序列,并根据计算结果划分为+1或-1两类。基本模型通过加权求和各特征值并加入偏差项来判断结果。输出结果则取决于加权输入与偏差项之和是否超过零。其训练机制旨在逐步优化权重系数与偏置参数以最小化误分类率为目标。
3.2 基于用户的协同过滤算法——基于相似用户推荐
该推荐系统采用基于相似用户的协同过滤算法(Similar Users Recommendation)进行运作。其核心原理是通过分析用户的协同过滤行为来识别出与目标用户具有高度相似性的一群用户群体,并结合用户的使用习惯、偏好以及历史行为数据进行商品推荐服务。
3.2.1 数据集划分
我们假定有N名用户以及M种商品。每位用户与其他所有用户的互动关系被构建为一个评分矩阵U。通过奇异值分解SVD对该评分矩阵进行分解得到三个子空间:U = UXΛY^T(其中X是一个m×m阶的正交矩陣),Y也是一个n×n阶的正交矩陣;而Λ则是一个m×n维的对角線矩陣,在其對角線上的元素滿足λ₁ ≥ λ₂ ≥ ... ≥ λₙ
用户体验(UX)可用于用于预测特定用户的商品i评分;其中,U[u][i]表示用户u对商品i的预测评分。
- Λ矩阵可以用来表示用户间的相似度,例如:Λ[u1][u2]表示用户u1和u2的相似度;
YTX可用于体现商品间的关联性关系。如YTX[i1][i2]则具体体现为商品i1与商品i2间的相似程度。
通过分析发现,在推荐算法的设计中,默认情况下通常会采用用户-商品评分矩阵U和商品间关系矩阵Y^TX这两种关键输入数据进行计算与建模。因此,在实际应用场景中需要将原始数据集按照功能划分并分别提取出这两部分原始特征信息。在现实世界中, 数据往往不是那么容易获得, 但是可以通过多种途径获取较为困难, 但可以通过收集用户的多元行为信号以及结合商品属性信息(如关键词描述、分类标签等)来构建有效的评分矩阵U
3.2.2 候选集生成
基于类似用户的推荐算法的第一步是生成候选集... 候选集是指那些具有高度相似性的用户所感兴趣的物品... 具体而言,在这一过程中... 系统首先识别出具有高度相似性的用户群体... 并根据这些用户的兴趣偏好来筛选出相关商品进行推荐。
根据相似用户的评分矩阵Λ来确定与目标用户u₁最为接近的同批用户提供服务方案。假设目标用户的ID为i,则与其相近用户的IDj可由以下公式确定:j=(Λ[u₁,:]−μ)²/(σ²)+u₁(其中μ和σ分别表示Λ[u₁,:]这一行数据序列的平均值和标准差)。该方法旨在识别出与目标用户最接近的k个相近用户提供服务方案,并通过分析这些相近用户的评分记录来构建候选商品集合以供后续推荐使用
3.2.3 个性化推荐
该算法的第三阶段旨在向用户提供感兴趣的商品。
该算法的基础在于将用户的喜好商品推送给具有相似特征的用户。
为了实现个性化推荐,则需综合考虑目标用户的使用习惯、兴趣偏好以及历史行为数据等关键指标。
具体来说就是从候选集中筛选并排序商品;接着根据用户的浏览历史确定受欢迎程度;最后将精选的商品推送给目标客户
4.具体代码实例和详细解释说明
4.1 获取数据集
import pandas as pd
ratings_data = pd.read_csv('ratings.dat', sep='::', names=['user_id', 'item_id', 'rating'], header=None)
movies_data = pd.read_csv('movies.dat', sep='::', names=['item_id', 'title'], header=None)
print(ratings_data.head())
print(movies_data.head())
代码解读
4.2 数据预处理
def get_user_items_matrix():
user_ids = ratings_data['user_id'].unique()
item_ids = movies_data['item_id']
users_dict = {}
items_dict = {}
for i in range(len(user_ids)):
uid = user_ids[i]
users_dict[uid] = {'ratings': [], 'likes': []}
for i in range(len(item_ids)):
mid = str(item_ids[i])
items_dict[mid] = set([])
for row in ratings_data.itertuples():
u, m, r = int(row[1]), str(row[2]), float(row[3])
if u not in users_dict or m not in items_dict:
continue
users_dict[u]['ratings'].append((r, m))
users_dict[u]['likes'].append(m)
items_dict[m].add(u)
return users_dict, items_dict
users_dict, items_dict = get_user_items_matrix()
for k, v in users_dict.items():
print(f'User {k}:')
print('\tRatings:', len(v['ratings']))
print('\tLikes:', len(set(v['likes'])))
print('')
print(list(items_dict.keys())[:10])
代码解读
4.3 生成相似用户推荐候选集
from scipy import spatial
import numpy as np
def generate_similar_users(user_id):
# Calculate similarity matrix between all users and target user
all_users = list(users_dict.keys())
sim_mat = np.zeros((len(all_users), len(all_users)))
for i in range(sim_mat.shape[0]):
for j in range(sim_mat.shape[1]):
if i == j:
sim_mat[i][j] = 1
else:
ui_ratings = [r[0] for r in users_dict[all_users[i]]['ratings']]
uj_ratings = [r[0] for r in users_dict[all_users[j]]['ratings']]
ratings_dist = spatial.distance.euclidean(ui_ratings, uj_ratings)
likes_dist = abs(len(users_dict[all_users[i]]['likes']) -
len(users_dict[all_users[j]]['likes'])) / max(len(users_dict[all_users[i]]['likes']),
len(users_dict[all_users[j]]['likes']))
sim_mat[i][j] = (1 - ratings_dist/max([np.std(ui_ratings)*3, 1])) * \
(1 + likes_dist) * (1 - spatial.distance.cosine(item_factors[str(movie)], user_factors[str(other_user)]))
# Find the most similar user to the given user ID
closest_user_index = np.argmin([(similarity[user_index]**2).sum() for user_index in range(len(all_users))])
closest_user_id = all_users[closest_user_index]
print(f"Target user's id: {user_id}")
print(f"Closest user's id: {closest_user_id}\n")
# Generate candidate sets of recommended items by recommending top K unseen items from closest user
closest_user_unseen_items = sorted(set(items_dict)-set([r[1] for r in users_dict[user_id]['ratings']]))
other_user_recommended_items = [(r[0], r[1]) for r in users_dict[closest_user_id]['ratings']][:num_recommendations]
recommendation_candidates = []
for rating, movie in other_user_recommended_items:
if movie in closest_user_unseen_items:
recommendation_candidates.append((-rating, movie))
return sorted(recommendation_candidates)[:num_recommendations]
target_user = 1
num_recommendations = 10
# Create a user factors matrix based on latent features obtained using PCA or SVD
user_factors = {}
for i in range(len(users_dict)):
user_factors[str(i)] = None
# Create an item factors matrix based on latent features obtained using PCA or SVD
item_factors = {}
for i in range(len(items_dict)):
item_factors[str(i)] = None
candidate_sets = generate_similar_users(target_user)
print("Recommended Candidates:")
for cand in candidate_sets:
print(cand)
代码解读
4.4 个性化推荐
class UserBasedCF:
def __init__(self, num_recommendations):
self.num_recommendations = num_recommendations
def fit(self, X, y=None):
pass
def recommend(self, user_id, is_new_user=False):
# Get known liked items for the user
known_items = set([int(m) for (_, m) in users_dict[user_id]['ratings']])
# Compute cosine similarity between each pair of unknown items and known liked items
all_items = set([int(m) for m in items_dict.keys()])
unknown_items = list(all_items - known_items)
scores = []
for item in unknown_items:
try:
score = 1 - spatial.distance.cosine(item_factors[str(item)], user_factors[str(user_id)])
except KeyError:
score = 0
scores.append((-score, item))
return sorted(scores)[:self.num_recommendations]
ubcf = UserBasedCF(num_recommendations)
recommendations = ubcf.recommend(target_user)
print("Personalized Recommendations:")
for rec in recommendations:
print(rec)
代码解读
