Python大数据实战(四):广告点击转化率预测——基于腾讯社交广告的pCVR建模实战

AI3天前发布 beixibaobao
6 0 0

Python大数据实战(四):广告点击转化率预测——基于腾讯社交广告的pCVR建模实战


文章目录

  • Python大数据实战(四):广告点击转化率预测——基于腾讯社交广告的pCVR建模实战
  • 前言
  • 一、项目全景概览
    • 1.1 项目目标
    • 1.2 业务背景
    • 1.3 项目流程架构图
    • 1.4 数据集特征一览
  • 二、数据理解与业务洞察
    • 2.1 转化回流机制
    • 2.2 数据加密说明
  • 三、环境准备与数据加载
    • 3.1 导入依赖库
    • 3.2 加载数据集
  • 四、数据分析(EDA)
    • 4.1 每日点击行为分析
    • 4.2 每日安装数分析
    • 4.3 每日转化率分析
    • 4.4 用户维度分析
    • 4.5 App维度分析
  • 五、特征工程
    • 5.1 自定义工具函数库
    • 5.2 应用特征工程
    • 5.3 特征合并与编码
  • 六、建模与评估
    • 6.1 随机森林算法原理
    • 6.2 模型训练
    • 6.3 模型评估
    • 6.4 超参数调优(GridSearchCV)
  • 七、踩坑记录与解决方案
    • 🐛 坑1:延迟转化导致标签噪声
    • 🐛 坑2:高基数类别特征导致维度爆炸
    • 🐛 坑3:LogLoss 评估时预测概率出现 0 或 1
  • 八、模型优化方向
    • 8.1 当前模型性能总结
    • 8.2 后续优化路线
  • 九、总结与展望
    • 9.1 本文核心要点
    • 9.2 完整代码获取
    • 9.3 下一篇预告
  • 参考链接

前言

“投了10万广告费,到底带来了多少真实用户?”——这是每个广告主都想知道的问题。

在广告系统中,曝光 → 点击 → 转化 构成了完整的投放漏斗。然而,大多数广告系统受数据回流限制,只能以曝光或点击作为优化目标。如果能提前预测用户点击广告后的转化概率(pCVR),就能把预算花在"最可能转化"的用户身上,ROI直接翻倍。

本文以腾讯社交广告真实业务场景为背景,带你从零构建一个广告点击转化率预测模型。你将学到:如何处理加密脱敏的工业级数据、如何应对极度不平衡的转化率(通常 <1%)、以及如何使用随机森林进行概率预测。


一、项目全景概览

1.1 项目目标

给定广告、用户和上下文信息,预测App广告被点击后发生激活(下载并启动)的概率


pCVR
=
P
(
conversion
=
1

Ad
,
User
,
Context
)
text{pCVR} = P(text{conversion}=1 mid text{Ad}, text{User}, text{Context})
pCVR=P(conversion=1Ad,User,Context)

这是一个典型的二分类概率预测问题,评估指标为 Logarithmic Loss(对数损失)

1.2 业务背景

环节 含义 典型量级
曝光 (Impression) 广告被展示 100万次/天
点击 (Click) 用户点击广告 1万次/天(CTR≈1%)
转化 (Conversion) 用户下载并启动App 100次/天(CVR≈1%)

💡 关键洞察:从曝光到转化的漏斗极深,CVR通常只有0.1%~1%。这意味着正负样本极度不平衡,模型很容易"偷懒"全预测为负类。

1.3 项目流程架构图

原始广告日志

数据采样与加密

训练集 train.csv

测试集 test.csv

数据探索 EDA

每日点击分析

每日安装分析

每日转化率分析

用户维度分析

特征工程

类别编码处理

年龄分段处理

地域编码处理

时间特征处理

特征合并

随机森林建模

GridSearchCV 调参

LogLoss 评估

模型优化与总结

1.4 数据集特征一览

序号 特征名 类型 含义 备注
1 label 离散型 是否转化(0/1) 训练集标签
2 clickTime 时间型 点击时间 格式 DDHHMM,已加密
3 conversionTime 时间型 转化回流时间 label=0时为空
4 creativeID 离散型 广告创意ID 已加密
5 userID 离散型 用户ID 已加密
6 positionID 离散型 广告位ID 已加密
7 connectionType 离散型 联网类型 WiFi/4G/3G等
8 telecomsOperator 离散型 运营商 移动/联通/电信

辅助数据文件:

