摘要:
合集:AI案例-ML-零售业
赛题:移动设备用户年龄和性别预测
主办方:科大讯飞 + Datawhale
主页:http://challenge.xfyun.cn/topic/info?type=mobile-devices&ch=dw-sq-1
AI问题:回归预测问题、分类问题
数据集:移动设备信息、APP信息和事件信息
数据集价值:对移动设备的用户进行性别和年龄的预测。
解决方案:使用LightGBM建立性别模型和年龄模型。
一、赛题描述
对于移动设备厂商而言,获取当前手机用户的人口属性信息是非常困难的。基于用户的手机及日常使用应用程序的偏好准确地预测其人口属性信息是提升个性化体验、构建精准用户画像的基础。需要说明的是,本赛事数据已获得个人用户的充分认可和同意,并已进行适当的匿名处理以保护隐私。由于保密,我们不会提供有关如何获得性别和年龄数据的详细信息。
本次比赛有两个任务,分别对移动设备的用户进行性别和年龄的预测,这里包含二分类和回归两个问题,最终会将两个部分的分数结合起来进行排名。
二、数据集说明
赛题数据由训练集、测试集、事件数据组成。总设备id超过2万部,包含设备信息、APP信息和事件信息,其中device_id为用户的唯一标识符,gender为用户性别,age为用户年龄。为了保证比赛的公平性,将会从中抽取2万条设备id为训练集,3千多个设备id作为测试集,同时会对部分字段信息进行脱敏。
特征字段 | 字段描述 |
---|---|
device_id | 用户对应设备号,唯一表示,无重复 |
gender | 用户性别,0为男性,1为女性 |
age | 用户年龄 |
phone_brand | 手机品牌 |
device_model | 手机型号 |
event_id | 事件id |
app_id | 应用程序id |
is_installed | 是否安装 |
is_active | 是否激活 |
tag_list | 应用程序的标签列表 |
date | 事件发生日期 |
数据样例
训练集中的设备信息
文件:train.csv
训练集包括用户年龄和性别目标变量值。
device_id | gender | age | phone_brand | device_model |
---|---|---|---|---|
0 | 0 | 35 | 0 | 0 |
1 | 1 | 37 | 1 | 1 |
2 | 0 | 32 | 1 | 2 |
3 | 1 | 28 | 1 | 2 |
4 | 0 | 75 | 2 | 3 |
5 | 0 | 25 | 0 | 4 |
6 | 0 | 27 | 3 | 5 |
测试集中的设备信息
文件: test.csv
测试集不包括用户年龄和性别目标变量值。
device_id | phone_brand | device_model |
---|---|---|
20000 | 3 | 59 |
20001 | 3 | 59 |
20002 | 0 | 10 |
20003 | 37 | 756 |
20004 | 2 | 3 |
训练集中的APP信息
train_app_events.csv
event_id | app_id | is_installed | is_active | device_id | tag_list | date |
---|---|---|---|---|---|---|
6 | 0 | 1 | 1 | 14271 | [549, 721, 704, 302, 303, 548, 183] | 1 |
6 | 1 | 1 | 1 | 14271 | [713, 704, 548] | 1 |
6 | 2 | 1 | 1 | 14271 | [549, 710, 704, 548, 172] | 1 |
6 | 3 | 1 | 1 | 14271 | [548, 549] | 1 |
6 | 4 | 1 | 1 | 14271 | [128, 1014] | 1 |
6 | 5 | 1 | 0 | 14271 | [1012] | 1 |
测试集中的APP信息
test_app_events.csv
event_id | app_id | is_installed | is_active | device_id | tag_list | date |
---|---|---|---|---|---|---|
39 | 1 | 1 | 1 | 20944 | [713, 704, 548] | 1 |
39 | 2 | 1 | 1 | 20944 | [549, 710, 704, 548, 172] | 1 |
39 | 67 | 1 | 0 | 20944 | [549, 713, 704, 548, 730, 756, 757, 775, 779, 783, 252, 407, 251, 406, 1012, 405] | 1 |
39 | 68 | 1 | 0 | 20944 | [714, 723, 548, 704, 178] | 1 |
39 | 69 | 1 | 0 | 20944 | [130, 223, 130] | 1 |
39 | 70 | 1 | 0 | 20944 | [1014] | 1 |
数据集版权许可协议
BY-NC-SA 4.0
https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh-hans
三、解决方案样例
解决方案
源码:Mobile_Phone_User_Forecast.ipynb
实现了一个基于LightGBM模型的移动设备用户年龄和性别预测系统。项目的主要目标是通过用户的手机使用行为和应用程序偏好数据,预测用户的人口统计信息(年龄和性别)。
安装
【本样例运行环境的关键版本信息】
python 3.12.3
lightgbm 3.3.0
seaborn 0.13.2
导入开发库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import gc
import seaborn as sns
from sklearn.model_selection import KFold
from sklearn.metrics import mean_absolute_error
import lightgbm as lgbm
主要分析步骤
- 数据加载与初步探索
- 读取训练集、测试集和应用程序事件数据
- 合并训练和测试的应用事件数据
- 数据探索分析
- 分析性别分布(二分类问题)
- 分析年龄分布(回归问题)
- 检查日期分布
- 分析事件ID和应用程序ID的分布
- 模型构建
- 使用LightGBM算法
- 同时处理分类(性别)和回归(年龄)问题
关键发现
- 性别分布
- 性别标签为0和1,分布相对均匀
- 年龄分布
- 主要集中分布在20-40岁之间
- 事件数据
- 事件ID的分布不均衡,有很多值为1的记录
- 较小的app_id出现频率较高
技术实现
- 工具库
- 主要使用pandas进行数据处理
- 使用matplotlib和seaborn进行可视化
- 使用LightGBM作为预测模型
- 模型特点
- 能够处理大规模数据
- 支持并行计算
- 对类别特征有良好支持
工作流程
1、数据预处理
- 合并相关数据表
- 分析特征分布
- 进行了特征工程
读入数据集:
data_path = './data/'
df_tr = pd.read_csv(data_path + 'train.csv')
df_tr_app_events = pd.read_csv(data_path + 'train_app_events.csv')
df_te = pd.read_csv(data_path + 'test.csv')
df_te_app_events = pd.read_csv(data_path + 'test_app_events.csv')
分析数据:
df_tr_te_app_events.head()
df_tr['gender'].value_counts().plot(kind = 'bar')
特征工程
最终生成的df_device_features
包含以下特征:
device_id
: 设备唯一标识event_id_count
: 设备总事件数event_id_nunique
: 设备唯一事件数app_id_nunique
: 设备使用的唯一应用数is_installed_mean
: 平均安装状态is_installed_sum
: 总安装次数is_active_mean
: 平均活跃状态is_active_sum
: 总活跃次数date_max
: 最后使用日期date_nunique
: 唯一日期数tag_list_len_mean
: 平均标签数量tag_list_len_std
: 标签数量标准差
df_tr_te_app_events['tag_list_len'] = df_tr_te_app_events['tag_list'].apply(lambda x: x.count(',') + 1)
agg_dic = {
"event_id": ['count', 'nunique'],
"app_id": ['nunique'],
"is_installed": ['mean', 'sum'],
"is_active": ['mean', 'sum'],
"date": ['max', 'nunique'],
"tag_list_len": ['mean', 'std']
}
df_device_features = df_tr_te_app_events.groupby('device_id').agg(agg_dic).reset_index()
fea_names = ['_'.join(c) for c in df_device_features.columns]
df_device_features.columns = fea_names
df_device_features.rename(columns = {'device_id_':'device_id'}, inplace = True)
2、模型训练
- 使用LightGBM进行训练
- 采用交叉验证评估模型性能
- 使用平均绝对误差(MAE)作为年龄预测的评估指标
性别模型 lgb_gender_models
这段代码实现了一个基于 LightGBM 的二分类模型(预测性别 gender
),采用 5折交叉验证 训练并生成预测结果。
核心逻辑:
- 数据划分:每折将训练集分为80%训练 + 20%验证。
- 早停机制:验证集AUC超过50轮未提升则终止训练。
- 集成预测:5折模型的预测结果取平均,减少方差,提升泛化性。
输出结果:
y_pred
:测试集的平均预测概率(范围[0,1]),表示性别为1的概率。lgb_gender_models
:保存的5个模型,可用于后续分析或集成。
# gender 模型
lgb_params = {
"objective": "binary", # 定义学习任务和相应的学习目标。"binary" 表示这是一个二分类任务
"metric": "auc", # 评估模型性能的指标。"auc": 曲线下面积,衡量模型的区分能力
"boosting_type": "gbdt", # 定义提升类型。"gbdt" 是梯度提升决策树的默认类型,适用于大多数情况
"early_stopping_rounds": 50, # 在验证集上监控模型的性能,如果在指定的轮数内性能没有提升,则提前停止训练,防止过拟合
"learning_rate": 0.05, # 控制每一步的步长,较小的学习率需要更多的迭代次数
"colsample_bytree": 0.8, # 每棵树随机采样的列数比例。0.8 表示每棵树使用 80% 的特征
"max_depth": 7, # 控制每棵树的最大深度,防止过拟合
"num_leaves": 63, # 调整为 2^max_depth - 1 或其他合适的值
"lambda_l1": 0.1, # L1 正则化参数,用于控制模型的稀疏性,促使部分特征的权重降为零
"lambda_l2": 0.1, # L2 正则化参数,用于防止模型权重过大,减少过拟合
"force_col_wise": True # 强制使用按列(特征)的多线程方式,提升并行计算的效率
}
X_tr_val = df_tr[tr_features + [label_gender]]
X_te = df_te[tr_features]
kf = KFold(n_splits=5)
lgb_gender_models = []
y_pred = 0
for f, (tr_ind,val_ind) in enumerate(kf.split(X_tr_val)):
X_train, X_valid = X_tr_val.iloc[tr_ind][tr_features], X_tr_val.iloc[val_ind][tr_features]
y_train, y_valid = X_tr_val.iloc[tr_ind][label_gender], X_tr_val.iloc[val_ind][label_gender]
lgbm_train = lgbm.Dataset(X_train, y_train)
lgbm_valid = lgbm.Dataset(X_valid, y_valid)
model_binary = lgbm.train(params = lgb_params,
train_set = lgbm_train,
valid_sets = [lgbm_train, lgbm_valid],
num_boost_round = 100000)
y_pred += model_binary.predict(X_te[tr_features]) / 5.0
lgb_gender_models.append(model_binary)
年龄模型 lgb_age_models
这段代码实现了一个基于 LightGBM 的回归模型,用于预测年龄(age),采用 5折交叉验证 训练并生成预测结果。
自定义评估指标 feval_lgb_Age,计算 逆平均绝对误差(Inverse MAE)。
- 公式:1 / (1 + MAE),将MAE映射到(0,1]区间,值越大表示误差越小。
- 用途:在训练过程中监控模型性能(MAE的逆指标更直观)。
- 返回值:
- ‘Age Error’:指标名称。
- 计算值:保留7位小数。
- True:表示该指标需要最大化(值越大越好)。
变量说明:
- tr_features:特征列名列表(如用户行为、设备信息等)。
- label_age:目标列名(年龄标签,连续值)。
核心逻辑:
- 数据划分:每折将训练集分为80%训练 + 20%验证。
- 早停机制:验证集MAE超过50轮未提升则终止训练。
- 集成预测:5折模型的预测结果取平均,提升稳定性。
输出结果:
- y_pred:测试集的平均预测年龄(连续值)。
- lgb_age_models:保存的5个模型,可用于后续分析或集成。
# age 模型
def feval_lgb_Age(preds, lgbm_train):
labels = lgbm_train.get_label()
return 'Age Error', round(1.0 / (1.0 + mean_absolute_error(y_true = labels, y_pred = preds)), 7), True
lgb_params = {
"objective": "mae", # 指定回归任务的目标函数为平均绝对误差 (Mean Absolute Error, MAE)
"metric": ["mae", "mse"], # 在训练过程中监控多个评估指标。MAE 作为主要指标,MSE 作为辅助指标
"boosting_type": "gbdt", # 使用梯度提升决策树 (Gradient Boosting Decision Tree, GBDT) 作为提升类型
"learning_rate": 0.05, # 控制每一步的步长,较小的学习率需要更多的树
"max_depth": 7, # 控制每棵树的最大深度,防止过拟合
"num_leaves": 63, # 调整为 2^max_depth - 1 或其他合适的值
"subsample": 0.8, # 每棵树使用的样本比例,防止过拟合
"colsample_bytree": 0.9, # 每棵树使用的特征比例,防止过拟合
"min_child_samples": 20, # 每个叶子节点最少需要的样本数,控制树的复杂度
"reg_alpha": 0.1, # L1 正则化参数,促使部分特征权重为零,实现特征选择
"reg_lambda": 0.1, # L2 正则化参数,防止特征权重过大,减少过拟合
"early_stopping_rounds": 50, # 在验证集上监控性能,若在连续 50 轮内性能未提升,则提前停止训练
"force_col_wise": True, # 强制使用按列(特征)的多线程方式,提升并行计算效率
"random_state": 42, # 设置随机种子以确保可重复性
}
X_tr_val = df_tr[tr_features + [label_age]]
X_te = df_te[tr_features]
kf = KFold(n_splits=5)
lgb_age_models = []
y_pred = 0
for f, (tr_ind, val_ind) in enumerate(kf.split(X_tr_val)):
X_train, X_valid = X_tr_val.iloc[tr_ind][tr_features], X_tr_val.iloc[val_ind][tr_features]
y_train, y_valid = X_tr_val.iloc[tr_ind][label_age], X_tr_val.iloc[val_ind][label_age]
lgbm_train = lgbm.Dataset(X_train, y_train)
lgbm_valid = lgbm.Dataset(X_valid, y_valid)
model_mae = lgbm.train(params = lgb_params,
train_set = lgbm_train,
valid_sets = [lgbm_train, lgbm_valid],
num_boost_round = 100000,
feval = feval_lgb_Age)
y_pred += model_mae.predict(X_te[tr_features]) / 5.0
lgb_age_models.append(model_mae)
lgb_age_models模型运行结果展示:
[LightGBM] [Info] Total Bins 3024
[LightGBM] [Info] Number of data points in the train set: 16060, number of used features: 14
[LightGBM] [Info] Start training from score 30.000000
[1] training's l1: 7.18658 training's l2: 98.7373 training's Age Error: 0.122151 valid_1's l1: 8.32054 valid_1's l2: 134.681 valid_1's Age Error: 0.10729
Training until validation scores don't improve for 50 rounds
[2] training's l1: 7.1481 training's l2: 97.9286 training's Age Error: 0.122728 valid_1's l1: 8.29756 valid_1's l2: 134.197 valid_1's Age Error: 0.107555
[3] training's l1: 7.10613 training's l2: 97.06 training's Age Error: 0.123363 valid_1's l1: 8.27313 valid_1's l2: 133.706 valid_1's Age Error: 0.107839
[4] training's l1: 7.06716 training's l2: 96.2934 training's Age Error: 0.123959 valid_1's l1: 8.25321 valid_1's l2: 133.252 valid_1's Age Error: 0.108071
[5] training's l1: 7.03234 training's l2: 95.6126 training's Age Error: 0.124497 valid_1's l1: 8.23709 valid_1's l2: 132.804 valid_1's Age Error: 0.108259
[6] training's l1: 6.99877 training's l2: 94.93 training's Age Error: 0.125019 valid_1's l1: 8.21982 valid_1's l2: 132.403 valid_1's Age Error: 0.108462
[7] training's l1: 6.96855 training's l2: 94.3555 training's Age Error: 0.125493 valid_1's l1: 8.20477 valid_1's l2: 132.179 valid_1's Age Error: 0.108639
[8] training's l1: 6.93853 training's l2: 93.7717 training's Age Error: 0.125968 valid_1's l1: 8.19138 valid_1's l2: 131.906 valid_1's Age Error: 0.108798
[9] training's l1: 6.91015 training's l2: 93.2181 training's Age Error: 0.12642 valid_1's l1: 8.18054 valid_1's l2: 131.621 valid_1's Age Error: 0.108926
[10] training's l1: 6.88501 training's l2: 92.771 training's Age Error: 0.126823 valid_1's l1: 8.17306 valid_1's l2: 131.422 valid_1's Age Error: 0.109015
...
[LightGBM] [Warning] No further splits with positive gain, best gain: -inf
[125] training's l1: 6.24874 training's l2: 83.9056 training's Age Error: 0.137955 valid_1's l1: 6.69279 valid_1's l2: 83.8546 valid_1's Age Error: 0.129992
Early stopping, best iteration is:
[75] training's l1: 6.44785 training's l2: 87.0945 training's Age Error: 0.134267 valid_1's l1: 6.68082 valid_1's l2: 83.9237 valid_1's Age Error: 0.130194
Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...
3、预测任务
- 性别预测作为二分类问题
- 年龄预测作为回归问题
4、提交预测数据
df_submit.to_csv('Fold5_LightGBM_Prediction.csv', index = None)
输出Fold5_LightGBM_Prediction.csv文件数据样例:
device_id | gender | age | |
---|---|---|---|
20000 | 0 | 28.806677413357917 | |
20001 | 0 | 27.59215349418558 | |
20002 | 0 | 29.26203952711162 | |
20003 | 0 | 30.695609222773804 | |
20004 | 0 | 26.23625341785736 | |
20005 | 0 | 31.658387653325356 | |
20006 | 0 | 30.43398943867413 |
源码开源协议
GPL-v3
https://zhuanlan.zhihu.com/p/608456168