基于机器学习的电商优惠券核销预测

news2024/9/17 7:12:06

1. 项目简介

        随着移动互联网的快速发展,O2O(Online to Offline)模式已成为电商领域的一大亮点。优惠券作为一种有效的营销工具,被广泛应用于吸引新客户和激活老用户。然而,传统的随机投放方式往往效率低下,不仅对用户造成干扰,还可能损害品牌形象。因此,个性化优惠券投放成为提高营销效果的关键。本文将详细介绍如何利用机器学习技术进行电商优惠券使用预测,以实现优惠券的精准投放。

2. 数据准备

2.1 数据来源与收集

本研究使用的数据集包括线下和线上两个部分。线下数据集包含用户ID、商户ID、优惠券ID、折扣率、距离、领券日期和消费日期等信息。线上数据集则包含用户ID、商户ID、行为类型、优惠券ID、折扣率、领券日期和消费日期等信息。

2.2 数据预处理

数据预处理是机器学习中的关键步骤。首先,我们需要处理缺失值,例如将字符串类型的缺失值替换为np.nan。其次,对于异常值,如距离字段中的null值,我们将其替换为-1,并转换为整数类型。最后,我们需要对数据类型进行转换,确保所有数值字段都是正确的数据类型。

# 处理缺失值和异常值
t2.replace('null', -1, inplace=True)
t2.distance = t2.distance.astype('int')
t2.replace(-1, np.nan, inplace=True)

3. 特征工程

特征工程是机器学习中提高模型性能的重要环节。我们从以下几个方面构建特征:

3.1 优惠券相关特征

  • 优惠券类型(直接优惠为0,满减为1)
  • 优惠券折率
  • 满减优惠券的最低消费
  • 历史出现次数
  • 历史核销次数
  • 历史核销率
  • 历史核销时间率
  • 领取优惠券是一周的第几天
  • 领取优惠券是一月的第几天
  • 历史上用户领取该优惠券次数
  • 历史上用户消费该优惠券次数
  • 历史上用户对该优惠券的核销率
def get_coupon_related_feature(dataset3, filename='coupon3_feature'):
    # 计算折扣率函数
    def calc_discount_rate(s):
        s = str(s)
        s = s.split(':')
        if len(s) == 1:
            return float(s[0])
        else:
            return 1.0 - float(s[1]) / float(s[0])

    # 提取满减优惠券中,满对应的金额
    def get_discount_man(s):
        s = str(s)
        s = s.split(':')
        if len(s) == 1:
            return 'null'
        else:
            return int(s[0])

    # 提取满减优惠券中,减对应的金额
    def get_discount_jian(s):
        s = str(s)
        s = s.split(':')
        if len(s) == 1:
            return 'null'
        else:
            return int(s[1])

    # 是不是满减卷
    def is_man_jian(s):
        s = str(s)
        s = s.split(':')
        if len(s) == 1:
            return 0
        else:
            return 1.0

    # 周几领取的优惠券
    dataset3['day_of_week'] = dataset3.date_received.astype('str').apply(
        lambda x: date(int(x[0:4]), int(x[4:6]), int(x[6:8])).weekday() + 1)

    # 每月的第几天领取的优惠券
    dataset3['day_of_month'] = dataset3.date_received.astype('str').apply(
        lambda x: int(x[6:8]))

    # 领取优惠券的时间与当月初距离多少天
    dataset3['days_distance'] = dataset3.date_received.astype('str').apply(
        lambda x: (date(int(x[0:4]), int(x[4:6]), int(x[6:8])) - date(2016, 6, 30)).days)

    # 满减优惠券中,满对应的金额
    dataset3['discount_man'] = dataset3.discount_rate.apply(get_discount_man)

    # 满减优惠券中,减对应的金额
    dataset3['discount_jian'] = dataset3.discount_rate.apply(get_discount_jian)

    # 优惠券是不是满减卷
    dataset3['is_man_jian'] = dataset3.discount_rate.apply(is_man_jian)

    # 优惠券的折扣率(满减卷进行折扣率转换)
    dataset3['discount_rate'] = dataset3.discount_rate.apply(calc_discount_rate)

    # 特定优惠券的总数量
    d = dataset3[['coupon_id']]
    d['coupon_count'] = 1
    d = d.groupby('coupon_id').agg('sum').reset_index()
    dataset3 = pd.merge(dataset3, d, on='coupon_id', how='left')

    dataset3.to_csv(os.path.join('features', filename + '.csv'), index=None)
    return dataset3