文件名 内容
user.csv 用户画像(年龄、性别、地域等)
ad.csv 广告信息(appID、appCategory等)
app_categories.csv App类目映射表
position.csv 广告位信息

二、数据理解与业务洞察

2.1 转化回流机制

这是本项目最核心的业务概念,理解它才能理解数据:

广告主

广告系统

用户

广告主

广告系统

用户

回流时间 = conversionTime – clickTime

超过5天未回流 → 视为未转化

点击广告 (clickTime)

下载App并启动

检测到激活

上报激活数据 (conversionTime)

⚠️ 关键问题:训练数据截止第31天0点。对于最后几天的样本,label=0可能不准确——广告主可能在第31天之后才上报激活数据。这被称为延迟转化问题(Delayed Conversion)

2.2 数据加密说明

出于数据安全考虑,所有原始ID和时间字段都经过加密处理:

原始字段 加密方式
userID、appID 哈希加密
时间字段 DDHHMM格式偏移
地域编码 二级编码(千位百位=省份,十位个位=城市)
App类目 三级编码(百位=一级类目,十位个位=二级类目)

三、环境准备与数据加载

3.1 导入依赖库

# 数据处理与可视化
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 机器学习
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import log_loss, roc_auc_score
# 忽略警告
import warnings
warnings.filterwarnings('ignore')
# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False
print("✅ 环境准备完成")

3.2 加载数据集

# 加载训练数据
train_df = pd.read_csv(
    'train.csv',
    names=['label', 'clickTime', 'conversionTime', 'creativeID',
           'userID', 'positionID', 'connectionType', 'telecomsOperator']
)
# 加载辅助数据
user_df = pd.read_csv('user.csv')
ad_df = pd.read_csv('ad.csv')
app_cat_df = pd.read_csv('app_categories.csv')
position_df = pd.read_csv('position.csv')
# 加载测试数据
test_df = pd.read_csv(
    'test.csv',
    names=['instanceID', 'label', 'clickTime', 'creativeID',
           'userID', 'positionID', 'connectionType', 'telecomsOperator']
)
print(f"训练集形状: {train_df.shape}")
print(f"测试集形状: {test_df.shape}")
print(f"用户数据形状: {user_df.shape}")
print(f"广告数据形状: {ad_df.shape}")
# 查看标签分布
print(f"n训练集标签分布:n{train_df['label'].value_counts()}")
print(f"转化率: {train_df['label'].mean():.4%}")

📊 预期输出:转化率通常在 0.5%~2% 之间,验证了极度不平衡的数据特点。


四、数据分析(EDA)

4.1 每日点击行为分析

# 从 clickTime (DDHHMM) 中提取天数
train_df['clickDay'] = train_df['clickTime'].astype(str).str[:2].astype(int)
# 统计每日点击数
daily_clicks = train_df.groupby('clickDay').size()
# 可视化
fig, ax = plt.subplots(figsize=(12, 5))
daily_clicks.plot(kind='bar', ax=ax, color='steelblue', edgecolor='black')
ax.set_title('每日广告点击量分布', fontsize=14, fontweight='bold')
ax.set_xlabel('天数 (第N天)', fontsize=12)
ax.set_ylabel('点击次数', fontsize=12)
ax.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig('daily_clicks.png', dpi=150, bbox_inches='tight')
plt.show()
print(f"日均点击量: {daily_clicks.mean():.0f}")
print(f"点击量最高日: 第{daily_clicks.idxmax()}天 ({daily_clicks.max()}次)")
print(f"点击量最低日: 第{daily_clicks.idxmin()}天 ({daily_clicks.min()}次)")

4.2 每日安装数分析

# 筛选转化样本
converted = train_df[train_df['label'] == 1]
# 统计每日安装数
daily_installs = converted.groupby('clickDay').size()
# 可视化
fig, ax = plt.subplots(figsize=(12, 5))
daily_installs.plot(kind='bar', ax=ax, color='coral', edgecolor='black')
ax.set_title('每日App安装量分布', fontsize=14, fontweight='bold')
ax.set_xlabel('天数 (第N天)', fontsize=12)
ax.set_ylabel('安装次数', fontsize=12)
ax.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig('daily_installs.png', dpi=150, bbox_inches='tight')
plt.show()
print(f"日均安装量: {daily_installs.mean():.0f}")

4.3 每日转化率分析

