摘要:
合集:AI案例-ML-零售业
赛题:基于用户画像的商品推荐挑战赛
主办方:科大讯飞股份有限公司
主页:http://challenge.xfyun.cn/topic/info?type=user-portrait
AI问题:分类问题。
数据集:基本数据,性别年龄、用户标签、常驻地信息、机型信息5类特征
数据集价值:支持基于用户画像的商品推荐
解决方案:使用回归器LGBMRegressor用于0-1分类问题。
一、赛题描述
讯飞AI营销云基于深耕多年的人工智能和大数据技术,赋予营销智慧创新的大脑,以健全的产品矩阵和全方位的服务,帮助广告主用AI+大数据实现营销效能的全面提升,打造数字营销新生态。
基于用户画像的产品推荐,是目前AI营销云服务广告主的一项重要能力,本次赛题选择了两款产品分别在初赛和复赛中进行用户付费行为预测,参赛选手需基于提供的样本构建模型,预测用户是否会购买相应商品。
二、数据集说明
本次赛题是一个二分类任务,特征维度主要包括:基本数据,性别年龄、用户标签、常驻地信息、机型信息5类特征,出于数据安全的考虑,所有数据均为脱敏处理后的数据。初赛数据和复赛数据特征维度相同。
数据结构
pid,用户id
label,是否购买。
gender,性别,0-男性,1-女性
age,年龄,1-18岁以下,2-18-22岁,3-23-30岁,4-31~40岁,5-41~55岁,6-55岁以上
tagid,标签 id
time,用户标签生成时间戳,单位为毫秒
province,常驻地省份
city,常驻地城市
model,机型
make,厂商
其中:label字段作为因变量/输出变量。
数据样例
注释:未展示time字段值。
pid | label | gender | age | tagid | province | city | make | model |
---|---|---|---|---|---|---|---|---|
1016588 | 0 | NULL | NULL | [4457057,9952871,…] | 广西 | 北海 | 华为 | 华为 mate20pro |
1295808 | 1 | NULL | 5 | [10577375,13567578,…] | 广东 | 广州 | OPPO | r11 |
1110160 | 0 | NULL | NULL | [11171956,9454883,…] | 内蒙古 | 锡林郭勒盟 | 小米 | 小米 红米note2 |
1132597 | 0 | NULL | 2 | [4457927,9412324,…] | 四川 | 成都 | vivo | vivo x20 |
数据集版权许可协议
CC0
https://creativecommons.org/publicdomain/zero/1.0/deed.zh
三、解决方案样例
解决方案
源码:User_Product_Recommendation.ipynb
本案例的目标是基于用户画像数据,使用LightGBM算法预测用户购买行为。系统通过分析用户特征(如性别、年龄、地理位置、设备信息等)来预测用户购买概率。
安装
【本样例运行环境的关键版本信息】
python 3.12.3
lightgbm 3.3.0
导入相关系统库
import pandas as pd
import lightgbm as lgb
from sklearn.preprocessing import OrdinalEncoder
import warnings
warnings.filterwarnings("ignore")
工作流程
1、数据加载
- 读取训练数据(
train.csv
)和测试数据(apply_new.csv
) - 训练数据包含用户ID(pid)、标签(label)、性别(gender)、年龄(age)、标签ID列表(tagid)、时间(time)、省份(province)、城市(city)、设备品牌(make)、设备型号(model)等字段
train_df = pd.read_csv('./data/train.csv')
test_df = pd.read_csv('./data/apply_new.csv')
2、特征工程
tagid字段处理
tagid
字段包含用户的多维标签列表,格式为[id1,id2,...]
get_feature()
函数将tagid拆分为30个单独的特征列(tagid0-tagid29)- 如果标签数量不足30个,多余列填充为None
- 例如:
[4457057,9952871,...]
被拆分为tagid0=4457057, tagid1=9952871,…
# 拆分 targid 字段
def get_feature(df):
df['tagid_list'] = df['tagid'].apply(lambda x:x[1:-1].split(","))
for i in range(30):
df['tagid' + str(i)] = df['tagid_list'].apply(lambda x:x[i] if len(x) >= i + 1 else None)
return df
类别特征编码
- 对省份(province)和城市(city)使用OrdinalEncoder进行数值编码
- 未知类别会被编码为-1
# 将非数值类型字段转换为数值类型
train['label'] = train['label'].fillna(0)
train['label'] = pd.to_numeric(train['label'], errors='coerce')
oe = OrdinalEncoder(handle_unknown='use_encoded_value', unknown_value=-1)
for col in ['province', 'city']:
test[col] = oe.fit_transform(test[[col]])
train[col] = oe.transform(train[[col]])
for col in ['gender', 'age']:
train[col] = train[col].fillna(0)
test[col] = test[col].fillna(0)
train[col] = pd.to_numeric(train[col], errors='coerce')
test[col] = pd.to_numeric(test[col], errors='coerce')
缺失值处理
- 性别(gender)和年龄(age)中的缺失值用0填充
- tagid拆分后的各列中的缺失值也用0填充
for i in range(30):
col = f'tagid{i}'
train[col] = pd.to_numeric(train[col], errors='coerce')
test[col] = pd.to_numeric(test[col], errors='coerce')
# 用0填充缺失值
train[col].fillna(0, inplace=True)
test[col].fillna(0, inplace=True)
3、模型训练
3.1 特征选择
- 排除不用于训练的特征:pid、model、make、tagid_list、tagid、time、label
- 最终特征包括:gender、age、province、city和30个tagid特征
3.2 LightGBM模型
- 使用LGBMRegressor(回归器)而非分类器
- 参数配置:
- max_depth=15 (树的最大深度)
- num_leaves=20 (叶子节点数)
- learning_rate=0.1 (学习率)
- n_estimators=100 (树的数量)
- seed=2020 (随机种子)
fea = [f for f in train.columns if f not in ['pid', 'model', 'make', 'tagid_list', 'tagid', 'time', 'label']]
model = lgb.LGBMRegressor(max_depth=15, num_leaves=20, learning_rate=0.1, n_estimators=100, seed=2020)
model.fit(train[fea], train['label'])
pre = model.predict(test[fea])
说明:
model
:之前定义的LightGBM回归器实例fit()
:模型训练方法train[fea]
:训练特征数据(自变量/输入特征)train['label']
:训练标签数据(因变量/输出变量)
虽然fit()
方法本身不返回可见输出,但训练过程中LightGBM通常会显示类似如下的日志:
[LightGBM] [Info] Auto-choosing col-wise multi-threading, the overhead of testing was 0.044313 seconds.
You can set `force_col_wise=true` to remove the overhead.
[LightGBM] [Info] Total Bins 7926
[LightGBM] [Info] Number of data points in the train set: 300000, number of used features: 34
[LightGBM] [Info] Start training from score 0.500000
4. 预测与输出
4.1 预测
- 对测试集进行预测,得到每个用户的购买概率(0-1之间的值)
4.2 结果转换
- 将概率值转换为二元分类结果:
- 0.5的预测为1(会购买)
- ≤0.5的预测为0(不会购买)
4.3 结果保存
- 输出包含user_id和category_id两列的CSV文件
- category_id即为预测结果(0或1)
test['pre'] = pre
test['pre'] = test['pre'].apply(lambda x:1 if x > 0.5 else 0)
sub = test[['pid', 'pre']]
sub = sub.rename(columns = ({'pid':'user_id', 'pre':'category_id'}))
sub.to_csv('sub.csv', index = False)
输出:sub.csv数据样例
user_id category_id
1400001 1
1400002 0
1400003 0
1400004 0
1400005 0
1400006 0
1400007 1
1400008 0
1400009 1
...
5. 关键点分析
- 特征工程:通过拆分tagid列表,将用户的多维标签转化为模型可用的特征
- 类别编码:使用OrdinalEncoder处理地理信息,简单高效但可能不适合所有场景
- 缺失值处理:统一用0填充,简单但可能引入偏差
- 模型选择:虽然这是一个分类问题(预测0或1),但使用了LGBMRegressor。实际输出是0-1之间的概率值,后续通过阈值(0.5)转换为类别。
- 参数选择:相对保守的参数设置(中等树深和叶子数),可能为了防止过拟合
- 并行计算:LightGBM会自动利用多线程进行并行训练。可以通过
n_jobs
参数控制线程数。
源码开源协议
GPL-3.0 license
https://github.com/datawhalechina/competition-baseline/blob/master/LICENSE