3.2 商户相关特征

  • 商家优惠券被领取次数
  • 商家优惠券被领取后不核销次数
  • 商家优惠券被领取后核销次数
  • 商家优惠券被领取后核销率
  • 商家优惠券核销的平均/最小/最大消费折率
  • 核销商家优惠券的不同用户数量,及其占领取不同的用户比重
  • 商家优惠券平均每个用户核销多少张
  • 商家被核销过的不同优惠券数量
  • 商家被核销过的不同优惠券数量占所有领取过的不同优惠券数量的比重
  • 商家平均每种优惠券核销多少张
  • 商家被核销优惠券的平均时间率
  • 商家被核销优惠券中的平均/最小/最大用户-商家距离
def get_merchant_related_feature(feature3, filename='merchant3_feature'):
    merchant3 = feature3[['merchant_id', 'coupon_id', 'distance', 'date_received', 'date']]

    # 提取不重复的商户集合
    t = merchant3[['merchant_id']]
    t.drop_duplicates(inplace=True)

    # 商户的总销售次数
    t1 = merchant3[merchant3.date != 'null'][['merchant_id']]
    t1['total_sales'] = 1
    t1 = t1.groupby('merchant_id').agg('sum').reset_index()

    # 商户被核销优惠券的销售次数
    t2 = merchant3[(merchant3.date != 'null') & (merchant3.coupon_id != 'null')][['merchant_id']]
    t2['sales_use_coupon'] = 1
    t2 = t2.groupby('merchant_id').agg('sum').reset_index()

    # 商户发行优惠券的总数
    t3 = merchant3[merchant3.coupon_id != 'null'][['merchant_id']]
    t3['total_coupon'] = 1
    t3 = t3.groupby('merchant_id').agg('sum').reset_index()

    # 商户被核销优惠券的用户-商户距离,转化为int数值类型
    t4 = merchant3[(merchant3.date != 'null') & (merchant3.coupon_id != 'null')][['merchant_id', 'distance']]
    t4.replace('null', -1, inplace=True)
    t4.distance = t4.distance.astype('int')
    t4.replace(-1, np.nan, inplace=True)

    # 商户被核销优惠券的最小用户-商户距离
    t5 = t4.groupby('merchant_id').agg('min').reset_index()
    t5.rename(columns={'distance': 'merchant_min_distance'}, inplace=True)

    # 商户被核销优惠券的最大用户-商户距离
    t6 = t4.groupby('merchant_id').agg('max').reset_index()
    t6.rename(columns={'distance': 'merchant_max_distance'}, inplace=True)

    # 商户被核销优惠券的平均用户-商户距离
    t7 = t4.groupby('merchant_id').agg('mean').reset_index()
    t7.rename(columns={'distance': 'merchant_mean_distance'}, inplace=True)

    # 商户被核销优惠券的用户-商户距离的中位数
    t8 = t4.groupby('merchant_id').agg('median').reset_index()
    t8.rename(columns={'distance': 'merchant_median_distance'}, inplace=True)

    # 合并上述特征
    merchant3_feature = pd.merge(t, t1, on='merchant_id', how='left')
    merchant3_feature = pd.merge(merchant3_feature, t2, on='merchant_id', how='left')
    merchant3_feature = pd.merge(merchant3_feature, t3, on='merchant_id', how='left')
    merchant3_feature = pd.merge(merchant3_feature, t5, on='merchant_id', how='left')
    merchant3_feature = pd.merge(merchant3_feature, t6, on='merchant_id', how='left')
    merchant3_feature = pd.merge(merchant3_feature, t7, on='merchant_id', how='left')
    merchant3_feature = pd.merge(merchant3_feature

4. 数据集可视化分析

4.1 预测标签的类别分布

        可以看出,标签为 1 的占比非常少,是一个类别极度不均衡的二分类问题。

4.2 特征相关性分析

4.3 商户的总销售次数分布情况

 

4.4  领取优惠券的时间与当月初距离天数分布

        由于特征太多篇幅有限,此处只列出部分特征的分布可视化。 

5. 训练集和验证集切分

        由于比赛已结束,所以此处将手动切分出训练集、验证集、测试集,测试集用于不同模型的性能对比。

df_columns = dataset12_x.columns.values
print('===> feature count: {}'.format(len(df_columns)))

X_train, X_valid, y_train, y_valid = train_test_split(dataset12_x, dataset12_y, test_size=0.1, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X_train, y_train, test_size=0.1, random_state=42)
print('train: {}, valid: {}, test: {}'.format(X_train.shape[0], X_valid.shape[0], X_test.shape[0]))
===> feature count: 53
train: 327856, valid: 40477, test: 36429

6. Xgboost 建模预测

        Xgboost是一种高效的梯度提升框架,它可以用来解决分类、回归等多种机器学习任务。Xgboost通过集成多个弱学习器(通常是决策树),并优化损失函数来提高模型的准确性。

xgb_params = {
    'eta': 0.01,
    'min_child_weight': 20,
    'colsample_bytree': 0.5,
    'max_depth': 15,
    'subsample': 0.9,
    'lambda': 2.0,
    'eval_metric': 'auc',
    'objective': 'binary:logistic',
    'nthread': -1,
    'silent': 1,
    'booster': 'gbtree'
}

pre_xgb_model = xgb.train(dict(xgb_params),
                      dtrain,
                      evals=watchlist,
                      verbose_eval=50)

        交叉验证获取最佳迭代次数:

print('---> cv train to choose best_num_boost_round')
cv_result = xgb.cv(dict(xgb_params),
                   dtrain,
                   num_boost_round=5000,
                   early_stopping_rounds=100,
                   verbose_eval=100,
                   show_stdv=False,
                   )
best_num_boost_rounds = len(cv_result)
mean_train_logloss = cv_result.loc[best_num_boost_rounds-11 : best_num_boost_rounds-1, 'train-auc-mean'].mean()
mean_test_logloss = cv_result.loc[best_num_boost_rounds-11 : best_num_boost_rounds-1, 'test-auc-mean'].mean()
print('best_num_boost_rounds = {}'.format(best_num_boost_rounds))

print('mean_train_auc = {:.7f} , mean_test_auc = {:.7f}\n'.format(mean_train_logloss, mean_test_logloss))
[0]	train-auc:0.87954	test-auc:0.87309
[100]	train-auc:0.90277	test-auc:0.89217
[200]	train-auc:0.90981	test-auc:0.89533
[300]	train-auc:0.91590	test-auc:0.89786
[400]	train-auc:0.92089	test-auc:0.89978
[500]	train-auc:0.92522	test-auc:0.90138
[600]	train-auc:0.92873	test-auc:0.90252
[700]	train-auc:0.93169	test-auc:0.90334
[800]	train-auc:0.93411	test-auc:0.90396
[900]	train-auc:0.93610	test-auc:0.90444
[1000]	train-auc:0.93786	test-auc:0.90482
[1100]	train-auc:0.93937	test-auc:0.90512
[1200]	train-auc:0.94078	test-auc:0.90540
[1300]	train-auc:0.94218	test-auc:0.90564
[1400]	train-auc:0.94347	test-auc:0.90583
[1500]	train-auc:0.94468	test-auc:0.90595
[1600]	train-auc:0.94578	test-auc:0.90607
[1700]	train-auc:0.94686	test-auc:0.90616
[1800]	train-auc:0.94787	test-auc:0.90626
[1900]	train-auc:0.94886	test-auc:0.90632
[2000]	train-auc:0.94986	test-auc:0.90636

6.1 特征重要程度分析

6.2 性能评估

# predict train
predict_train = xgb_model.predict(dtrain)
after_xgb_train_auc = evaluate_score(predict_train, y_train)

# predict validate
predict_valid = xgb_model.predict(dvalid)
after_xgb_valid_auc = evaluate_score(predict_valid, y_valid)

dtest = xgb.DMatrix(X_test, feature_names=df_columns)
predict_test = xgb_model.predict(dtest)
after_xgb_test_auc = evaluate_score(predict_test, y_test)

print('训练集 auc = {:.7f} , 验证集 auc = {:.7f} , 测试集 auc = {:.7f}\n'.format(
    after_xgb_train_auc, after_xgb_valid_auc, after_xgb_test_auc))

 训练集 auc = 0.9042264 , 验证集 auc = 0.8958611 , 测试集 auc = 0.8960916

6.3 调参前后模型性能对比

        可以看出,调参后,训练集、验证集和测试集的 AUC 都得到了不同程度的提升、

6.4 预测性能 ROC 曲线

7. 随机森林(RandomForest)建模预测

        随机森林是一种集成学习方法,它通过构建多个决策树并将它们的预测结果进行汇总来提高整体模型的性能。随机森林在处理高维数据时表现出色,并且对于过拟合具有一定的抵抗力。

        用RandomSearch+CV选取超参数:

# 建立一个分类器或者回归器
rf_clf = RandomForestClassifier()

# 给定参数搜索范围:list or distribution
param_dist = {
    "n_estimators": [100, 500, 1000, 1500, 2000],
    "max_depth": [3, 5, 8, 12, 15],
    "max_features": [2, 5, 10,],
    "min_samples_split": [2, 4, 6, 8, 10, 12],
    "bootstrap": [True, False],
    "criterion": ["gini", "entropy"],
}

n_iter_search = 20
random_search_cv = RandomizedSearchCV(rf_clf, param_distributions=param_dist, n_iter=n_iter_search, cv=5, n_jobs=-1, verbose=1)

        最佳参数训练 RF 模型:

rf_model = RandomForestClassifier(
    n_estimators=3000, criterion='gini', max_depth=12, 
    min_samples_split=1000, min_samples_leaf=6, min_weight_fraction_leaf=0.0, 
    max_features='sqrt', max_leaf_nodes=None, min_impurity_decrease=0.0, 
    bootstrap=True, n_jobs=-1, random_state=42, 
    verbose=1, warm_start=False, 
    max_samples=None
)

 

训练集 auc = 0.6242629 , 验证集 auc = 0.6232508 , 测试集 auc = 0.6194697

8. Stochastic Gradient Descent(SGD算法)

        SGD是一种优化算法,它通过随机选择样本来更新模型参数,从而减少计算量并加快收敛速度。SGD适用于大规模和在线机器学习任务。

        同样的方法,测试 SGD 算法建模预测性能,此处省略。

9. 模型对比

import matplotlib.pyplot as plt
import numpy as np

species = ['训练集', '验证集', '测试集']
penguin_means = {
    'Xgboost': (xgb_train_auc, xgb_valid_auc, xgb_test_auc),
    'RandomForest': (rf_train_auc, rf_valid_auc, rf_test_auc),
    'SGD': (sgd_train_auc, sgd_valid_auc, sgd_test_auc),
}
xgb_train_auc
x = np.arange(len(species))
width = 0.25
multiplier = 0

plt.figure(figsize=(40, 20))
fig, ax = plt.subplots(layout='constrained', figsize=(30, 15))

for attribute, measurement in penguin_means.items():
    offset = width * multiplier
    rects = ax.bar(x + offset, measurement, width, label=attribute)
    ax.bar_label(rects, padding=3, fontsize=26)
    multiplier += 1

ax.set_ylabel('数据集', fontsize=26)
ax.set_title('不同模型的评测性能对比', fontsize=40)
ax.set_xticks(x + width, species, fontsize=26)
ax.legend(loc='upper left', fontsize=26)
ax.set_ylim(0, 1.5)

plt.show()

        我们比较了Xgboost、随机森林和SGD三种模型的性能。结果显示,Xgboost模型在训练集、验证集和测试集上的AUC值均高于其他两种模型。

10. 结论

        通过对用户行为和优惠券使用情况的分析,我们构建了一个基于机器学习的优惠券使用预测模型。该模型能够有效地预测用户是否会核销他们收到的优惠券,从而帮助企业更精准地进行营销活动。未来的工作可以进一步优化特征选择、调整模型参数,或者尝试其他类型的机器学习算法以提升预测准确性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2116260.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaWeb【day11】--(SpringBootWeb案例)

SpringBootWeb案例 前面我们已经实现了员工信息的条件分页查询以及删除操作。 关于员工管理的功能,还有两个需要实现: 新增员工 修改员工 首先我们先完成"新增员工"的功能开发,再完成"修改员工"的功能开发。而在&quo…

万能视频下载器-下载所有网站上的任何视频

万能视频下载器-下载所有网站上的任何视频 在Edge浏览器中发现了一款令人惊叹的视频下载扩展插件,简直就是视觉盛宴的利器!只需轻点几下,在拓展商店中轻松查找并安装,你便能随时随地随心所欲地把心仪的视频收入囊中。无论是教学资…

matlab仿真 OFDM系统仿真

(内容源自详解MATLAB/SIMULINK 通信系统建模与仿真 刘学勇编著第九章内容,有兴趣的读者请阅读原书) clear all N8;%子载波数 f1:N;%各个子载波频率 xrandi([0 3],1,N);%子载波上的数据 x1qammod(x,4);%4-QAM调制 t0:0.001:1-0.…

学习周报-2024.9.3

目录 摘要 Abstract 文献阅读:一种改善河流水质预测的耦合模型以解决非平稳性和数据限制 一、现有问题 二、提出方法 三、相关知识 1、基于小波分析的LSTM(WA-LSTM) 2、迁移学习TL改进WA-LSTM 四、WA-LSTM-TL模型 五、研究实验 1、…

手写NACOS的服务的注册与发现|心跳机制|轮询调用服务功能

背景 手写NACOS的服务的部分核心功能,提高自身的编码能力 本篇文章设计的是单体NACOS后端服务,提供SDK给多个NACOS客户端使用 本文编写了注册与发现|心跳机制|轮询调用服务功能,可当做入门级阅读 nacos-service 项目结构 代码内容 pom配置…

Detect It Easy

Detect It Easy(简称 DIE)项目的网址为 https://github.com/horsicq/Detect-It-Easy 下载完安装包后,直接双击die.exe即可进入到操作界面 工具介绍: 它可以用来检测程序架构和文件类型。如图所示。其中,「模式」说明程…

UE5 贝塞尔曲线导弹

首先创建导弹Actor蓝图 代码逻辑,这其中创建的所有变量都不用添加值,这些逻辑要画图来解释,比较麻烦,大家自行理解一下 接下来进入人物蓝图编写代码逻辑,我这里是在两个不同的位置发射两枚导弹 宏中的代码,…

时序预测|基于粒子群优化支持向量机的时间序列预测Matlab程序PSO-SVM 单变量和多变量 含基础模型

时序预测|基于粒子群优化支持向量机的时间序列预测Matlab程序PSO-SVM 单变量和多变量 含基础模型 文章目录 一、基本原理1. 问题定义2. 数据准备3. SVM 模型构建4. 粒子群优化(PSO)5. 优化与模型训练6. 模型评估与预测7. 流程总结8. MATLAB 实现概述 二、…

Python QT实现A-star寻路算法

目录 1、界面使用方法 2、注意事项 3、补充说明 用Qt5搭建一个图形化测试寻路算法的测试环境。 1、界面使用方法 设定起点: 鼠标左键双击,设定红色的起点。左键双击设定起点,用红色标记。 设定终点: 鼠标右键双击&#xf…

轻松上手,高效产出:音频剪辑工具年度精选

不知道你有没有拍vlog记录生活的习惯,有时候视频里穿插进自己的声音能让视频更加丰富贴上自己的标签。这次我们一起探讨当下有哪些好用的在线音频剪辑工具。 1.FOXIT音频剪辑 链接直达>>https://www.foxitsoftware.cn/audio-clip/ 这个工具是一款专业的音…

GNU的伪操作 (25)

这里主要是 对 GNU的 各个伪操作进行 详细的解释。 先来看着几个 伪操作。 .byte, .short, .long, .quad , .float , 这个是关于 字节的。 .string .ascii 是关于字符串的。 这个字符串编译器是可以自动在末尾补0 的。 举例: val: .word 0x11223344 mov r…

计算机组成原理(SRAM电路图示)

1.该电路由6个MOS管(T1-T6)组成 2.T1-T4是一个由MOS管组成的触发器基本电路; T5,T6像开关,受行地址选择信号控制; T7,T8受列地址选择控制,分别与位线A,和相连 3.假设触发器…

FinOps原则:云计算成本管理的关键

导语: FinOps 原则为我们提供了北极星(North Star),在我们实践云财务管理时指导我们的活动。这些原则由 FinOps 基金会成员制定,并通过经验磨练出来。 北极星(North Star)的含义: …

不用管理员权限直接修改windows中hosts值的方法

本文只适用于少数经常修改hosts文件的程序员帅哥和美女们。 背景:直接修改hosts文件的不足 修改C:\Windows\System32\drivers\etc\hosts时,必须要管理员权限。 经常修改,会觉得有一丝丝麻烦。 方法1 (安全性低,不…

ThinkPHP5 5-rce远程代码执行漏洞复现

启动容器 docker-compose up -d 查看端口 docker ps 端口为:8080,访问网站,搭建成功 漏洞复现 (1)输出关于 PHP 配置的信息 (2)将php代码写入文件 接着访问shell.php 由于存在过滤,需要用到base64加密来使…

SPIRNGBOOT+VUE实现浏览器播放音频流并合成音频

一、语音合成支持流式返回,通过WS可以实时拿到音频流,那么我们如何在VUE项目中实现合成功能呢。语音合成应用非常广泛,如商家广告合成、驾校声音合成、新闻播报、在线听书等等场景都会用到语音合成。 二、VUE下实现合成并使用浏览器播放代码…

学习记录:js算法(二十八):删除排序链表中的重复元素、删除排序链表中的重复元素II

文章目录 删除排序链表中的重复元素我的思路解法一:循环解法二:递归 网上思路 删除排序链表中的重复元素 II我的思路网上思路 总结 删除排序链表中的重复元素 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出…

软件质量保障:故障演练介绍

目录 背景:架构变化带来的问题 什么是故障演练 为什么需要故障演练 故障演练场景有哪些 不同演练类型和目标 如何对工具进行评估 功能评测项 告警评测项 观测指标评测项 总结 背景:架构变化带来的问题 随着架构越来越复杂、应用越来越多样&…

外卖霸王餐对接接口为用户提供了哪些好处?

外卖霸王餐对接接口为用户提供了多种好处,以下是一些主要优势: 免费或低成本的美食体验:用户可以通过霸王餐活动免费或以非常低的价格尝试不同的餐厅和菜品。发现新餐厅和菜品:霸王餐活动可以帮助用户发现新的餐厅和他们可能感兴趣…

【C/C++IO流汇总】C/C++IO流以及系统调用open/read/write等详解

IO流学习分享 1、C中文件IO使用1.1、文件函数1.2、文件的使用方式1.3、文件的读写函数1.4、示例1.4.1、fgetc()函数1.4.2、getc()函数1.4.3、fputc()函数1.4.4、putc()函数1.4.5、fgets()函数1.4.6、fputs()函数1.4.7、fscanf()函数1.4.8、fprintf()函数 1.5、fread()函数1.5.1…