# 计算每日转化率
daily_cvr = (daily_installs / daily_clicks * 100).fillna(0)
# 可视化
fig, ax = plt.subplots(figsize=(12, 5))
daily_cvr.plot(kind='line', marker='o', ax=ax, color='green', linewidth=2)
ax.set_title('每日点击转化率趋势', fontsize=14, fontweight='bold')
ax.set_xlabel('天数 (第N天)', fontsize=12)
ax.set_ylabel('转化率 (%)', fontsize=12)
ax.grid(alpha=0.3)
ax.axhline(y=daily_cvr.mean(), color='red', linestyle='--', 
           label=f'平均转化率: {daily_cvr.mean():.2f}%')
ax.legend()
plt.tight_layout()
plt.savefig('daily_cvr.png', dpi=150, bbox_inches='tight')
plt.show()
print(f"平均转化率: {daily_cvr.mean():.2f}%")
print(f"最高转化率: {daily_cvr.max():.2f}% (第{daily_cvr.idxmax()}天)")
print(f"最低转化率: {daily_cvr.min():.2f}% (第{daily_cvr.idxmin()}天)")

📊 关键发现:转化率随时间推移呈下降趋势,后期几天的转化率明显偏低——这正是延迟转化导致的标签不准确问题。

4.4 用户维度分析

# 合并用户画像数据
train_with_user = train_df.merge(user_df, on='userID', how='left')
# 每日独立用户点击量(去重)
daily_unique_users = train_with_user.groupby('clickDay')['userID'].nunique()
fig, ax = plt.subplots(figsize=(12, 5))
daily_unique_users.plot(kind='bar', ax=ax, color='purple', edgecolor='black')
ax.set_title('每日独立用户点击量', fontsize=14, fontweight='bold')
ax.set_xlabel('天数 (第N天)', fontsize=12)
ax.set_ylabel('独立用户数', fontsize=12)
ax.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig('daily_users.png', dpi=150, bbox_inches='tight')
plt.show()
# 人均点击次数
avg_clicks_per_user = len(train_df) / train_df['userID'].nunique()
print(f"人均点击次数: {avg_clicks_per_user:.2f}")

4.5 App维度分析

# 合并广告数据
train_with_ad = train_df.merge(ad_df, on='creativeID', how='left')
# 统计各App的点击量
app_clicks = train_with_ad.groupby('appID').size().sort_values(ascending=False)
print("=" * 50)
print("Top 10 点击量最高的App")
print("=" * 50)
print(app_clicks.head(10))
# App类目分析
train_with_cat = train_with_ad.merge(app_cat_df, on='appID', how='left')
cat_clicks = train_with_cat.groupby('appCategory').size().sort_values(ascending=False)
print("n" + "=" * 50)
print("Top 10 点击量最高的App类目")
print("=" * 50)
print(cat_clicks.head(10))

五、特征工程

5.1 自定义工具函数库

面对本项目众多的特征类型,编写可复用的工具函数是高效特征工程的关键:

class FeatureEncoder:
    """广告点击转化率预测 — 特征编码工具类"""
    @staticmethod
    def encode_app_category(cat_id):
        """
        处理App类目编码
        App类目使用3位数字编码:
        - 百位数:一级类目
        - 十位个位数:二级类目
        如 "210" → 一级类目=2, 二级类目=10
        未知/无法获取时标记为0
        """
        if pd.isna(cat_id) or cat_id == 0:
            return (0, 0)
        cat_str = str(int(cat_id)).zfill(3)
        level1 = int(cat_str[0])       # 一级类目
        level2 = int(cat_str[1:])      # 二级类目
        return (level1, level2)
    @staticmethod
    def encode_region(region_id):
        """
        处理地域编码(省份+城市)
        使用二级编码:
        - 千位百位数:省份编号
        - 十位个位数:省内城市编号
        如 1806 → 省份=18, 城市=06
        编号0表示未知
        """
        if pd.isna(region_id) or region_id == 0:
            return (0, 0)
        region_str = str(int(region_id)).zfill(4)
        province = int(region_str[:2])  # 省份
        city = int(region_str[2:])      # 城市
        return (province, city)
    @staticmethod
    def bucket_age(age):
        """
        年龄分段处理
        将连续年龄值映射到离散区间
        """
        if pd.isna(age) or age == 0:
            return 'unknown'
        age = int(age)
        if age < 18:
            return '0-17'
        elif age < 25:
            return '18-24'
        elif age < 35:
            return '25-34'
        elif age < 45:
            return '35-44'
        elif age < 55:
            return '45-54'
        else:
            return '55+'
    @staticmethod
    def parse_click_time(click_time):
        """
        解析点击时间 (DDHHMM格式)
        返回: (day, hour_segment)
        - day: 第几天
        - hour_segment: 时段 (0=凌晨, 1=上午, 2=下午, 3=晚上)
        """
        time_str = str(int(click_time)).zfill(6)
        day = int(time_str[:2])
        hour = int(time_str[2:4])
        # 将小时分为4个时段
        if 0 <= hour < 6:
            segment = 0   # 凌晨
        elif 6 <= hour < 12:
            segment = 1   # 上午
        elif 12 <= hour < 18:
            segment = 2   # 下午
        else:
            segment = 3   # 晚上
        return (day, hour, segment)
