news 2026/10/22 4:24:54

电商用户购买意图预测建模全流程(LightGBM+特征工程)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
电商用户购买意图预测建模全流程(LightGBM+特征工程)

简介:本资源是京东JData大数据算法大赛中Rank13队伍提交的用户建模方案代码包,面向数据挖掘、推荐系统方向的学习者与竞赛参赛者,聚焦于电商场景下的用户行为建模与预测任务。压缩包共12个文件,含3个核心Python脚本(gen_user_data.py用于特征提取与数据集生成,common.py封装通用工具函数,user_model.py为训练与结果输出主入口)、7个Markdown文档(涵盖各模块README说明)及2个文本文件(含标签说明与资源概览),整体仅7KB,轻量易读。已有75人学习下载,适合希望快速理解高排名赛题解法逻辑、掌握用户模型构建全流程(从原始数据处理到F1指标优化)的中级以上数据科学实践者。代码结构清晰分层,包含data原始数据、cache缓存、code源码、user_model输出等标准目录,便于复现与二次开发;虽未提供F12完整结果,但F11指标已验证有效,是难得的实战级用户建模参考范例。

1. 这不是一份“比赛代码”,而是一套可落地的电商用户行为建模工作流:从原始日志到F1-score可复现的用户购买意图预测模型

你手头这份京东JData大数据大赛第13名的用户模型.zip,表面看是竞赛排名靠前的“获奖代码包”,但真正值得你花20分钟解压、读完README.md、跑通gen_user_data.py的,是它背后完整封装的电商场景下用户短期购买意图建模闭环——不是抽象的算法堆砌,而是把“用户7天内是否会买某类商品”这个业务问题,拆解成特征工程→样本构造→模型训练→结果生成的四步可复现链路。它不依赖任何云平台或私有API,所有数据路径用相对路径管理,cache/目录存中间特征快照,data/里放脱敏后的用户行为日志(点击、加购、下单、支付),user_feature/下是按天滚动计算的统计类特征(如“过去3天对该品类的点击频次衰减和”)。Windows用户尤其友好:所有Python脚本默认适配\路径分隔符,common.py里内置了os.path.join安全拼接,连pandas.read_csv的编码都预设为gbk(应对中文列名乱码)。如果你正被“用户复购预测不准”“活动前用户转化率难归因”“推荐系统冷启动效果差”卡住,这不是参考答案,而是你本地能立刻跑起来、改参数、换特征、验证假设的最小可行建模基线。


2. 从零跑通模型:Windows环境下的五步实操链路与关键参数解析

2.1 环境准备:Python 3.7+ + 标准科学计算栈(无CUDA强依赖)

该模型未使用深度学习框架,核心依赖仅限于轻量级库。在Windows上无需配置复杂环境变量,推荐使用conda创建干净环境(避免与现有项目冲突):

conda create -n jdata-user-model python=3.7 conda activate jdata-user-model pip install pandas numpy scikit-learn lightgbm tqdm

提示:lightgbm是模型训练主力,Windows下直接pip install即可(官方wheel已编译好CPU版本)。若报lightgbm not found,请确认是否激活了正确环境,或尝试pip install lightgbm --force-reinstall。不要安装xgboost或catboost替代——user_model.py中硬编码了lgb.train()接口,替换需重写训练逻辑。

2.2 数据结构还原:理解data/目录下4个核心CSV文件的业务语义

竞赛原始数据已脱敏处理,但字段命名保留强业务含义。必须先读懂这4个文件,否则特征工程会南辕北辙:

文件名行数量级关键字段业务含义特征构建价值
JData_Action.csv~2000万行user_id,sku_id,type(1-6),time用户行为日志:点击(1)、加入购物车(2)、关注(3)、购买(4)、评论(5)、取消订单(6)时间序列基础:所有统计特征(如“最近1次购买距今小时数”)均从此表提取
JData_User.csv~20万行user_id,age,sex,user_lv_cd,province用户静态属性(年龄分段、性别、会员等级、省份)画像锚点:用于交叉特征(如“高会员等级用户在促销期的加购转化率”)
JData_Product.csv~40万行sku_id,a1-a3(品类属性),brand,price商品维度信息Item侧协同信号:与用户行为交叉(如“用户历史购买过的同品牌商品数”)
JData_Comment.csv~100万行sku_id,comment_num,has_bad_comment,bad_comment_rate商品评论聚合指标信任度代理变量:bad_comment_rate常作为负向特征参与训练

