ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

营销反作弊实战:Python构建异常行为分析模型全流程

营销反作弊实战:Python构建异常行为分析模型全流程 做营销的同学应该都有过这种感觉活动预算一次比一次高用户量看着涨了最后GMV和复购却对不上账。上个月和一个做增长的朋友吃饭他大促发了一波新人立减券第二天一查后台同一个网段IP领走了几百张券注册时间集中在凌晨三点设备型号清一色是某个改机工具伪造的空壳机型。这不是段子是每年都在发生的真实损耗。营销反作弊要解决的就是这种事。它的核心不是封号而是从海量行为和流量里把那些不像“真人用户”的访问和交易提前识别出来。而异常行为分析模型就是反作弊体系里最基础也最吃功夫的一环——用数据分析的方法给每个用户的行为“打分”判断他到底是正常用户、羊毛党、脚本机器人还是团伙化作业的引流号。这篇文章我会用一份模拟的营销活动行为数据从特征提取开始手写规则引擎、统计离群点检测、孤立森林三套异常检测方法全部用Python实现。代码都经过实际运行可以直接复制下来跑。适合正要搭反作弊或者做活动风控的数据分析师、策略产品经理和Python开发者看也是我踩过很多坑之后沉淀下来的一套最小可用方案。1. 营销反作弊的战场先搞清楚黑产在薅什么1.1 异常行为分析模型在整个风控体系里的位置很多人一提到风控就想到机器学习模型但实际在营销反作弊场景里模型的地位很尴尬。真正的线上风控体系是一个多层的漏斗最底下是实时接口和名单库比如设备黑名单、手机号黑名单、IP信誉库往上一层是规则引擎跑那些确定性很强的策略比如“同一设备30分钟内注册超过3个账号”“同一IP当天领券超过10次”再往上才是异常行为分析模型用来捕捉那些单看规则不太明显、但组合起来就很可疑的行为模式。异常行为分析模型解决的是“规则引擎看不出来的那部分”。黑产也在进化他会模拟真人会养号会控制频率。如果只靠硬规则很容易被绕过。而用统计和机器学习方法做异常检测不会被单一阈值卡死能从多维度的行为组合里发现“这个人不太对劲”。这里要强调一个认知模型不是用来替代规则的是用来补位的。我见过不少团队一上来就上深度学习结果线上误伤一大堆真实用户运营天天来骂。合理的做法是先有规则兜底再用模型做广覆盖的异常召回最后人工审核收尾。1.2 黑产的行为画像在数据上到底长什么样要做异常检测首先得知道“异常”长什么样。结合我接触过的实际案例营销黑产的行为特征基本可以归纳成下面几类高度聚集性大量账号来自同一批IP、同一个设备、同一批手机号段这些信息在数据上会呈现明显的扎堆。高频与高速脚本跑起来可以在几秒内完成注册、领券、下单全套动作真人不可能做到。价值导向极端对优惠券、补贴、返现极其敏感使用率接近100%下单金额几乎贴着活动门槛。生命周期异常注册时间很新但行为密度非常高或者注册后长时间沉寂突然在某个活动节点活跃起来。这些特征单独看任何一条可能都有误判风险。一个家庭里三个人用同一个WiFiIP就是同一个一个大妈帮全家领优惠券注册时间也可能扎堆。所以异常行为分析模型必须做组合判断而不是只盯单点。2. 准备数据与Python工具异常检测的第一步2.1 行为日志数据字段别嫌多后面都有用做异常行为分析最理想的数据是用户行为明细日志至少要有以下字段user_id用户唯一标识。action_type行为类型比如register、login、browse、coupon_receive、order。action_time行为发生时间精确到秒最好。ip行为来源IP。device_id设备指纹通常由客户端SDK生成。coupon_used是否使用了优惠券。order_amount订单金额。有这些日志就能在用户维度上做特征聚合。如果公司没有埋点至少也要有注册信息表和订单表能拼出用户ID、注册时间、设备、IP、订单金额这些基础信息。我在实际项目里甚至见过只有Excel报名表的那就只能做最简单的注册频率和IP统计效果会弱很多。所以如果你要搭这个模型第一件事不是写代码是把埋点和日志补上。数据不到位后面一切白搭。2.2 Python环境与必需库代码部分我用的全是常见的Python数据分析库Python版本3.9或3.10都行建议直接用Anaconda管理环境。需要安装的库有pip install pandas numpy scipy scikit-learn matplotlib这几个库的分工很明确pandas负责数据清洗和聚合numpy做数值计算scipy提供统计函数scikit-learn提供孤立森林等机器学习算法matplotlib用来把检测结果可视化。如果你电脑里Python环境还没装顺手优先装Python 3.10再换国内镜像源装库速度会快很多依赖冲突也少。2.3 特征提取思路从行为日志到“用户行为指纹”异常行为分析模型处理的对象不是原始日志而是“用户行为特征表”。这些特征就是每个用户的行为指纹。常用特征分几类频次类登录次数、领券次数、下单次数、总行为数。聚合类用到的IP数、设备数、手机号数。比率类优惠券使用率、低金额订单占比、活动订单占比。速度类平均行为间隔、注册到首次下单时长。时间类活跃小时段分布、凌晨活跃占比。把这些特征拼成一张宽表每一行是一个用户每一列是一个行为指标。之后的规则、统计、机器学习检测全部跑在这张表上。下面的代码演示如何从一个明细日志里聚合出这些特征import pandas as pd # 假设 raw_df 是原始行为日志 # 字段: user_id, action_type, action_time, ip, device_id, coupon_used, order_amount feature_df raw_df.groupby(user_id).agg( total_actions(action_time, count), login_count(action_type, lambda x: (x login).sum()), coupon_count(action_type, lambda x: (x coupon_receive).sum()), order_count(action_type, lambda x: (x order).sum()), ip_count(ip, nunique), device_count(device_id, nunique), coupon_rate(coupon_used, mean), avg_order_amount(order_amount, mean), ).reset_index()这段代码用groupby按用户聚合nunique统计去重后的IP和设备数量mean计算优惠券使用占比。实际生产环境里数据量可能是千万级这里建议加上pandas的groupby优化或者直接用Spark/DuckDB做预处理。3. 手写Python代码从模拟数据到异常检测全流程3.1 第一步构造一份营销活动行为数据为了让代码可以完整跑通我先构造一份模拟数据。里面包含8000个正常用户和200个黑产用户正常用户行为分散黑产用户行为高度聚合且异常。import pandas as pd import numpy as np np.random.seed(42) n_normal 8000 n_black 200 data [] # 正常用户 for i in range(n_normal): data.append({ user_id: fU{10000i}, login_count: int(np.random.lognormal(2, 0.6)), device_count: int(np.random.randint(1, 3)), ip_count: int(np.random.randint(1, 3)), action_speed: float(np.random.gamma(2, 0.5)), coupon_rate: float(np.random.beta(2, 5)), order_count: int(np.random.randint(1, 10)), avg_order_amount: float(np.random.lognormal(4, 0.5)), }) # 黑产用户 for i in range(n_black): data.append({ user_id: fB{20000i}, login_count: int(np.random.randint(80, 300)), device_count: int(np.random.randint(3, 10)), ip_count: int(np.random.randint(3, 15)), action_speed: float(np.random.uniform(8, 30)), coupon_rate: float(np.random.uniform(0.85, 1.0)), order_count: int(np.random.randint(10, 80)), avg_order_amount: float(np.random.lognormal(3, 0.3)), }) df pd.DataFrame(data) print(df.head())这里有个小细节正常用户我用随机分布模拟比如登录次数服从对数正态分布优惠券使用率服从Beta分布这样更接近真实业务里的长尾分布。黑产用户则直接是“高登录、多设备、高速度、高券率”的形态。3.2 第二步用业务规则引擎做第一轮初筛规则引擎是异常检测里最朴素也最可靠的方法。它的优势是可解释、可快速上线、不容易被质疑。但规则不能太死否则很容易被黑产针对性绕过。我通常会把规则做成“打分制”而不是单条命中就判定。每条规则命中加1分总分超过阈值再判为高风险这样能降低单条规则的误伤。def rule_score(row): score 0 if row[login_count] 60: score 1 if row[device_count] 3: score 1 if row[ip_count] 3: score 1 if row[action_speed] 5: score 1 if row[coupon_rate] 0.8: score 1 if row[order_count] 30: score 1 return score df[rule_score] df.apply(rule_score, axis1) df[rule_abnormal] df[rule_score] 3 print(df[rule_abnormal].sum())运行结果会得到一批风险用户其中正常用户里也会有一些误报。为什么阈值取3我的经验是5到6条规则里命中3条以上基本可以认为行为模式明显偏离正常用户同时把误伤控制在可接受范围。阈值可以结合业务数据调整。3.3 第三步用IQR和Z-Score做统计离群点检测规则引擎是人工经验统计方法则是从数据分布里找离群点。这里介绍两个最常用的方法。IQR四分位距法不要求数据服从正态分布抗干扰能力强。它的原理是把数据切成四分位认为落在Q1-1.5×IQR到Q31.5×IQR之外的是离群点。Z-Score则是计算每个值和均值的距离超过3倍标准差算异常更适合近似正态分布的数据。def iqr_outlier_mask(s): q1 s.quantile(0.25) q3 s.quantile(0.75) iqr q3 - q1 lower q1 - 1.5 * iqr upper q3 1.5 * iqr return (s lower) | (s upper) def zscore_outlier_mask(s, th3): mu s.mean() std s.std() if std 0: return pd.Series(False, indexs.index) return (s - mu).abs() / std th df[iqr_abnormal] ( iqr_outlier_mask(df[login_count]) | iqr_outlier_mask(df[device_count]) | iqr_outlier_mask(df[coupon_rate]) | iqr_outlier_mask(df[action_speed]) ) df[zscore_abnormal] ( zscore_outlier_mask(df[login_count]) | zscore_outlier_mask(df[device_count]) | zscore_outlier_mask(df[coupon_rate]) | zscore_outlier_mask(df[action_speed]) ) print(df[[iqr_abnormal, zscore_abnormal]].sum())这两种方法有各自的性格。IQR对极端值不那么敏感适合优惠券使用率这种偏态分布很强的特征Z-Score会受极端值影响但响应更快适合做实时监控。我在项目里一般两个都跑然后取交集或做加权。3.4 第四步用孤立森林识别多维异常规则和统计方法都是单特征检测但真正的黑产行为往往是多特征组合出来的。孤立森林就适合干这个它的原理很形象异常点很少而且一旦被切分很快就能被孤立出来。from sklearn.ensemble import IsolationForest feature_cols [login_count, device_count, ip_count, action_speed, coupon_rate, order_count, avg_order_amount] X df[feature_cols].copy() # 有些模型对尺度敏感这里先做个标准化 from sklearn.preprocessing import StandardScaler scaler StandardScaler() X_scaled scaler.fit_transform(X) iso IsolationForest( n_estimators100, max_samples256, contamination0.05, random_state42 ) df[iso_score] iso.fit_predict(X_scaled) # 1正常, -1异常 df[iso_abnormal] df[iso_score] -1 print(df[iso_abnormal].sum())contamination参数很关键它表示模型预期数据里异常点占的比例。我这里设了0.05因为模拟数据里黑产占比大约2.4%留了一点buffer。真实场景里如果你不知道异常比例可以先看规则引擎和统计方法检测出的量级来推测。3.5 第五步可视化输出让检测结果直接落地模型不是跑完就结束你还要给运营和审核同事一个能理解的输出。可视化是最直接的沟通方式。对于多维特征可以用PCA降到二维再散点展示把检测出的异常点标红import matplotlib.pyplot as plt from sklearn.decomposition import PCA pca PCA(n_components2) X_pca pca.fit_transform(X_scaled) plt.figure(figsize(10, 6)) plt.scatter(X_pca[:, 0], X_pca[:, 1], c[#d62728 if a else #1f77b4 for a in df[iso_abnormal]], s10, alpha0.6) plt.title(Isolation Forest Abnormal Detection) plt.xlabel(PC1) plt.ylabel(PC2) plt.show()除了散点图还可以画每个特征在异常用户和正常用户之间的箱线图对比这样能直接看出哪些特征贡献最大。这一步在向业务方解释“为什么这波用户有风险”的时候特别好用有图就有说服力。4. 代码背后的原理每个检测指标为什么有效4.1 为什么“IP聚集度”和“设备指纹”是重灾区指标营销反作弊里有两个特征几乎是必看的IP聚集团和设备指纹。IP聚集度说的是同一个IP下关联了多少账号。黑产做批量操作最容易露馅的地方就在IP。虽然他可以用换IP的手段规避但IP池终究是有限的大量账号最终还是会聚类到一小批IP上。统计每个IP下关联的user_id数量一旦超过阈值这些账号就有连坐风险。设备指纹则是比IP更准的一层。正常用户哪怕换IP设备长期是稳定的黑产一台设备可能跑几十个账号。在实际项目里如果发现一个device_id关联的账号数超过5个基本可以标记高风险。这里注意设备指纹不止是设备ID字符串还包括机型、系统版本、屏幕分辨率等组合信息很多黑产会改设备ID但改不全其他属性组合起来反而能暴露。4.2 IQR和Z-Score的适用边界这两种统计方法看起来简单但用错了也会出问题。我在项目里见过同事直接用Z-Score检测订单金额结果因为订单金额长尾严重均值被大额订单拉高反而是那些正常的小额订单被误判成异常。所以用哪种方法先看数据分布。如果分布接近正态用Z-Score没问题如果是明显的长尾分布优先用IQR。也可以用scipy里的正态性检验先跑一下快速判断。不过实际业务里数据几乎都是偏态的我用IQR的次数明显更多。4.3 孤立森林参数怎么调才不瞎报警孤立森林用起来门槛不高但参数不对效果会差很多。最核心的三个参数n_estimators树的数量默认100够用数据量超大时加到200收益递减明显。max_samples每棵树抽多少样本默认256。如果数据量很大不需要全部参与反而能增加随机性。contamination异常占比这个最敏感直接决定判定阈值。设高了误报多设低了漏报多。实际操作中我会先跑一个基础的contamination0.05然后看检测结果的分布分数。IsolationForest的decision_function可以输出每个样本的异常分数不用直接看二分类标签而是把分数按从低到高排序人工复核Top N然后反推合理阈值。这样做比直接信默认参数靠谱得多。4.4 特征分布长尾严重时的处理技巧营销行为数据的特征几乎都是长尾的比如订单金额、登录次数、行为速度少数用户贡献了绝大多数值。如果不做处理直接喂给模型那些超大值会把模型带偏。常用的处理方式有两种一种是取对数变换比如np.log1p另一种是做分箱或分位缩放把特征转成0到1之间的相对排名。孤立森林本身是树模型对单调变换不敏感但其他模型比如基于距离和方差的就非常需要做标准化和对数化。我上面代码里已经用StandardScaler做了标准化但对于严重长尾特征最好先取对数再标准化。5. 真实上线会踩的坑误报、漏报和数据质量5.1 误报率太高运营说你是狼来了异常检测模型最怕的不是漏报是误报。因为漏报只是损失钱可误报会让运营人员处理大量无效工单消耗信任。一旦运营发现你标记的用户大部分是正常的后面你说什么他都不信了。控制误报的手段有两个。第一模型输出分数而不是标签运营只处理分数最高的Top N而不是全量命中用户。第二叠加人工审核和申诉机制被误判的用户可以申诉审核通过后加入白名单并且用这些样本反哺模型迭代。我在项目里会让运营在审核页面上加一个“确认正常”按钮点得多了后续就能拿这批数据做有监督的修正。5.2 新用户冷启动和特征缺失怎么兜底不少用户行为数据很少比如刚注册的新用户只有一个注册行为登录次数、下单次数统统是0或者缺失。这种情况下统计模型和孤立森林都会失效因为特征太稀疏了。我的处理方式是做缺口分流行为数据充足的老用户走完整的多维模型新用户和低活跃用户单独走注册类规则比如注册频率、IP聚集度、设备聚集度。等他们积累了足够行为再进入完整模型打分。所以在特征表里最好加一个“active_level”字段标识这个用户的行为样本是否足够避免模型去猜一个没有足够信息的用户。5.3 规则阈值、模型分数怎么和人工审核配合现实中的反作弊不可能全靠自动判定一定会有人工审核环节。问题是怎么配合最高效。我的经验是按风险分层高分段直接自动拦截中分段进人工审核队列低分段正常放行。分层阈值不是拍脑袋定的而是先小流量试跑一周看人工审核结果和模型分数的对应关系再用分数段的“风险命中率”来确定拦截阈值。这里有个管理上的教训不要追求100%准确率再上线那会让你错过大量拦截时机。先跑起来用人工审核兜底再持续迭代这是反作弊实战最实际的推进方式。5.4 模型落地部署的几个提醒离线分析的代码要变成线上可用的模型有几个坑要提前想清楚。模型要保存成文件可以序列化为pkl或者用ONNX格式线上加载同一个特征处理流程必须保持一致。最容易出错的就在特征处理上离线训练时你用了标准化线上预测时用的mean和std必须要和训练时一致否则分数完全对不上。解决办法是把scaler和模型一起打包保存而不是每次重新计算。还要注意时区问题。行为日志里的时间戳统一用UTC分析的时候再转本地时区否则凌晨活跃判定会因为时区偏移产生误差。这个我踩过大促复盘的时候发现一批用户被标成凌晨活跃后来查下来是日志里的时间是东八区代码里又当成UTC转了一次。6. 效果评估与后续迭代方向6.1 没有标注样本怎么评估模型有没有用异常检测最尴尬的问题是训练时没有标准答案你不知道哪些用户真的是黑产。这时候评估就得靠间接指标。我常用的评估方法有三个。一是抽样复核把模型判为异常的用户随机抽100个人工去核查注册链路和设备信息计算命中率。二是历史回溯拿过去已经确认的黑产名单回放看模型能在什么比例上召回。三是关注业务指标变化比如上线后同等活动成本的转化率、客诉率有没有改善这也是最朴素的证明方式。顺带说一句如果条件允许把每天拦截的用户名单沉淀下来加上运营的处置结果积累一个月后就能变成有标签样本回头再训练二分类模型精度会明显上一个台阶。这也是反作弊体系“从无监督到有监督”的常规路径。6.2 从单用户检测走向团伙识别单个用户的异常检测只是第一层。真正杀伤力大的黑产是团伙化作业——几千个账号协同行动单看每一个账号可能都很正常但放在一起看他们的行为网络高度紧密。所以“异常行为分析模型一”讲了单点异常检测之后下一步我建议做团伙识别。思路是把用户之间共用IP、设备、收货电话、支付账号这些关系构建成图用户是节点关联关系是边然后用社区发现算法找密集连接的团伙。你会发现那些单点模型觉得“还好”的用户一旦进了同一个团伙子图风险等级会瞬间拉满。这一段内容我计划单独写一篇展开涉及networkx建图、连通分量分析、社区发现算法以及和单点模型的融合策略。最后再分享一个实战心得。任何异常行为分析模型本质上都是在跟黑产玩猫鼠游戏。你今天觉得很强的特征可能三个月后就被对方绕过去了。所以千万别把模型当一次性项目来做要建立起特征池和规则库的持续更新机制每次大促结束都做一轮复盘把新发现的黑产手法沉淀成新特征。反作弊这件事没有一劳永逸只有兵来将挡、水来土掩但每一次有效的拦截省下来的都是实打实的真金白银。
返回列表