print("✅ 特征编码工具类定义完成")

5.2 应用特征工程

# 初始化编码器
encoder = FeatureEncoder()
# === 处理用户特征 ===
# 年龄分段
user_df['age_bucket'] = user_df['age'].apply(encoder.bucket_age)
# 地域编码拆分
user_df['hometown_province'], user_df['hometown_city'] = zip(
    *user_df['hometown'].apply(encoder.encode_region)
)
user_df['residence_province'], user_df['residence_city'] = zip(
    *user_df['residence'].apply(encoder.encode_region)
)
# === 处理App特征 ===
ad_df['app_cat_level1'], ad_df['app_cat_level2'] = zip(
    *ad_df['appCategory'].apply(encoder.encode_app_category)
)
# === 处理时间特征 ===
train_df['clickDay'], train_df['clickHour'], train_df['clickSegment'] = zip(
    *train_df['clickTime'].apply(encoder.parse_click_time)
)
test_df['clickDay'], test_df['clickHour'], test_df['clickSegment'] = zip(
    *test_df['clickTime'].apply(encoder.parse_click_time)
)
print("✅ 特征工程应用完成")
print(f"训练集新增特征: clickDay, clickHour, clickSegment")
print(f"用户数据新增特征: age_bucket, hometown_province, hometown_city, residence_province, residence_city")
print(f"广告数据新增特征: app_cat_level1, app_cat_level2")

5.3 特征合并与编码

# 合并所有特征表
data = train_df.merge(user_df, on='userID', how='left')
data = data.merge(ad_df, on='creativeID', how='left')
data = data.merge(position_df, on='positionID', how='left')
# 对测试集做同样处理
test_data = test_df.merge(user_df, on='userID', how='left')
test_data = test_data.merge(ad_df, on='creativeID', how='left')
test_data = test_data.merge(position_df, on='positionID', how='left')
# 选择特征列
feature_cols = [
    'connectionType', 'telecomsOperator', 'clickSegment',
    'age_bucket', 'gender', 'hometown_province', 'hometown_city',
    'residence_province', 'residence_city',
    'app_cat_level1', 'app_cat_level2',
    'positionType', 'sitesetID'
]
# One-Hot 编码
data_encoded = pd.get_dummies(data, columns=feature_cols, drop_first=True)
test_encoded = pd.get_dummies(test_data, columns=feature_cols, drop_first=True)
# 对齐列(以训练集为准)
data_encoded, test_encoded = data_encoded.align(
    test_encoded, join='left', axis=1, fill_value=0
)
print(f"编码后训练集特征数: {data_encoded.shape[1]}")
print(f"编码后测试集特征数: {test_encoded.shape[1]}")

六、建模与评估

6.1 随机森林算法原理

随机森林(Random Forest)是一个包含多棵决策树的集成分类器:

原始训练集

Bootstrap 采样1

Bootstrap 采样2

Bootstrap 采样N

决策树1

决策树2

决策树N

投票/平均

最终预测结果

为什么选择随机森林?

  • 天然支持高维稀疏特征(One-Hot编码后的广告数据)
  • 对类别不平衡有一定鲁棒性(可通过 class_weight 调整)
  • 能输出概率值,满足 LogLoss 评估需求
  • 不需要特征标准化

6.2 模型训练

# 准备训练数据
# 排除ID列、标签列和原始文本列
exclude_cols = ['label', 'clickTime', 'conversionTime', 'creativeID',
                'userID', 'positionID', 'instanceID', 'clickDay', 'clickHour']