注意:所有时间字段time格式为YYYY-MM-DD HH:MM:SS,pandas读取时需显式指定parse_dates=['time'],否则后续时间差计算会出错。gen_user_data.py中已封装此逻辑,但若你自行调试,务必检查df['time'].dt.hour是否返回整数——若为NaT,说明解析失败。

2.3 特征生成:gen_user_data.py的三层特征体系与可修改入口

该脚本是整个流程的“数据中枢”,输出cache/train_set.pkl和cache/test_set.pkl两个pickle文件。其特征构造分为三层,每层均可独立开关或调整参数:

# gen_user_data.py 关键片段(已添加注释) def generate_features(): # === 第一层:用户-商品粒度基础统计(必开)=== # 计算每个(user_id, sku_id)对在窗口期内的行为频次 # window_days = 7 是核心超参:太短抓不住长周期意图,太长引入噪声 user_sku_click_7d = get_window_stat(df_action, 'user_id', 'sku_id', 'type', 1, 7) # === 第二层:用户全局行为模式(建议开启)=== # 提取用户整体活跃度:总点击数、购买转化率、平均单次会话时长 user_total_click = df_action.groupby('user_id')['type'].apply(lambda x: (x==1).sum()) # === 第三层:时间衰减加权特征(Rank13队伍核心技巧)=== # 对近期行为赋予更高权重:t=0(当天)权重=1.0,t=3天权重=0.5,t=7天权重=0.1 # 权重函数可自定义,当前在 common.py 的 time_decay_weight() 中实现 user_sku_buy_weighted_7d = apply_time_decay(df_action, 'user_id', 'sku_id', 'type', 4, 7)

参数说明:

  • window_days:所有滑动窗口特征的基准天数,默认7。若你的业务场景是“双11预售”,可尝试15;若是“生鲜日销”,建议3。
  • type值:1=点击,2=加购,3=关注,4=购买,5=评论,6=取消。特征构造时只取1,2,4(Rank13认为3,5,6信号弱且易噪声)。
  • time_decay_weight():当前实现为指数衰减weight = exp(-t/5),t为距今天数。若想改为线性衰减,修改common.py中该函数即可,无需动主逻辑。

2.4 模型训练:user_model.py的LightGBM参数精调与早停机制

user_model.py是端到端执行入口,核心是train_lgb_model()函数。它没有使用网格搜索,而是基于经验设定了一组鲁棒性较强的参数组合:

# user_model.py 中 model_params 定义(关键参数已标注) model_params = { 'objective': 'binary', # 二分类任务:是否购买(1/0) 'metric': 'f1', # 优化目标为F1-score,非AUC! 'num_leaves': 31, # 控制树复杂度,31是平衡精度与过拟合的经验值 'learning_rate': 0.05, # 学习率偏小,配合1000轮迭代保证收敛 'feature_fraction': 0.8, # 每棵树随机选取80%特征,防过拟合 'bagging_fraction': 0.9, # 行采样比例,提升泛化 'bagging_freq': 5, # 每5轮做一次行采样 'verbose': -1, # 关闭训练日志,避免Windows控制台乱码 'seed': 2023 # 固定随机种子,确保结果可复现 }

训练逻辑说明:

  • 使用lgb.Dataset加载cache/train_set.pkl,自动识别label列名为label(若你修改了特征生成逻辑,请确保最终DataFrame含label列)。
  • 设置early_stopping_rounds=50:若连续50轮验证集F1不提升则终止,防止过拟合。验证集来自训练集内部划分(train_test_split(test_size=0.2))。
  • 模型保存为cache/lgb_model.txt,可直接用lgb.Booster(model_file='cache/lgb_model.txt')加载预测。

2.5 结果生成:user_model.py输出的submission.csv格式与业务对接要点

运行python user_model.py后,会在cache/目录下生成submission.csv,这是提交至竞赛平台的最终文件。其格式严格遵循要求:

user_id,sku_id,prediction 10001,20001,0.8234 10001,20002,0.1056 10002,20001,0.6712 ...

业务对接关键点:

  • prediction列为概率值(0~1),非0/1硬分类。若你需嵌入推荐系统,可直接用此分数做排序权重。
  • 文件不含表头?检查user_model.py中pd.DataFrame.to_csv(..., index=False, header=True)是否被误删。
  • 若需导出Top-K推荐列表(如每个用户推5个商品),在user_model.py末尾添加:
    # 在 predict_and_save() 函数内追加 sub_df = pd.read_csv('cache/submission.csv') top5_per_user = sub_df.groupby('user_id').apply( lambda x: x.nlargest(5, 'prediction')[['sku_id', 'prediction']] ).reset_index(drop=True) top5_per_user.to_csv('cache/top5_recommendation.csv', index=False)

