2026/10/31 21:46:35

社交网络用户活跃度预测:从特征工程到XGBoost的完整方案

社交网络用户活跃度预测:从特征工程到XGBoost的完整方案 简介基于Python的社交网络活动预测系统源码包面向具备一定Python基础、对社交网络分析与行为预测感兴趣的计算机专业学生或开发者。该系统通过分析成员历史行为、社交网络结构及活动时间点预测成员对活动的反应内置八种预测模式涵盖初始兴趣、训练集调整、社交网络相似度等不同场景。资源共16个文件以6个Python脚本为核心辅以Excel结果文件、PNG网络可视化图、Markdown实验报告及说明文档压缩包仅3.22MB轻量易用。目前已有54人下载学习适合作为课程设计、毕业设计或算法实验的参考。读者可获得多模式预测的完整实现包括无权/有权网络构建、成员相似度与共同出现次数计算、数据读取与结果导出并配有实验报告和分组成绩表格便于对照分析、快速运行和二次开发。1. 社交网络活动预测系统用户下周还会不会来模型怎么回答“社交网络活动预测系统”听起来像学术项目但它解决的是运营每天都在纠结的问题本周推送名额有限消息发给谁某几个用户群体发帖量连续下滑下个月要不要重点维护做法是基于用户过去几周的行为记录——发帖、点赞、评论、登录——用 Python 训练模型预测未来 7 天用户的活跃概率或活跃度分值。按这个标题交付的源码通常包含数据清洗、特征构建、模型训练和在线预测四块。这篇文章会把整套方案最常用的落地路径拆开讲适合做用户增长的运营、刚入门时序预测的 Python 工程师以及被业务方追着要预测结果的算法新人。不用纠结你拿到的包和我讲的细节是否完全一致活动预测的核心逻辑是通用的。2. 系统的整体设计从行为日志到预测结果的数据链路2.1 预测目标先定清楚分类和回归不是拍脑袋选的拿到这类源码的第一件事不是跑代码而是看它把“活动预测”定义成了哪种任务。最常见的定义有两种二分类预测用户未来 7 天“是否活跃”回归或者多分类预测用户未来 7 天的发帖数、活跃天数、互动次数落在哪个区间。选哪一种取决于业务方拿到预测结果后怎么用。如果运营动作是“给即将沉默的用户发优惠券”分类就够了阈值可以直接对应发券名单。如果运营要做的是“把用户按活跃度分层配置不同力度的召回资源”那分数比标签更有用这时要么训练回归模型要么用分类模型输出的概率值排序。我一般建议先按分类建模把活跃概率当作分数输出业务方按分数切分桶。原因很简单二分类的评估指标成熟AUC、精确率、召回率而且概率值天然支持后续分层和排序。标签定义要在写代码之前定死否则后面所有评估都失真。一个常用的标签规则是把行为日志按天归一化未来 7 天内发帖次数大于等于 1或者登录天数大于等于 3记为活跃否则记为不活跃。注意这里有一个容易被忽略的细节预测窗口的起点必须是特征截止时间的次日不能把特征截止当天的行为算进标签否则就引入了时间泄漏具体在第 5 章的避坑部分展开。2.2 数据从哪里来API、日志表还是爬虫这个系统所需的最小数据集是两张表行为表和关系表。行为表至少包含用户 ID、行为类型、时间戳三列行为类型可以是发帖、评论、点赞、登录、分享。关系表是用户之间的关注、转发或好友关系用于提取社交网络特征。数据的三类来源里内部日志表是最可靠的格式统一、字段完整直接读数仓的 Hive 表或日志系统就行。公开数据集做实验时常见的是直接下载现成的社交网络数据集省去采集成本。第三种就是自己写 python 爬虫去公开页面或开放接口拿 JSON 数据这块要注意合规问题建议只采集公开接口里明确允许的字段保存原始响应再解析不要刻意绕过访问频率限制。数据链路在源码里通常长这样原始日志 → 按天分区落数仓 → 离线脚本抽取近 N 天行为 → 特征宽表 → 模型训练 → 预测结果写回 MySQL 或 Redis 供运营系统读取。注意这条链路里特征宽表是核心中间产物所有特征都拼在这一张表上每行是一个用户在某个特征截止日的特征。这个设计能保证训练和在线预测用同一套特征逻辑避免两边特征不一致。2.3 模型选型XGBoost 是底座深度学习是武器库表格特征占主导的预测场景XGBoost 和 LightGBM 是第一选择不要一上来就上 LSTM 或图神经网络。活动预测的特征大多是数值聚合比如 7 天发帖数、14 天活跃天数、每晚活跃占比这类特征在树模型上表现稳定训练快还能输出特征重要性给运营解释。这和做量化交易策略有点像历史信号归纳成特征再预测未来窗口特征工程质量决定模型上限。社交网络活动预测本质上是一个时序表格问题先把 xgboost 跑通拿到基线再考虑要不要升级。只有当你有明确的行为序列数据比如每个用户的时间戳列表而不是聚合值时LSTM/GRU 才有发挥空间只有当社交关系对行为影响明显时GraphSAGE 这类图模型才值得引入。图模型对特征稀疏的用户补全效果好但训练和部署成本高出不少。3. 特征工程是重头戏时间滑窗、行为序列与社交图谱3.1 时间滑窗特征最近 N 天的行为聚合多数活动预测效果差不是模型不行而是特征没表达出“近期变化”。用户昨天突然活跃和过去三个月一直活跃是两种完全不同的状态。时间滑窗特征的思路是对每个用户在特征截止日之前取多个窗口分别聚合行为量。窗口太短噪声大太长周期性掩盖变化常用组合是 3 天、7 天、14 天。import pandas as pd import numpy as np def time_window_features(interactions: pd.DataFrame, target_date: str, windows(3, 7, 14)) - pd.DataFrame: 对目标日期之前的多个时间窗口做行为聚合。 输入必须有 user_id、action_type、ts 三列ts 是带时区的 datetime。 target_date pd.Timestamp(target_date) base interactions[interactions[ts] target_date] frames [] for w in windows: start target_date - pd.Timedelta(daysw) part base[base[ts] start] g part.groupby(user_id).agg( cnt(action_type, count), post_cnt(action_type, lambda s: (s post).sum()), like_cnt(action_type, lambda s: (s like).sum()), active_days(ts, lambda s: s.dt.normalize().nunique()), ) # 列名加上窗口后缀避免多个窗口 merge 时冲突 g.columns [f{c}_{w}d for c in g.columns] g[user_id] g.index frames.append(g.reset_index(dropFalse)) res frames[0] for f in frames[1:]: res res.merge(f, onuser_id, howouter) return res逻辑说明这段代码把行为记录先截到特征截止日之前再逐个窗口做 groupby 聚合。cnt_7d表示最近 7 天行为总量post_cnt_7d表示发帖量active_days_7d表示有多少天有行为这个字段比单纯行为次数更能反映“持续活跃”还是“一天爆发”。参数使用建议窗口数量和长度按业务节奏定。如果你的产品日活波动大3 天窗口能捕捉短期热度如果运营活动是周级的7 天和 14 天是标配月度考核再加 30 天窗口。注意窗口之间是重叠包含关系特征相关性会变高树模型不太怕这个但如果你后续要接线性模型或神经网络就要先做相关性筛选。3.2 周期性特征活跃不是均匀分布的累计行为特征只能回答“做了多少”回答不了“什么时候做”。同一周发帖 10 次的用户有人集中在工作日上午有人集中在周末深夜前者可能是内容生产者后者可能是夜猫子闲聊用户后续活跃度差异很大。周期性特征的目的是把行为的时间分布转成可用的数值。def periodicity_features(interactions: pd.DataFrame, target_date: str, window: int 7) - pd.DataFrame: 提取用户在窗口内的活跃习惯周末占比、夜间占比、平均间隔时长。 target_date pd.Timestamp(target_date) start target_date - pd.Timedelta(dayswindow) part interactions[(interactions[ts] start) (interactions[ts] target_date)].copy() part[is_weekend] part[ts].dt.dayofweek 5 part[hour] part[ts].dt.hour part[is_night] (part[hour] 23) | (part[hour] 5) g part.groupby(user_id).agg( cnt_total(action_type, count), weekend_ratio(is_weekend, mean), # 周末行为占比 night_ratio(is_night, mean), # 夜间行为占比 peak_hour(hour, lambda s: s.mode().iloc[0] if len(s) 0 else -1), ) return g.reset_index()逻辑说明weekend_ratio是窗口内周末发生的行为占总行为的比例取值 0 到 1能区分工作日型用户和休闲型用户。night_ratio同理识别深夜活跃群体。peak_hour取行为发生小时数的众数作为用户习惯的粗糙描述。参数说明window和 3.1 节里的滑窗一致建议用同一个值这样特征能对上同一段行为。ts.dt.dayofweek里周一到周日对应 0 到 6大于等于 5 就是周六周日。注意partition[hour]这一列是中间变量可以直接用不需要额外保存。这里有一个易踩的细节mean()在聚合布尔列时计算的是 True 占比但前提是列类型是 bool如果列被转成 int 再求均值结果一样不影响。而peak_hour的 mode 结果可能有多值取第一个即可少量用户行为太少没有众数返回 -1 作为缺失占位。3.3 社交网络特征用图中心性补足稀疏行为行为特征对活跃用户很有效但对新用户和沉默用户基本是零。社交网络特征能补上这一块一个用户关注了很多高活跃大 V或者有不少双向好友即使他最近自己没动作也有理由预测他会回来。这类特征在行为稀疏的用户身上提升最明显。import networkx as nx def graph_features(edge_list: pd.DataFrame) - pd.DataFrame: edge_list 包含 user_id 和 friend_id 两列表示“关注/好友”关系。 返回每个节点的度、PageRank 值和 k-core 层级。 G nx.Graph() # 数据量大时建议用 nx.from_pandas_edgelist 一次性建图 for _, row in edge_list.iterrows(): G.add_edge(row[user_id], row[friend_id]) degree dict(G.degree()) pagerank nx.pagerank(G, alpha0.85) core_number nx.core_number(G) res pd.DataFrame({user_id: list(G.nodes())}) res[degree] res[user_id].map(degree) res[pagerank] res[user_id].map(pagerank) res[k_core] res[user_id].map(core_number) return res逻辑说明degree是直接连接的节点数量代表用户的直接社交范围。pagerank计算的是节点在整个图中的影响力一个用户虽然好友不多但如果他的好友都是高影响力节点他的 pagerank 也会偏高这种用户通常消息触达率高。k_core表示用户所在的最深核层能体现用户嵌入社交网络的紧密程度core_number越高的用户越难离开平台。参数说明alpha0.85是 PageRank 的阻尼系数它控制随机跳转概率。社交网络里取 0.85 是经验默认值调高会让影响力更集中在少数头部节点调低会平滑。建图时如果边表超过几十万条建议改用nx.from_pandas_edgelist避免逐行循环拖慢速度。社交网络特征要和行为特征做在同一张 user_id 上社交特征缺失的节点例如关系表里没有但行为表里有要填 0 或者 -1不能直接丢弃行否则预测结果会漏掉一部分用户。4. 模型训练与活动预测最小可复现的 Python 方案4.1 切分数据时序切分和随机切分的区别活动预测的数据天然带时间属性不能用 sklearn 默认的train_test_split随机切分。原因是行为数据时间相关性强随机切分会把 1 月的数据同时分进训练集和验证集模型相当于见过未来验证集的指标虚高。正确做法是按时间顺序切分前面的时间窗口做训练后面的时间窗口做验证。from sklearn.model_selection import TimeSeriesSplit # 特征宽表必须按特征截止日排序保证切分是纯时间语义 feature_table.sort_values(feature_date, inplaceTrue) X feature_table.drop(columns[user_id, feature_date, label_active]) y feature_table[label_active].astype(int) tscv TimeSeriesSplit(n_splits3) for fold, (train_idx, val_idx) in enumerate(tscv.split(X)): X_train, X_val X.iloc[train_idx], X.iloc[val_idx] y_train, y_val y.iloc[train_idx], y.iloc[val_idx] # 每个 fold 里训练集时间都早于验证集 print(ffold {fold}: train {len(X_train)} rows, val {len(X_val)} rows)逻辑说明TimeSeriesSplit在切分时不打乱顺序第一次切分训练集是前一段、验证集是后一小段第二次训练集扩大。它的本质是保证训练集时间截止点在验证集开始点之前。这里有个前提feature_table必须按时间排过序而且每一行对应一个用户在某一个特征截止日的快照。参数说明n_splits3表示做 3 次滚动切分每次验证集占总样本约四分之一。如果数据跨度只有 30 天3 次切分会把验证集切得很碎建议改成 2如果跨度超过 90 天用 5 次更合适能看出模型在不同季节下的稳定性。还要注意同一用户的多个快照可能落在不同 fold用户重叠会让指标略微乐观严格做法是按用户 ID 分组切分。4.2 训练与调参XGBoost 的核心参数说明基线模型用 XGBoost 是稳妥选择。这个场景里特征大多有缺失值样本类别不均衡XGBoost 对这两点都有内置处理缺失值会自动学习分裂方向scale_pos_weight可以调节正负样本权重。下面是训练代码和参数说明。import xgboost as xgb from sklearn.metrics import roc_auc_score, average_precision_score tscv TimeSeriesSplit(n_splits3) for fold, (train_idx, val_idx) in enumerate(tscv.split(X)): X_train, X_val X.iloc[train_idx], X.iloc[val_idx] y_train, y_val y.iloc[train_idx], y.iloc[val_idx] # 类别不均衡的经典处理让模型更重视少数类活跃用户 scale_pos_weight (y_train 0).sum() / (y_train 1).sum() model xgb.XGBClassifier( n_estimators300, max_depth4, learning_rate0.05, min_child_weight2, subsample0.8, colsample_bytree0.8, scale_pos_weightscale_pos_weight, eval_metricauc, early_stopping_rounds20, ) model.fit( X_train, y_train, eval_set[(X_train, y_train), (X_val, y_val)], verboseFalse, ) y_pred model.predict_proba(X_val)[:, 1] print(ffold {fold}: AUC{roc_auc_score(y_val, y_pred):.4f}, fAP{average_precision_score(y_val, y_pred):.4f})逻辑说明predict_proba(X_val)[:, 1]取出类别 1 的预测概率这就是给运营用的活跃概率分数。AUC 反映排序能力AP平均精确率对类别不均衡更敏感两个指标一起看AP 掉得厉害说明模型对少数类的召回有问题。参数说明max_depth4在活动预测这类特征量大的场景下够用过深的树容易记住噪声learning_rate0.05配n_estimators300靠早停找树的数量min_child_weight2抑制过拟合缺失值多的节点样本量少时不会被继续分裂subsample0.8和colsample_bytree0.8分别是行采样和列采样减少方差。注意scale_pos_weight在正样本极少的场景下可以再放大 1.2 到 1.5 倍但要留在验证集上观察是不是只是提高了召回却压低了精确率。如果你的 python 环境连 numpy 和 pandas 都没装先按官方教程把基础库补齐上面代码依赖 numpy、pandas、xgboost、networkx 四个包numpy 是 pandas 和 xgboost 的底层依赖装完 pandas 后 numpy 会自动带上单独装一份也无妨。4.3 评估与阈值先看 AUC 还是先调阈值训练完模型先不要急着定阈值。AUC 是先要看的指标它衡量的是模型把活跃用户排在沉默用户前面的能力只要 AUC 在 0.75 以上排序就是有效的可以继续往下做。阈值放到业务场景里选运营能覆盖的推送名额有限这就变成一个在精确率和召回率之间取舍的问题。from sklearn.metrics import precision_recall_curve # 用最后一个 fold 的预测结果来选择阈值 precisions, recalls, thresholds precision_recall_curve(y_val, y_pred) # 场景假设运营要求召回率不低于 40%在这个约束下选最高精确率的阈值 candidates [(p, r, t) for p, r, t in zip(precisions, recalls, thresholds) if r 0.40] best max(candidates, keylambda x: x[0]) print(fselected threshold{best[2]:.3f}, precision{best[0]:.3f}, recall{best[1]:.3f})逻辑说明precision_recall_curve返回每个阈值下的精确率和召回率组合。运营约束通常是“接受一定漏召回但推送名单里不能有太多沉默用户”对应这里“召回率不低于 40% 时取精确率最高”。如果你反过来希望广撒网就在“精确率不低于某个值”的约束下取召回率最高。参数说明阈值的单位是概率范围 0 到 1。选完阈值后要回到原始特征宽表里看看被选中的用户分布确认不是集中在一两个特征极端值上。阈值不是永久的每周运营策略变化后要重新算这也是源码里通常把阈值作为配置项而不是写死的原因。5. 活动预测避坑指南五个最常翻车的细节5.1 时间泄漏标签用了未来信息指标全是假的现象训练时 AUC 高达 0.95验证集表现也完美上线后预测结果一塌糊涂运营反馈“名单里的人比随机选还差”。原因最常见的是特征和标签没在时间上对齐。比如用“截止到 1 月 10 日的特征”去预测“1 月 8 日到 1 月 14 日是否活跃”模型等于看到了未来或者标签构造时把特征截止日当天的活跃行为也算进去造成标签和特征包含同一段信息。另一个隐蔽来源是特征里混入了全局统计比如用了全量数据计算的用户历史平均活跃度这个值本身包含了预测窗口之后的信息。解决给每行样本打上feature_date字段强制要求特征截止日期 标签开始日期。在特征工程代码里加一道校验采样一小部分用户打印他们特征最后一条行为的时间戳和标签窗口的起始时间肉眼确认边界。我习惯把这类校验写成函数进数据管道时自动跑一旦特征时间戳晚于标签起始日就报错。5.2 类别不均衡AUC 没动不代表模型没救现象活跃用户只占样本的 6%模型输出几乎全是 0.1 以下的低概率AUC 却有 0.72看起来正常但精确率只有 8%运营没法用。原因AUC 只关心排序不关心预测概率的绝对水平。正样本少时模型倾向于把所有样本都预测成低概率只要少数正样本排在前面AUC 就好看。这时候精确率和召回率才是业务指标。解决用scale_pos_weight提高正样本权重或者在训练前对负样本做下采样让训练集里正负比接近 1:5 到 1:10。评估指标改成 AP平均精确率和召回率并画出 PR 曲线不要只盯着 AUC。阈值选择上用 5.3 里的约束式搜索不要用默认的 0.5。5.3 冷启动用户特征全是 0模型照样要输出现象新注册用户没有历史行为时间滑窗特征全是 0周期特征也没有有效值模型给出的活跃概率落在 0.2 左右被一刀切进沉默名单实际这批人注册头两周活跃率不低。原因行为特征对零历史样本没有区分度树模型在大量零值特征上学会的规律是“这个人没动过所以不活跃”对冷启动用户是系统性偏差。解决单独给冷启动用户建一套规则或轻量模型。特征上用社交网络信息补比如新用户关注的高活跃大 V 数量、好友数没有社交关系的话至少加入注册渠道和注册时长两个特征。常见做法是在特征表里加is_new_user标记让模型学到这部分用户的行为规律与老用户不同再用他注册前 3 天的有限行为比如是否完善了资料、是否首个互动对象是大 V做替代特征。5.4 数据对齐爬虫拿来的 UID 和内部 ID 对不上现象特征工程脚本运行时报 user_id 重复或者合并后行为表里的用户名和关系表里的对不上预测结果里用户数量比实际少了一截。原因社交网络活动预测里数据来源不统一时最容易出这个问题。爬虫拿的是平台公开页面上的用户名字符串或对外 ID内部系统用的是数字 UID两边没有做映射甚至时间戳格式都不同一边是毫秒级 Unix 时间戳另一边是字符串日期直接合并后时间窗口错位。解决在进特征工程之前先做 ID 映射和字段类型统一。写一个独立的对齐脚本先比对两个来源的样本量再抽样检查 user_id 是否都能在对方表里找到时间戳统一转成带时区的 datetime单独存一列原始值方便排查。对齐校验结果要打印如果映射覆盖率低于 99%先停了后续流程去补数据不要带着缺口往下跑。5.5 模型衰减上个月的模型这个月就不准了现象模型上线第一周 AUC 0.76一个月后 AUC 掉到 0.68运营明显感受到推送转化率下降。原因社交网络用户行为受热点事件、版本更新、运营活动影响行为分布一直在漂移。用户在夏天和冬天的活跃时段不同发帖类型也会随平台功能变化。模型学到的规律是截止到训练数据那一天的不会自动更新。解决常见做法是每天或每周增量重训。XGBoost 支持继续训练xgb_model参数传入上一轮模型用最近 30 天数据继续拟合比每天从零训练省时间。另外要监控特征分布和服务端预测概率均值一旦预测概率分布整体偏移超过设定阈值就触发重训流程。参考线是活动预测模型建议每 7 天重训一次重大运营活动结束后加训一次。6. 预测结果怎么用验证与进阶的实操技巧6.1 用回测验证预测结果离线 AUC 只是第一道关真正让人放心的是滚动回测。做法是取历史 60 天数据每天都做一次“特征截止日 未来 7 天标签”的样本构造每天训练并预测后一天第二天再滚动。这样你能得到 30 天以上的每日预测记录把它和真实行为对齐画出每日预测活跃率和实际活跃率的对比曲线偏差超过 5 个百分点就要排查。这套回测在源码里通常是一个独立脚本不会和训练脚本混在一起。跑一次回测要清楚它检验的不只是模型还有特征管道和标签定义的稳定性。如果回测里某天效果突然变差优先看那天前后是不是有运营活动或数据采集断档。6.2 输出概率分布而不是单点分数分类模型默认输出的是单个活跃概率但运营需要的是一个分数区间。把预测概率分成五档0 到 0.1、0.1 到 0.3、0.3 到 0.5、0.5 到 0.7、0.7 以上统计每个档位里用户的真实活跃率。如果模型校准得好0.5 到 0.7 档位的真实活跃率应该在 0.5 附近如果真实活跃率远低于预测值说明概率偏高需要做校准。校准的轻量做法是sklearn.isotonic或 Platt scaling用验证集拟合一个单调函数把预测概率映射到真实频率。校准不会改变 AUC但会让概率值可以直接当预算用比如“预测概率高于 0.6 的用户预计有 5000 人其中约 3000 人会回来”这句话运营能听懂也敢用来做资源预算。6.3 增量更新和轻量图模型我实际项目里最后保留的方案是XGBoost 底座每 7 天增量重训预测概率用校准曲线修正。图模型没有全面铺开只对冷启动用户做了 GraphSAGE 的邻居聚合特征因为冷启动用户行为特征全零邻居的活跃度均值比任何规则都稳定。增量重训时注意 xgb_model 接续训练要保留同样的特征列顺序新增特征列会导致模型内部索引错位。如果特征管道经常调整那就老老实实全量重训别为了省时间埋雷。另外线上预测脚本要支持从特征宽表实时读取最新特征我用的是把特征工程函数封装成独立模块训练和预测都 import 同一份代码避免两边各写一套逻辑。这套系统最值钱的部分不是模型算法而是特征截止日期的纪律性。我自己的教训是第一次做活动预测因为偷懒把标签和特征揉在同一个数据切片里整个一版模型作废重来。后来每张特征表都带 feature_date 和 label_window_start_time 两列任何下游任务看到这两列就知道数据边界在哪。希望帮到你。本文还有配套的精品资源点击获取