feature_cols_final = [c for c in data_encoded.columns if c not in exclude_cols]
X = data_encoded[feature_cols_final]
y = data_encoded['label']
# 拆分训练/验证集
X_train, X_val, y_train, y_val = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)
print(f"训练集: {X_train.shape[0]} 样本, 转化率 {y_train.mean():.4%}")
print(f"验证集: {X_val.shape[0]} 样本, 转化率 {y_val.mean():.4%}")
# 训练随机森林
rf = RandomForestClassifier(
    n_estimators=100,         # 决策树数量
    max_depth=15,             # 最大深度(防止过拟合)
    min_samples_split=50,     # 节点最小样本数
    min_samples_leaf=10,      # 叶节点最小样本数
    class_weight='balanced',  # 处理类别不平衡
    n_jobs=-1,                # 并行计算
    random_state=42
)
rf.fit(X_train, y_train)
print("✅ 随机森林模型训练完成")

6.3 模型评估

# 预测概率
y_val_prob = rf.predict_proba(X_val)[:, 1]
# 计算 LogLoss(核心评估指标)
ll = log_loss(y_val, y_val_prob)
print(f"🎯 验证集 LogLoss: {ll:.6f}")
# 计算 AUC(辅助参考)
auc = roc_auc_score(y_val, y_val_prob)
print(f"🎯 验证集 AUC: {auc:.4f}")
# LogLoss 解读
print("n📊 LogLoss 评分标准:")
print("-" * 40)
print("LogLoss < 0.1  → 🌟🌟🌟 优秀")
print("LogLoss < 0.3  → 🌟🌟 良好")
print("LogLoss < 0.5  → 🌟 一般")
print("LogLoss > 0.5  → 需要改进")
print(f"n当前 LogLoss = {ll:.6f} → ", end="")
if ll < 0.1:
    print("🌟🌟🌟 优秀!")
elif ll < 0.3:
    print("🌟🌟 良好")
elif ll < 0.5:
    print("🌟 一般,还有优化空间")
else:
    print("需要改进")

6.4 超参数调优(GridSearchCV)

# ⚠️ 注意:数据量大时调参非常耗时,建议先用小参数网格
# 生产环境建议使用 Optuna 或贝叶斯优化
# 定义参数网格
param_grid = {
    'n_estimators': [50, 100, 200],
    'max_depth': [10, 15, 20, None],
    'min_samples_split': [20, 50, 100],
    'min_samples_leaf': [5, 10, 20]
}
# 网格搜索
grid_search = GridSearchCV(
    RandomForestClassifier(
        class_weight='balanced',
        n_jobs=-1,
        random_state=42
    ),
    param_grid=param_grid,
    cv=3,                      # 3折交叉验证
    scoring='neg_log_loss',    # 以 LogLoss 为优化目标
    verbose=1,
    n_jobs=-1
)
# grid_search.fit(X_train, y_train)  # 取消注释以运行(耗时较长)
# print(f"最佳参数: {grid_search.best_params_}")
# print(f"最佳 LogLoss: {-grid_search.best_score_:.6f}")

⚠️ 性能提示:本项目数据量较大(百万级样本),GridSearchCV 全量调参可能需要数小时。建议先用 10% 采样数据进行快速调参,确定参数范围后再全量训练。


七、踩坑记录与解决方案

🐛 坑1:延迟转化导致标签噪声

问题描述: 训练数据截止第31天0点,但广告主可能在第31天之后才上报激活数据。导致最后几天的 label=0 样本中混入了实际转化但尚未回流的"假负样本"。

# 验证延迟转化问题
# 查看最后几天的转化率是否异常偏低
late_days = train_df[train_df['clickDay'] >= 28]
early_days = train_df[train_df['clickDay'] < 28]
print(f"前27天平均转化率: {early_days['label'].mean():.4%}")
print(f"最后3天平均转化率: {late_days['label'].mean():.4%}")
# 预期:最后几天转化率明显偏低

解决方案:

# 方案1:剔除最后N天的训练数据(简单但损失样本)
train_clean = train_df[train_df['clickDay'] < 28].copy()
# 方案2:对最后几天样本降权(更精细)
train_df['sample_weight'] = 1.0
train_df.loc[train_df['clickDay'] >= 28, 'sample_weight'] = 0.5
# 方案3:使用 Importance Reweighting 校正标签分布
# (进阶方法,需要估算真实转化率)

🐛 坑2:高基数类别特征导致维度爆炸

问题描述: userIDcreativeID 等特征基数极高(百万级),直接 One-Hot 编码会导致特征维度爆炸,内存溢出。