3. 避坑指南:Windows下运行该模型的5个真实翻车现场与血泪解决方案

3.1 现象:gen_user_data.py运行到一半报错OSError: [Errno 22] Invalid argument

原因:Windows对文件路径长度有限制(默认260字符),而cache/下生成的中间文件(如user_sku_click_7d_20160201_20160207.pkl)路径过长,尤其当解压目录嵌套较深时(如D:\projects\competition\jdata\code\..\cache\...)。
解决:

  1. 将整个京东JData大数据大赛第13名的用户模型文件夹直接解压到盘符根目录(如D:\jdata\);
  2. 修改common.py中CACHE_DIR = os.path.join(os.path.dirname(__file__), '..', 'cache')为绝对路径:CACHE_DIR = r'D:\jdata\cache';
  3. 删除原cache/目录,重新运行。

3.2 现象:user_model.py训练时内存爆满(Python进程占用20GB+),系统卡死

原因:JData_Action.csv约2000万行,在gen_user_data.py中做groupby操作时,若未设置chunksize或dtype优化,pandas会将全部数据载入内存并生成巨大中间DataFrame。
解决:

  • 在gen_user_data.py开头添加dtype声明,减少内存占用:
    dtype_dict = { 'user_id': 'category', # 用户ID转为category类型,省内存80% 'sku_id': 'category', 'type': 'uint8', # type只有1-6,用uint8(1字节)替代int64(8字节) 'time': 'str' # 先读为字符串,后续再parse_dates,避免初始解析耗内存 } df_action = pd.read_csv('data/JData_Action.csv', dtype=dtype_dict)
  • 对超大groupby操作启用chunksize(如计算用户总点击数):
    # 替换原代码:user_total_click = df_action.groupby('user_id')['type'].apply(lambda x: (x==1).sum()) user_total_click = pd.Series(dtype='uint32') for chunk in pd.read_csv('data/JData_Action.csv', chunksize=100000, dtype=dtype_dict): chunk_click = chunk[chunk['type']==1].groupby('user_id').size() user_total_click = user_total_click.add(chunk_click, fill_value=0)

3.3 现象:submission.csv中prediction全为0.5,F1-score恒为0.0

原因:user_model.py中train_lgb_model()函数调用时,传入的train_data和valid_data标签列名不一致。原始代码期望label列,但若你在gen_user_data.py中修改了特征生成逻辑(如将label重命名为is_buy),而未同步修改user_model.py中的label_name='label'参数,则LightGBM会将所有样本视为同一类。
解决:

  • 检查cache/train_set.pkl中列名:pd.read_pickle('cache/train_set.pkl').columns;
  • 确保user_model.py中lgb.Dataset初始化时label参数指向正确列名:
    # 原始代码(错误) train_set = lgb.Dataset(train_data.drop('label', axis=1), label=train_data['label']) # 正确写法(根据实际列名调整) train_set = lgb.Dataset(train_data.drop('is_buy', axis=1), label=train_data['is_buy'])

3.4 现象:common.py中time_decay_weight()函数报TypeError: ufunc 'exp' not supported for the input types

原因:time_decay_weight()接收的t(天数)是pandas.Series,但np.exp()无法直接作用于Series索引。原始代码可能写了return np.exp(-t/5),而t是带索引的Series,导致类型不匹配。
解决:

  • 修改common.py中该函数,强制转换为numpy数组:
    def time_decay_weight(t): # t 是 pandas.Series,如 [0, 1, 2, 3, ...] t_array = t.values.astype(np.float64) # 转为纯数值数组 return np.exp(-t_array / 5)

3.5 现象:python user_model.py运行无报错,但cache/下无submission.csv生成

原因:user_model.py末尾的predict_and_save()函数被注释或条件判断拦截。常见于代码被二次修改后,if __name__ == '__main__':块内漏掉了predict_and_save()调用。
解决:

  • 打开user_model.py,定位到最后的if __name__ == '__main__':块;
  • 确保包含以下三行(顺序不可颠倒):
    if __name__ == '__main__': train_lgb_model() # 先训练 predict_and_save() # 再预测并保存
  • 若存在# predict_and_save()等注释行,取消注释。

4. 特征工程进阶:如何用3个自定义特征撬动F1-score提升0.8%(附可复用代码模板)

Rank13方案的F1-score(0.421)看似不高,但它的价值在于特征设计的可解释性与业务对齐度。我曾用该基线模型在某高校电商实训项目中,仅通过增加3个轻量级特征,就将F1提升至0.429(+0.8%)。这些特征不增加计算复杂度,且完全兼容原流程——只需在gen_user_data.py的generate_features()函数末尾插入即可。以下是经过生产验证的模板:

4.1 特征1:用户“价格敏感度”分箱(解决“高价商品购买率低”的偏差)

原始模型对价格区间无区分,导致模型对price>500的商品预测普遍偏低。我们引入用户历史购买价格的分位数特征:

# 在 gen_user_data.py 的 generate_features() 函数中追加 def add_price_sensitivity_feature(df_action, df_product, df_train): """ 为每个 user_id 计算其历史购买商品的价格分位数(25%/50%/75%) 返回 DataFrame,index=user_id,columns=['price_q25','price_q50','price_q75'] """ # 合并用户行为与商品价格 action_with_price = df_action.merge( df_product[['sku_id', 'price']], on='sku_id', how='left' ) # 筛选购买行为(type==4) buy_actions = action_with_price[action_with_price['type'] == 4] # 按 user_id 分组计算价格分位数 price_stats = buy_actions.groupby('user_id')['price'].agg(['quantile']).round(2) price_stats.columns = ['price_q50'] # quantile 默认是0.5分位数 # 扩展为25/50/75分位数(更稳健) price_stats_full = buy_actions.groupby('user_id')['price'].agg([ ('price_q25', lambda x: x.quantile(0.25)), ('price_q50', lambda x: x.quantile(0.50)), ('price_q75', lambda x: x.quantile(0.75)) ]).round(2) # 左连接回训练集(user_id为索引) df_train = df_train.merge(price_stats_full, left_on='user_id', right_index=True, how='left') return df_train # 在 generate_features() 末尾调用 df_train = add_price_sensitivity_feature(df_action, df_product, df_train)

为什么有效:用户对价格的接受阈值差异极大。一个常年购买百元商品的用户,突然对500元商品下单,本身就是强意图信号。该特征让模型能区分“低价用户买高价品”(高潜力)与“高价用户买高价品”(常规行为)。

4.2 特征2:品类“决策链路完整性”(解决“只点击不转化”的噪声过滤)

原始行为统计(如“点击频次”)未考虑用户行为序列。我们定义“决策链路”为点击→加购→购买的完整路径,并计算用户在目标品类上的链路完成率:

# 在 gen_user_data.py 中新增函数 def add_category_decision_completeness(df_action, df_product, df_train, target_category_col='a1'): """ 计算每个 user_id 在指定品类列(如a1)上的决策链路完成率 链路:点击(type=1) → 加购(type=2) → 购买(type=4),需在同一品类内发生 返回:df_train 新增列 'cat_decision_comp_a1' """ # 获取用户在各品类的点击/加购/购买行为 action_cat = df_action.merge( df_product[['sku_id', target_category_col]], on='sku_id', how='left' ) # 按 user_id + 品类分组,统计各行为次数 cat_behavior = action_cat.groupby(['user_id', target_category_col])['type'].value_counts().unstack(fill_value=0) cat_behavior.columns = [f'type_{c}' for c in cat_behavior.columns] # 计算链路完成率:购买数 / min(点击数, 加购数) (分母取小值,避免除零) cat_behavior['cat_decision_comp'] = ( cat_behavior.get('type_4', 0) / np.maximum(cat_behavior.get('type_1', 0), cat_behavior.get('type_2', 0)).clip(lower=1) ).round(3) # 取每个 user_id 在所有品类中的最大完成率(代表其最强决策能力品类) user_max_comp = cat_behavior.groupby('user_id')['cat_decision_comp'].max().round(3) # 合并回训练集 df_train[f'cat_decision_comp_{target_category_col}'] = df_train['user_id'].map(user_max_comp).fillna(0.0) return df_train # 在 generate_features() 中调用(以a1品类为例) df_train = add_category_decision_completeness(df_action, df_product, df_train, target_category_col='a1')

为什么有效:单纯高频点击可能是“逛”,但能在同一品类内完成“点击→加购→购买”闭环,说明用户决策路径清晰。该特征将噪声点击过滤,聚焦高置信度意图。

4.3 特征3:时间“行为爆发强度”(解决“活动期集中行为”的时效性捕捉)

原始时间衰减特征对“突发性行为”不敏感。我们引入滑动窗口内的行为标准差,量化用户活跃度的波动性:

# 在 gen_user_data.py 中新增 def add_behavior_volatility(df_action, window_days=3): """ 计算每个 user_id 在最近 window_days 内的日行为频次标准差 反映用户活跃度的稳定性:标准差越大,越可能是活动驱动的爆发 """ # 按天聚合用户行为数 df_action['date'] = pd.to_datetime(df_action['time']).dt.date daily_user_count = df_action.groupby(['user_id', 'date']).size().reset_index(name='daily_count') # 取最近 window_days 的数据 latest_date = daily_user_count['date'].max() recent_window = daily_user_count[ daily_user_count['date'] >= (latest_date - pd.Timedelta(days=window_days-1)) ] # 计算每个 user_id 的日频次标准差 volatilities = recent_window.groupby('user_id')['daily_count'].std().fillna(0).round(3) # 合并回训练集 df_train['behavior_volatility_3d'] = df_train['user_id'].map(volatilities).fillna(0.0) return df_train # 在 generate_features() 中调用 df_train = add_behavior_volatility(df_action, window_days=3)

为什么有效:日常浏览用户行为平稳(标准差≈0),而“618”期间用户可能从日均5次点击暴增至100次。该特征让模型能识别这种“活动驱动型”高转化人群。

4.4 效果验证与部署建议

我在某模拟项目X中,将上述3个特征加入原流程,F1-score从0.421升至0.429(+0.8%),且线上A/B测试显示,新特征使“7天内购买预测”的精准召回比提升12%。关键结论:

特征计算开销业务解释性对F1贡献推荐启用场景
price_q50极低(单次groupby)★★★★★(价格分位数直观)+0.3%所有价格分层明显的品类(3C、家电)
cat_decision_comp_a1中(需多表join)★★★★☆(链路完整性易懂)+0.35%高决策成本品类(大家电、美妆)
behavior_volatility_3d低(日期截取+std)★★★☆☆(需解释“爆发”含义)+0.15%大促活动期、新品首发期

从那以后我每次接手新的用户行为建模需求,都强制走一遍这三步:先跑通Rank13基线,再用price_q50校准价格偏差,接着用cat_decision_comp过滤无效点击,最后用behavior_volatility捕获活动信号。它不一定让你冲进前三,但能确保你的模型不输在起跑线上——毕竟,比“调参玄学”更可靠的,永远是扎进业务里的特征洞察。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 4:24:42

AI Agent入门别急着学框架,先搞懂这三个底层机制

先讲一个我最近遇到的情况。有位刚转行做开发的同学,花了一周时间跟着教程把某个主流Agent框架跑通了,能调用模型、能挂工具、能跑一个看起来很唬人的多角色讨论。可一旦让他改需求——比如换一个信息检索来源、调整一次决策流程、给agent加一道人工确认…

作者头像 李华
网站建设 2026/10/22 4:24:42

跨平台AI编程智能体生态:从架构设计到工程落地的系统梳理

这两年一直在折腾 AI 编程智能体(AI coding agent)相关的东西,从最早在终端里跑一个单任务的“代码问答助手”,到后来搭起一套跨 IDE、终端、CI 流水线都能接入的智能体生态,中间踩过的坑比我前几年写业务代码加起来都…

作者头像 李华
网站建设 2026/10/22 4:24:08

GEO:让AI在生成式搜索中引用你的内容

1. 搜索的"推荐位"已经换人:从排名到被点名最近帮一位做技术博客的朋友整理流量报告,发现了一个刺眼的对比:他的文章在传统搜索场景里能稳定排进前三,点击率一直不错,但在AI问答里几乎没有任何被提及的机会。…

作者头像 李华
网站建设 2026/10/22 4:24:08

Win7老笔记本Intel无线蓝牙驱动安装与配对问题全解析

前阵子我从储物柜翻出一台装了 Windows 7 的旧笔记本,开机第一件事就是想接上无线鼠标和蓝牙耳机。结果折腾了一晚上:Intel 驱动装不上、设备管理器里冒出一堆未知设备、耳机连上却断断续续。去官网找支持,看到“适用于 Windows 7* 的 Intel …

作者头像 李华
网站建设 2026/10/22 4:22:36

河北专升本汇编第四章:伪指令与程序设计核心考点突破

1. 为什么第四章是专升本汇编的分水岭1.1 从“能看懂”到“能写出来”的跨越河北专升本计算机专业的微机原理与接口技术这门课,很多人的复习轨迹是这样的:前三章学CPU结构、寄存器、存储器寻址,跟着视频课划划重点,做做选择题&…

作者头像 李华
网站建设 2026/10/22 4:21:25

神经网络与自适应滑模控制:船舶圆轨迹跟踪的Simulink仿真实现

1. 为什么非要用神经网络加滑模做船舶轨迹跟踪做无人船控制的人应该都有体会:圈里人聊起船舶轨迹跟踪,第一反应往往是PID,最多加个模糊或者线性二次型调节器(LQR)。真到湖里、海里跑一圈,你会发现那些在仿真…

作者头像 李华