简介:这是一份面向计算机相关专业毕业设计的完整项目资料,围绕社交网络中用户行为分析与推荐算法展开。项目可真实运行,不仅覆盖关注、转发、点赞、评论、评分等典型行为特征提取,还给出基于用户行为的推荐模型设计与实现;后端提供用户、物品信息的增删、搜索、评价、排序、推荐等管理功能,形成从行为数据到推荐结果的闭环。压缩包共229个文件,体积约408KB,以Vue前端与JavaScript逻辑代码为主,辅以CSS样式、Markdown说明、配置文件、Shell脚本及少量字体图标资源,目录下api与frontend分层清晰,方便对照README进行环境配置与启动调试。目前已有23人学习下载。该资源适合作为毕业设计参考范本,能帮助快速搭建项目骨架、理解推荐算法落地流程,并可直接用于功能演示与答辩准备。
1. 毕业设计做推荐系统,最容易被低估的是用户行为数据
任何一个社交网络推荐算法,无论论文里把模型写得多么复杂,落到工程实现上,输入永远只有两类东西:用户过去的行为,和物品(或内容)自身的属性。而用户行为数据的质量直接决定了推荐结果的天花板。许多毕业设计在开题时把重点放在算法创新上,结果中期检查才发现,真正消耗时间的是数据清洗、行为权重设计和评估指标的构建。
这个基于用户行为的社交网络推荐算法研究与实现项目,本质上要解决的是三个问题:如何把原始点击、点赞、关注、评论行为转化成算法可用的特征;如何通过协同过滤或图算法在用户之间找到相似的兴趣路径;以及如何在离线评估和在线效果之间建立可信的验证方法。近几年社交网络与舆情分析方向的研究热度持续走高,用户行为序列建模、图神经网络推荐等话题成为热门,但本科毕业设计不需要追逐最前沿,把协同过滤、矩阵分解和排序学习这条链路做扎实,已经足够支撑一篇优秀的论文和可演示的系统。
本文按照实际开发顺序展开:先讲行为数据的工程化建模,再实现召回和排序两阶段算法,然后讨论评估与冷启动,最后给出线上使用的工程技巧。
2. 用户行为数据建模:从原始日志到推荐特征
2.1 行为日志的采集字段与埋点设计
社交网络中的用户行为比电商场景更稀疏、更多样化,常见的用户行为有点击、浏览时长、点赞、评论、收藏、关注和分享。这些行为在推荐算法中有着不同的权重和置信度:分享行为代表用户愿意用自己的社交信用背书,权重应当最高;而曝光未点击则是一种隐性的负反馈。
推荐算法领域的经典做法是将行为统一建模为三元组(user_id, item_id, behavior_type, timestamp),其中 behavior_type 对应不同行为的加权分值。在工程落地时,我一般会额外采集 context 字段,包括用户所在页面位置、设备类型和实验分组。对于行为权重的赋值,比较稳妥的做法是使用对数比例而不是线性比例。
| 行为类型 | 权重建议 | 置信度 | 适用场景 |
|---|---|---|---|
| 曝光 | 0(负样本来源) | 低 | 训练负采样 |
| 点击 | 1.0 | 中 | 基础正样本 |
| 点赞 | 2.0 | 中高 | 轻量正反馈 |
| 收藏 | 3.0 | 高 | 强兴趣信号 |
| 评论 | 4.0 | 高 | 深度互动 |
| 关注 | 5.0 | 极高 | 长期兴趣 |
| 分享 | 8.0 | 极高 | 社交传播信号 |
权重赋值完成后,原始日志就可以转化为标准的行为序列。
2.2 行为序列的切分与用户兴趣提取
行为日志按时间排序后,需要做序列切分。很多毕业设计在这个环节容易出错——直接用全量历史行为训练模型,把一天前的点击和今天的点击混在一起。正确的做法是设置时间窗口,一般取最近 14 到 30 天作为有效行为窗口,超过窗口的旧行为做时间衰减处理。
序列切分的核心代码如下:
import pandas as pd import numpy as np from datetime import timedelta def build_user_behavior_seq(df, time_window_days=30, decay_factor=0.9): """ 构建用户行为序列,按时间排序并做时间衰减 :param df: 包含 user_id, item_id, behavior_type, timestamp 的 DataFrame :param time_window_days: 时间窗口大小(天) :param decay_factor: 衰减因子,0~1之间 """ df['timestamp'] = pd.to_datetime(df['timestamp']) cutoff = df['timestamp'].max() - timedelta(days=time_window_days) df = df[df['timestamp'] >= cutoff] # 行为权重映射 weight_map = {'expose': 0, 'click': 1.0, 'like': 2.0, 'fav': 3.0, 'comment': 4.0, 'follow': 5.0, 'share': 8.0} df['weight'] = df['behavior_type'].map(weight_map) # 时间衰减:越近的行为权重越高 days_diff = (df['timestamp'].max() - df['timestamp']).dt.days df['decay_weight'] = df['weight'] * np.power(decay_factor, days_diff) # 按用户和物品聚合 user_item_rating = df.groupby(['user_id', 'item_id'])['decay_weight'].sum().reset_index() user_item_rating.columns = ['user_id', 'item_id', 'rating'] # 行为序列:每个用户按时间排序的物品 id 列表 behavior_seq = df.sort_values(['user_id', 'timestamp']) \ .groupby('user_id')['item_id'] \ .apply(list) \ .reset_index() behavior_seq.columns = ['user_id', 'item_seq'] return user_item_rating, behavior_seq这段代码做了三件事:截取时间窗口内的行为、按时差做指数衰减、按用户聚合。参数说明:time_window_days控制训练数据的时效范围,社交网络内容更新快,建议取值 14 天以内;decay_factor控制历史行为的衰减速度,取值 0.9 表示每过一天权重乘以 0.9,10 天前行为的权重只有当天的约 0.35。这个值不宜低于 0.8,否则长期兴趣完全丢失。
2.3 社交关系特征:关注关系与好友协同
纯用户行为建模会漏掉社交网络的独特优势——关系链本身就是一种强特征。常见做法是把关注关系构造成邻接矩阵,存入 NetworkX 的 Graph 对象,用于后续计算用户相似度或做图传播。
import networkx as nx def build_social_graph(follow_df): """ 构建社交关系图 :param follow_df: 包含 follower_id, followee_id 的 DataFrame """ G = nx.DiGraph() G.add_edges_from(zip(follow_df['follower_id'], follow_df['followee_id'])) return G def get_social_neighbors(G, user_id, depth=2): """ 获取用户的社交邻居集合,BFS 到指定深度 """ neighbors = set() visited = set([user_id]) queue = [(user_id, 0)] while queue: node, d = queue.pop(0) if d >= depth: continue for neighbor in G.neighbors(node): if neighbor not in visited: visited.add(neighbor) neighbors.add(neighbor) queue.append((neighbor, d + 1)) return neighbors社交邻居的引入可以缓解行为数据的稀疏性:当用户 A 的行为很少时,其关注的用户 B 的行为可以作为间接推荐依据。但这只适用于冷启动阶段,行为数据积累到一定量后,直接行为信号优于社交传播信号。
3. 基于用户行为的召回算法实现
3.1 ItemCF 与 UserCF 的选型逻辑
协同过滤是社交网络推荐系统的基石,召回阶段只需要两个候选算法:UserCF 和 ItemCF。UserCF 的思路是找到和自己兴趣相似的用户,把那些用户喜欢的物品推荐给自己;ItemCF 的思路是找到和已交互物品相似的物品。
选型标准并不复杂:内容更新快的社交平台,如微博热搜、短视频,用 ItemCF 更合适,因为 ItemCF 能实时反映物品的热度变化;用户群体相对固定且兴趣稳定的平台,如知识社区,用 UserCF 效果更好。毕业设计如果想体现工作量,可以把两者都实现,再做一个加权融合。
3.2 使用 Python 实现 ItemCF 召回
from collections import defaultdict def item_cf_recall(user_item_rating, user_k=10, top_n=20): """ ItemCF 召回实现 :param user_item_rating: user_id, item_id, rating 三列 :param user_k: 取相似物品的数量 :param top_n: 最终返回的推荐数量 """ # 构建用户 -> 物品倒排表 user_items = defaultdict(dict) for _, row in user_item_rating.iterrows(): user_items[row['user_id']][row['item_id']] = row['rating'] # 计算物品相似度矩阵 item_sim = defaultdict(dict) item_cnt = defaultdict(int) for user, items in user_items.items(): for item in items: item_cnt[item] += 1 for other_item in items: if item == other_item: continue item_sim[item][other_item] = item_sim[item].get(other_item, 0) + 1 # 归一化物品相似度 for item, sim_items in item_sim.items(): for other_item, cnt in sim_items.items(): item_sim[item][other_item] = cnt / (item_cnt[item] ** 0.4 * item_cnt[other_item] ** 0.4) # 生成推荐 def recommend(user_id): interacted = user_items.get(user_id, {}) scores = defaultdict(float) for item, rating in interacted.items(): for other_item, sim in item_sim.get(item, {}).items(): if other_item in interacted: continue scores[other_item] += sim * rating # 按得分排序取 top_n return sorted(scores.items(), key=lambda x: x[1], reverse=True)[:top_n] return recommend代码中的核心逻辑是:用户对物品 A 有过行为,系统找到与 A 最相似的物品 B、C、D,然后按相似度乘用户对 A 的评分加权求和。user_k控制回召质量,取值太小则物品覆盖不足,取值太大则计算量爆炸且噪声增多,一般取 10 到 30 之间。
3.3 矩阵分解实现隐因子推荐
协同过滤的相似度计算在物品数量超过 10 万时性能下降明显,另一种常见做法是矩阵分解(Matrix Factorization),将用户物品交互矩阵分解为低维的用户隐向量矩阵 P 和物品隐向量矩阵 Q,再通过向量内积预测评分。推荐算法研究中,SVD 和 FunkSVD 是两种基础实现。
import numpy as np def funk_svd(user_item_rating, latent_dim=20, lr=0.01, reg=0.02, epochs=30): """ FunkSVD 矩阵分解 :param latent_dim: 隐向量维度 :param lr: 学习率 :param reg: 正则化系数 :param epochs: 迭代轮数 """ # 构建用户和物品索引 users = sorted(user_item_rating['user_id'].unique()) items = sorted(user_item_rating['item_id'].unique()) user_idx = {u: i for i, u in enumerate(users)} item_idx = {i: j for j, i in enumerate(items)} # 初始化隐向量 P = np.random.normal(0, 0.1, (len(users), latent_dim)) Q = np.random.normal(0, 0.1, (len(items), latent_dim)) ratings = user_item_rating.values for epoch in range(epochs): np.random.shuffle(ratings) total_loss = 0 for u, i, r in ratings: uid, iid = user_idx[u], item_idx[i] pred = np.dot(P[uid], Q[iid]) err = r - pred total_loss += err ** 2 # SGD 更新 P[uid] += lr * (err * Q[iid] - reg * P[uid]) Q[iid] += lr * (err * P[uid] - reg * Q[iid]) if epoch % 10 == 0: print(f"epoch {epoch}, loss: {total_loss / len(ratings):.4f}") return P, Q, user_idx, item_idxFunkSVD 只考虑用户物品交互矩阵,不考虑 bias 项,代码简洁适合毕业设计讲解。参数说明:latent_dim是隐向量维度,社交网络场景推荐 15 到 30 之间,太大会过拟合,太小欠拟合;lr为学习率,取值 0.005 到 0.02 区间,超过 0.05 就会震荡不收敛;reg是正则化系数,配合latent_dim一起调节。
4. 排序学习与个性化重排策略
4.1 从召回候选到排序特征的工程链路
召回阶段得到几百个候选 item,排序阶段的目标是对这些候选做精细化打分。业界标准做法是 Learning to Rank,把候选列表按用户历史行为特征、物品特征、社交特征和实时热度特征做 CTR 预估。
排序特征一般分四组:用户侧特征入用户活跃度、兴趣分类分布;物品侧特征入内容发布时间、作者粉丝数、历史互动率;交叉特征入用户对同一作者的过往行为、用户对同类内容的点击率;上下文特征入请求时段、设备类型、当前页面位置。特征构建的核心代码:
def build_ranking_features(user_item_rating, item_meta, user_meta): """ 构建排序特征矩阵 :param user_item_rating: 用户物品交互数据 :param item_meta: 物品元信息(发布时间、作者等) :param user_meta: 用户元信息 """ features = [] labels = [] for _, row in user_item_rating.iterrows(): uid, iid = row['user_id'], row['item_id'] label = 1 if row['rating'] > 0 else 0 # 二分类标签 feat = { 'user_active_days': user_meta.loc[uid, 'active_days'], 'item_publish_hour': item_meta.loc[iid, 'publish_hour'], 'item_author_followers': item_meta.loc[iid, 'author_followers'], 'user_item_cat_ctr': calc_user_cat_ctr(uid, iid, item_meta, user_item_rating), 'cross_author_interact': calc_cross_author_interact(uid, iid, item_meta, user_item_rating), 'seq_last_click_gap': calc_time_gap(uid, iid, item_meta), 'social_overlap_score': calc_social_overlap(uid, iid) } features.append(feat) labels.append(label) return pd.DataFrame(features), np.array(labels)这一段特征构建实现需要封装大量辅助函数,在毕业设计论文中可以配合特征重要性分析展示每个特征的贡献度差异。
4.2 基于 LightGBM 的排序模型训练流程
排序模型的首要选择是 GBDT,推荐算法竞赛中 LightGBM 表现稳定,训练快、调参空间大。
import lightgbm as lgb from sklearn.model_selection import train_test_split from sklearn.metrics import ndcg_score def train_ranking_model(features, labels, user_ids, test_size=0.2): """ 训练 LightGBM 排序模型 """ X_train, X_test, y_train, y_test, u_train, u_test = \ train_test_split(features, labels, user_ids, test_size=test_size, random_state=42) # 构造 LightGBM 的排序数据集 train_data = lgb.Dataset(X_train, label=y_train, group=[len(X_train)]) valid_data = lgb.Dataset(X_test, label=y_test, group=[len(X_test)]) params = { 'objective': 'binary', 'metric': 'auc', 'learning_rate': 0.05, 'num_leaves': 31, 'min_data_in_leaf': 50, 'feature_fraction': 0.8, 'bagging_fraction': 0.8, 'bagging_freq': 1, 'verbose': -1 } model = lgb.train(params, train_data, num_boost_round=300, valid_sets=[valid_data], early_stopping_rounds=50) # 计算 NDCG@10 y_pred = model.predict(X_test) # 按用户分组计算 NDCG y_true_list = [] y_pred_list = [] for u in u_test.unique(): mask = u_test == u y_true_list.append(y_test[mask]) y_pred_list.append(y_pred[mask]) ndcg_val = ndcg_score(y_true_list, y_pred_list, k=10) print(f"NDCG@10: {ndcg_val:.4f}") return model # 输出特征重要性 feat_importance = pd.DataFrame({ 'feature': features.columns, 'importance': model.feature_importance() }).sort_values('importance', ascending=False)注意:train_test_split必须按用户划分,不能随机划分样本,否则同一个用户的行为同时出现在训练集和测试集中,出现数据泄漏的风险,评估指标会虚高。num_leaves不宜超过 64,社交网络数据噪声大,叶子节点过多容易过拟合到头部热门内容。
4.3 去热门与多样性重排
排序模型的输出天然偏向热门内容,热门内容有更多的交互数据供模型学习。但推荐系统不能只推热门内容,否则用户看到的全是同质化信息。常见做法是在排序阶段之后加一道多样性重排,使用 MMR(Maximal Marginal Relevance)算法平衡相关性和多样性。
def mmr_rerank(ranked_items, item_sim_matrix, lambda_val=0.7, top_k=20): """ MMR 重排:平衡相关性与多样性 :param ranked_items: 排序后的 [(item_id, score)] 列表 :param item_sim_matrix: 物品相似度矩阵 :param lambda_val: 相关性权重,越大越重视相关性 """ selected = [] not_selected = list(ranked_items) while len(selected) < top_k and not_selected: mmr_scores = {} for item_id, score in not_selected: # 计算与已选物品的最大相似度 sim_to_selected = 0 for sel_id, _ in selected: sim = item_sim_matrix.get(item_id, {}).get(sel_id, 0) sim_to_selected = max(sim_to_selected, sim) # MMR = lambda * 相关性 - (1 - lambda) * 最大相似度 mmr_scores[item_id] = lambda_val * score - (1 - lambda_val) * sim_to_selected # 选择 MMR 得分最高的物品 best_item = max(mmr_scores, key=mmr_scores.get) selected.append((best_item, mmr_scores[best_item])) not_selected = [(i, s) for i, s in not_selected if i != best_item] return selectedlambda_val的取值规律:默认 0.7,偏向相关性;如果内容生态需要更强探索,可降到 0.5。每降 0.1,推荐结果中非热门内容的占比大约提升 5 到 8 个百分点。在实际调优时,先跑一版不加重排的排序结果,统计 top20 中热门内容占比,再通过调节 lambda 逐步达到目标比例。
5. 评估指标与冷启动问题的边界处理
5.1 离线评估:准确率、召回率与 NDCG 计算
推荐系统需要一套可复现的评估流程。精度类指标(Precision、Recall、F1)和排序类指标(NDCG、MAP)各有侧重,在论文中建议都给出。
def evaluate_recall(user_reco, user_holdout, k_list=[5, 10, 20]): """ 评估召回效果 :param user_reco: dict, user_id -> 推荐列表 :param user_holdout: dict, user_id -> 测试集真实交互物品 """ import numpy as np result = {} for k in k_list: precision_list = [] recall_list = [] hit_count = 0 total_user = 0 for user_id in user_holdout: if user_id not in user_reco: continue reco = user_reco[user_id][:k] true_items = set(user_holdout[user_id]) hit = len(set(reco) & true_items) total_user += 1 if hit > 0: hit_count += 1 precision_list.append(hit / k) recall_list.append(hit / len(true_items)) result[f'precision@{k}'] = np.mean(precision_list) result[f'recall@{k}'] = np.mean(recall_list) result[f'hit_rate@{k}'] = hit_count / total_user return result评估数据切分方法是时间分裂:把每个用户的行为按时间排序,前 80% 做训练,后 20% 做测试。注意不能随机分裂用户行为,推荐系统有强时序依赖,随机分裂会高估指标 10% 以上。hit_rate表示推荐的 20 个物品中有至少一个命中的用户占比,社交网络场景 hit_rate 比精确率更有参考价值,因为它衡量的是推荐系统发现潜在兴趣的能力。
5.2 双塔模型对冷启动的改进方法
冷启动是社交网络推荐算法绕不开的问题,分为新用户冷启动和新技术冷启动。对于新用户,常见做法是先用热门内容做策略推荐,再收集少量行为后切到个性化推荐。对于新内容,可以利用内容属性做基于内容的召回。传统矩阵分解和协同过滤对冷启动几乎失效,因为用户与物品的交互矩阵是空的。
业界给定低延迟场景使用的解决方法:双塔模型(Two-Tower Model)。一个 tower 编码用户特征,一个 tower 编码物品特征,把两者映射到同一个 embedding 空间,用内积计算相关度。双塔模型尽早在矩阵分解、协同过滤方法上做了替换,把用户侧和物品侧扩展到包含所有用户和物品属性。
import torch import torch.nn as nn class UserTower(nn.Module): """用户塔:输入用户特征,输出用户 embedding""" def __init__(self, user_id_dim, social_dim, behavior_dim, emb_dim=64): super().__init__() self.user_id_emb = nn.Embedding(user_id_dim, emb_dim) self.social_net = nn.Linear(social_dim, emb_dim) self.behavior_net = nn.Linear(behavior_dim, emb_dim) self.fc = nn.Sequential( nn.Linear(emb_dim * 3, emb_dim), nn.ReLU(), nn.Linear(emb_dim, emb_dim) ) def forward(self, user_id, social_feat, behavior_feat): u_emb = self.user_id_emb(user_id) s_emb = self.social_net(social_feat) b_emb = self.behavior_net(behavior_feat) return self.fc(torch.cat([u_emb, s_emb, b_emb], dim=-1)) class ItemTower(nn.Module): """物品塔:输入物品特征,输出物品 embedding""" def __init__(self, item_id_dim, cat_dim, author_dim, emb_dim=64): super().__init__() self.item_id_emb = nn.Embedding(item_id_dim, emb_dim) self.cat_emb = nn.Embedding(cat_dim, emb_dim) self.author_emb = nn.Embedding(author_dim, emb_dim) self.fc = nn.Sequential( nn.Linear(emb_dim * 3, emb_dim), nn.ReLU(), nn.Linear(emb_dim, emb_dim) ) def forward(self, item_id, cat_id, author_id): i_emb = self.item_id_emb(item_id) c_emb = self.cat_emb(cat_id) a_emb = self.author_emb(author_id) return self.fc(torch.cat([i_emb, c_emb, a_emb], dim=-1))对用户来说,新用户虽然交互矩阵为空,但注册时可能选择兴趣标签、关注默认博主,这些社交特征通过用户塔映射到 embedding 空间后仍然可以完成召回;新内容虽然无交互数据,但发布者的历史粉丝行为可以从作者 embedding 中获得迁移信号。
5.3 冷启动中的负反馈信号利用
冷启动阶段没有足够正样本构建训练集时,可以利用曝光未点击数据作为负样本。但要注意的是,曝光未点击不完全代表不感兴趣,可能只是位置太靠下,这是推荐系统实现中最常见的偏差问题,即 position bias。解决方法是给不同曝光位置的负样本赋予不同权重:
def build_coldstart_samples(impression_log, position_weight_map): """ 基于曝光日志构建负样本 :param position_weight_map: {位置编号: 权重},位置越靠下权重越小 """ samples = [] for _, log in impression_log.iterrows(): # 曝光但未点击 -> 负样本 if log['is_click'] == 0: weight = position_weight_map.get(log['position'], 0.3) samples.append({ 'user_id': log['user_id'], 'item_id': log['item_id'], 'label': 0, 'weight': weight }) # 曝光且点击 -> 正样本 else: samples.append({ 'user_id': log['user_id'], 'item_id': log['item_id'], 'label': 1, 'weight': 1.0 }) return pd.DataFrame(samples)position_weight_map可以根据页面实际位置手动设置,比如位置 1 设为 1.0,位置 5 设为 0.6,位置 10 设为 0.3。这个参数的语义是:排在前面的内容占据用户注意力,被瞥见却没点击,比排在底部的内容被滑过更能说明用户不感兴趣。在训练时将 sample_weight 传入 LightGBM 或双塔模型的 loss 中即可。
6. 推荐链路的降级策略与离线在线一致性验证
6.1 三层降级链路设计
线上推荐系统允许部分模块失效,但不能整个接口不可用。从毕业设计演示扩展到工程部署时,需要设计好降级策略,这是一线工程师做推荐系统时最看重的能力之一。
常见的降级链路分为三层:
- 第一层,算法层故障,如召回模型超时、排序模型服务不可用,此时直接返回热门榜或编辑推荐。
- 第二层,行为特征服务故障,降级到只使用用户长期静态特征,如地域、年龄段、注册时长。此时推荐结果会偏粗粒度,但接口仍可返回 200。
- 第三层,数据库故障,此时连基础的用户配置都读不到,返回兜底内容池,从本地缓存中拿最近一次成功请求的结果。
三层降级的触发阈值需要认真设置。建议梯度是:召回耗时超过 100ms 时降级到强规则召回;行为特征服务错误率超过 5% 时降级到静态特征排序;数据连接池耗尽时直接使用本地缓存兜底。严格来说这不是推倒重来,而是按失败半径最大化保留可用能力。
6.2 离线评估与线上日志的一致性校验
很多推荐算法的毕业设计只做了离线评估就写结论,但离线指标和线上真实反馈经常不一致。有一个标准产品方法:先做一致性校验,再谈指标。一致性校验的核心是检查训练样本分布和线上实际请求分布是否匹配。
def check_train_online_consistency(train_df, online_log_df, check_col='category'): """ 校验训练集与线上日志分布一致性 """ from scipy import stats train_dist = train_df[check_col].value_counts(normalize=True).sort_index() online_dist = online_log_df[check_col].value_counts(normalize=True).sort_index() # 对齐 index 后计算 PSI(Population Stability Index) common_idx = train_dist.index.union(online_dist.index) train_dist = train_dist.reindex(common_idx, fill_value=0.0001) online_dist = online_dist.reindex(common_idx, fill_value=0.0001) psi = sum((train_dist - online_dist) * np.log(train_dist / online_dist)) if psi < 0.1: result = "分布一致性好,可信任离线结果" elif psi < 0.25: result = "分布存在轻度偏移,建议检查近期的数据采集逻辑" else: result = "分布严重偏移,禁止直接上线,须重新采数训练" return psi, resultPSI 指标是金融风控领域常用的分布稳定性指标,推荐系统直接迁移使用。训练集用的是历史积累的数据,线上日志反映的是当前用户实时行为,如果两者分布偏差过大,模型上线后效果通常会大幅下滑。建议在每次模型迭代后都执行这个检查。
最后给一个具体建议:在推荐系统的代码仓库里建立一个独立的验证脚本,把离线评估、PSI 检查和多样性指标打包运行,任何模型变更都先过这套验证,再决定是否上线。这个习惯能让你在毕业设计答辩时清晰地展示数据驱动的决策闭环。
本文还有配套的精品资源,点击获取