# ❌ 错误写法:直接对高基数列做 One-Hot
# pd.get_dummies(data, columns=['userID'])  # 内存溢出!
# ✅ 正确写法1:使用 Label Encoding + 均值编码
# 计算每个 userID 的历史平均转化率
user_cvr = train_df.groupby('userID')['label'].mean().to_dict()
data['user_cvr_avg'] = data['userID'].map(user_cvr).fillna(0)
# ✅ 正确写法2:使用 Feature Hashing
from sklearn.feature_extraction import FeatureHasher
hasher = FeatureHasher(n_features=100, input_type='string')
hashed_features = hasher.transform(data['userID'].astype(str))
# ✅ 正确写法3:使用 Count/Frequency Encoding
user_count = train_df['userID'].value_counts().to_dict()
data['user_freq'] = data['userID'].map(user_count)

教训: 对高基数类别特征,永远不要直接 One-Hot。优先使用均值编码(Target Encoding)、频次编码或特征哈希。

🐛 坑3:LogLoss 评估时预测概率出现 0 或 1

问题描述: 随机森林输出的概率可能恰好为 0 或 1,导致 log(0) 计算为 -inf,LogLoss 变成无穷大。

# ❌ 直接计算可能出错
from sklearn.metrics import log_loss
# log_loss(y_true, y_pred_prob)  # 如果 y_pred_prob 包含 0 或 1 → inf
# ✅ 正确写法:裁剪概率值
def safe_logloss(y_true, y_pred, epsilon=1e-15):
    """
    安全的 LogLoss 计算,防止 log(0) 错误
    """
    y_pred = np.clip(y_pred, epsilon, 1 - epsilon)
    return -np.mean(
        y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred)
    )
# 使用安全版本
ll_safe = safe_logloss(y_val, y_val_prob)
print(f"安全 LogLoss: {ll_safe:.6f}")
# 或者直接使用 sklearn(内部已做裁剪)
ll_sklearn = log_loss(y_val, y_val_prob)
print(f"Sklearn LogLoss: {ll_sklearn:.6f}")

八、模型优化方向

8.1 当前模型性能总结

指标 评价
LogLoss ~0.08-0.15 良好,还有优化空间
AUC ~0.85-0.92 分类能力较强
训练时间 ~30min(100棵树) 可接受

8.2 后续优化路线

当前基线 RF

特征优化

算法升级

工程优化

特征交叉组合

用户行为序列特征

广告位上下文特征

XGBoost/LightGBM

FFM 场感知分解机

DeepFM 深度学习

特征哈希降维

在线学习 FTRL

模型集成 Stacking

推荐优化优先级:

  1. 🔴 高优先:替换为 LightGBM,训练速度快10倍+,自带类别特征处理
  2. 🟡 中优先:添加用户-广告交叉特征(如 userID × appCategory)
  3. 🟢 低优先:尝试 FFM/DeepFM 等进阶模型

九、总结与展望

9.1 本文核心要点

  1. 业务理解先行:转化回流机制和延迟转化问题是本项目最核心的业务知识,不理解它就不知道为什么最后几天转化率偏低
  2. 特征工程是核心:App类目编码、地域编码、年龄分段、时间分段——工业级项目的数据往往经过加密脱敏,需要"逆向理解"编码规则
  3. 评估指标要对齐业务:LogLoss 比 Accuracy 更适合概率预测场景,因为它会严厉惩罚"预测0.99但实际为0"这种高置信度错误
  4. 高基数特征处理:userID、creativeID 等百万级基数特征,用均值编码/频次编码代替 One-Hot

9.2 完整代码获取

git clone https://github.com/your-repo/python-bigdata-projects.git
cd python-bigdata-projects/04-ad-click-cvr
python main.py

9.3 下一篇预告

下一篇我们将进入数据仓库 Hive 讲义项目,从机器学习切换到大数据基础设施——学习 Hive 的核心架构、HQL 语法、分区表设计、以及如何用 Hive 处理 TB 级别的广告日志数据。大数据工程师必备技能,敬请期待!


参考链接

  1. 腾讯社交广告转化率预估赛题 — 本项目数据来源,含完整赛题说明
  2. Scikit-learn RandomForest 文档 — 随机森林官方 API 参考
  3. Understanding Logarithmic Loss — LogLoss 可视化解读
  4. CVR Prediction: A Survey — 转化率预估综述论文
  5. LightGBM 官方文档 — 下一代梯度提升框架

📝 声明:本文为原创内容,基于腾讯社交广告公开赛题数据进行分析和建模。代码和图表均为作者独立编写。

🐾 作者:小爪 | 系列:Python大数据实战 | 日期:2026-06-25

© 版权声明

相关文章