数据分析36计(20):优化新财年广告预算,乘法营销组合模型的Python实现

2023-11-13

目录(文末附数据和代码)

1. 简介

如果你有做过FB广告投放,对 ROI 和 ROAS 这两个词一定不陌生,因为招聘的时候肯定会问你两个问题:

  1. 你接触过多大的盘子?即花过多少预算。

  2. 你的ROI一般是多少?

广告客户使用营销组合模型(MMM)来衡量其广告媒介投入如何促进销售增加,从而优化未来的预算分配。广告投入回报率(ROAS)和边际投入回报率(mROAS)是要关注的关键指标。较高的投入回报率表示渠道有效,而较高的边际投入回报率则意味着根据当前投入水平,增加渠道投入将产生高回报收益。


广告投入回报率 Return on Ad Spending,指广告上每投入一元所获得的营收占比。比如这个广告花了 1000 刀,给带来了 5000 刀的收入,则 ROAS=5,意思是在FB上花 1 刀就能带来 5 刀的收入。这个指标主要是测量广告花费的,算是战术层级。而 ROI 不仅包含广告费,还考虑了成本等因素,属于战略层级。


投资报酬率 Return on Investment,指每投资一元所获得的毛利占比。用谷歌官方的例子:

某产品成本 100 刀,卖 200 刀,你卖了 6 件,销售收入 1200 刀,广告花费是 200 刀。赚的利润:1200-6*100-200= 400 刀,成本投入:6*100+200= 800 刀,ROI=50%,即投资回报率是50%。

2. 模型原理

传统的营销归因,有几种规则,比如按照实际客户旅程的多个接触点线性计算贡献值。一位客户在电视上看到一个产品>点击了一个展示广告>点击了一个付费搜索广告>购买了30美元。在这种情况下,有3个接触点为此次转化做出了贡献。

还有只追踪可接触的数据,比如上一个数字接触点为SEM,通常只能跟踪上一个数字接触点。在这种情况下,SEM将会获得所有贡献。

模型原理:

  1. 使用媒体渠道展示、投入数据和控制变量,以先验的系数拟合回归模型来预测销售额;

  2. 将销售额分解为每个媒体渠道的贡献。渠道贡献是通过比较移除该渠道后的原始销售额和预期销售额得出的,原理类比于shapley value方法;

  3. 使用渠道贡献和投入来计算广告指标:ROAS和mROAS。

缺陷:对于营销组合模型(MMM),离线渠道的效果很难追踪。例如,客户看到电视广告,但在商店购物。且媒体渠道的效果是交织在一起的,交互效应无法测量。因此,一个好的归因模型应该考虑所有导致转化的相关变量。

2.1 乘法营销组合模型(MMM)

由于媒体渠道都以交互形式投放,因此采用了乘法模型结构:

取双方的对数,我们得到对数线性模型:

系数约束

  1. 媒体系数为正。

  2. 折扣,宏观经济,活动/零售节假日等控制变量将对销售额产生积极影响,其系数也应为正。

问题1:为什么不是纯粹的回归问题?(有sklearn,为什么要用复杂的 STAN / MCMC ?)

因为媒体变量的系数存在约束。媒体系数表明渠道对销售额的贡献程度应该为。系数为负数意味着在此渠道中投放广告将持续损害销售额,在广告上的投入越多,损失的销售额就越多。这是违反常识的。但是,如果用线性回归,则不可避免地会得到负系数或零系数。线性回归可朝着最小误差优化,它不关注系数方向。

问题2:STAN / MCMC采样器如何解决这个问题?

MMM是贝叶斯回归问题,我们对参数有先验知识。在下面的“3 模型实现”部分中,指定了参数的先验分布,并将其约束为正值/负值/在一定范围内。STAN 或 MCMC 采样器的作用是,从该样本空间中抽取样本多次(例如 1000 次迭代),并提出 1000 个可能的参数集合,将其平均值用作估计的参数值。

2.2 Adstock模型

广告理论是基于这样的假设,即电视广告的曝光会在消费者心中建立意识,从而影响他们的购买决策。每次新的广告曝光都会建立意识,如果最近有曝光,则该意识会更高,如果没有最近曝光,则该意识会更低。在没有进一步暴露的情况下,广告最终会衰减到可以忽略的水平。衡量和确定媒体渠道,尤其是在建立营销组合模型时,该假设是确定营销有效性的关键组成部分。

衰减或滞后效应:媒体对销售额的影响可能会滞后于初始曝光并且效果会持续数周。

  • L:媒体效果的时间长度

  • P:媒体效果的峰值,它比第一次曝光时间滞后几周

  • D:媒体的衰减率

累积到 L 周广告效果为当前第 L 周和之前 L-1 周的平均值:

示例如下:

不同的衰减率 D :通过拟合结果发现衰减率越高,效果越分散。

不同的时间长度 L: 时间长度影响相对较小。在模型训练中,长度参数可以固定为8周,也可以是直到媒体效果消失的一段时间范围。

import numpy as np
import pandas as pd


def apply_adstock(x, L, P, D):
    ‘’’
    params:
    x: original media variable, array
    L: length
    P: peak, delay in effect
    D: decay, retain rate
    returns:
    array, adstocked media variable
    ‘’’
    x = np.append(np.zeros(L-1), x)
 
    weights = np.zeros(L)
    for l in range(L):
        weight = D**((l-P)**2)
        weights[L-1-l] = weight
    
    adstocked_x = []
    for i in range(L-1, len(x)):
        x_array = x[i-L+1:i+1]
        xi = sum(x_array * weights)/sum(weights)
      adstocked_x.append(xi)
      adstocked_x = np.array(adstocked_x)
        
    return adstocked_x

2.3 边际收益递减模型

广告数量的增加会增加广告所覆盖的受众群体的百分比,从而增加需求,但是广告曝光率的线性增加不会对需求产生类似的线性影响。通常,广告的每个增量都会对需求增长产生逐渐减小的影响。这是广告边际收益递减效应。由上面的衰减效应模型得知,累积广告收益会先增加后消失。但是对于边际广告收益,在某个饱和点之后,增加投入将产生递减的边际收益,随着广告投入不断超支,渠道将失去效率。递减收益由希尔函数建模:

  • K:半饱和点

  • S:斜率

下图展示了Hill函数随 K 和 S 的变化而变化:

def hill_transform(x, ec, slope):
    return 1 / (1 + (x / ec)**(-slope))


3. 模型实现

3.1 数据集

四年(209周)的每周销售额,媒体展示和投入记录。

(1) 媒体变量

  • 媒体展示次数(前缀=“ mdip_”):13个媒体渠道的展示:直接邮件,插页,报纸,数字音频,广播,电视,数字视频,社交媒体,在线展示,电子邮件,SMS,会员,SEM

  • 媒体投入(prefix ='mdsp_'):媒体渠道投入

(2) 控制变量

  • 宏观经济(前缀=“ me _”):CPI,汽油价格。

  • 降价(prefix ='mrkdn_'):降价/折扣。

  • 商店数量('st_ct')

  • 零售节假日(prefix ='hldy_'):onehot编码

  • 季节性(prefix ='seas_'):月份,11月和12月分为几周。onehot编码

(3) 销售变量(“ sales”)

df = pd.read_csv(‘data.csv’)
# 1. media variables# media impressionmdip_cols=[col for col in df.columns if ‘mdip_’ in col]# media spendingmdsp_cols=[col for col in df.columns if ‘mdsp_’ in col]
# 2. control variables# macro economics variablesme_cols = [col for col in df.columns if ‘me_’ in col]# store count variablesst_cols = [‘st_ct’]# markdown/discount variablesmrkdn_cols = [col for col in df.columns if ‘mrkdn_’ in col]# holiday variableshldy_cols = [col for col in df.columns if ‘hldy_’ in col]# seasonality variablesseas_cols = [col for col in df.columns if ‘seas_’ in col]base_vars = me_cols+st_cols+mrkdn_cols+va_cols+hldy_cols+seas_cols
# 3. sales variablessales_cols =[‘sales’]
3.2 模型框架

训练了三个模型并构建模型融合:

  • 控制模型 control model

  • 营销组合模型 marketing mix model

  • 收益递减模型 diminishing return model

3.3 控制模型

目标:将预测的基准销售量(X_ctrl)为营销组合模型(MMM)的输入变量,这表示没有任何营销活动的基准销售额趋势。

X1:与销售额呈正相关的控制变量,包括宏观经济,门店数量,减价,节假日

X2:可能对销售额产生正面或负面影响的控制变量:季节性

y:sales

所有变量数据都标准化,参数先验分布如下:


import pystan
import os


os.environ[‘CC’] = ‘gcc-10’
os.environ[‘CXX’] = ‘g++-10’


# helper functions
def apply_mean_center(x):
    mu = np.mean(x)
    xm = x/mu
    return xm, mu


def mean_center_trandform(df, cols):
    df_new = pd.DataFrame()
    sc = {}
    for col in cols:
      x = df[col].values
         df_new[col], mu = apply_mean_center(x)
      sc[col] = mu
    return df_new, sc


def mean_log1p_trandform(df, cols):
    df_new = pd.DataFrame()
    sc = {}
    for col in cols:
        x = df[col].values
        xm, mu = apply_mean_center(x)
        sc[col] = mu
        df_new[col] = np.log1p(xm)
    return df_new, sc


# mean-centralize: sales, numeric base_vars
df_ctrl, sc_ctrl = mean_center_trandform(df, [‘sales’]+me_cols+st_cols+mrkdn_cols)
df_ctrl = pd.concat([df_ctrl, df[hldy_cols+seas_cols]], axis=1)


# variables positively related to sales: macro economy, store count, markdown, holiday
pos_vars = [col for col in base_vars if col not in seas_cols]
X1 = df_ctrl[pos_vars].values


# variables may have either positive or negtive impact on sales: seasonality
pn_vars = seas_cols
X2 = df_ctrl[pn_vars].values
ctrl_data = {
 ’N’: len(df_ctrl),
 ‘K1’: len(pos_vars), 
 ‘K2’: len(pn_vars), 
 ‘X1’: X1,
 ‘X2’: X2, 
 ‘y’: df_ctrl[‘sales’].values,
 ‘max_intercept’: min(df_ctrl[‘sales’])
}


ctrl_code1 = ‘’’
data {
 int N; // number of observations
 int K1; // number of positive predictors
 int K2; // number of positive/negative predictors
 real max_intercept; // restrict the intercept to be less than the minimum y
 matrix[N, K1] X1;
 matrix[N, K2] X2;
 vector[N] y; 
}
parameters {
 vector<lower=0>[K1] beta1; // regression coefficients for X1 (positive)
 vector[K2] beta2; // regression coefficients for X2
 real<lower=0, upper=max_intercept> alpha; // intercept
 real<lower=0> noise_var; // residual variance
}
model {
 // Define the priors
 beta1 ~ normal(0, 1); 
 beta2 ~ normal(0, 1); 
 noise_var ~ inv_gamma(0.05, 0.05 * 0.01);
 // The likelihood
 y ~ normal(X1*beta1 + X2*beta2 + alpha, sqrt(noise_var));
}
‘’’
sm1 = pystan.StanModel(model_code=ctrl_code1, verbose=True)
fit1 = sm1.sampling(data=ctrl_data, iter=2000, chains=4)
fit1_result = fit1.extract()

控制模型的平均绝对百分比误差 MAPE 为8.63%,从拟合结果中提取控制模型的参数,并预测基准销售额。

3.4 营销组合模型

目标

  • 找到适合各媒体渠道的 Adstock 模型参数

  • 将销售额分解为媒体渠道的贡献和非营销的贡献

L:媒体影响的时间长度

P:媒体影响的峰值

D:媒体影响的衰减

X:Adstock的媒体展示效果和基准销售额

y:sales

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据分析36计(20):优化新财年广告预算,乘法营销组合模型的Python实现 的相关文章

  • 如何在GPU支持下运行python代码

    我创建了一个 Flask 服务 用于接受以相机 URL 作为参数的请求 用于在相机框架中查找对象 桌子 椅子等 我已经在 Flask 中编写了用于接受 POST 请求的代码 app route rest detectObjects meth
  • 解析lxml.etree._Element内容

    我从以下元素中解析出 table td align center valign top a href ConfigGroups aspx cfgID 451161 amp prjID 11778 amp grpID DTST target
  • 使用 Selenium 选择具有特定内容的锚点

    我有一个 HTML 元素 如下所示 a class country href es co Columbia a 如何根据内容 Columbia 选择该锚元素 我不能使用find element by class css selector因为
  • 在 python pandas 中将级别附加到列索引

    我有几个具有相同列的数据框 我只想在它们的索引上合并 print df1 out Value ISO Id 200001 8432000000 USD 200230 22588186000 USD 200247 4633000000 USD
  • 如何从本地模式下运行的 pyspark 中的 S3 读取数据?

    我正在使用 PyCharm 2018 1 使用 Python 3 4 并通过 virtualenv 中的 pip 安装 Spark 2 3 本地主机上没有安装hadoop 因此没有安装Spark 因此没有SPARK HOME HADOOP
  • 打乱列表并返回副本

    我想对数组进行洗牌 但我找到的只是类似的方法random shuffle x from 在 Python 中随机化字符串列表的最佳方法 https stackoverflow com questions 1022141 best way t
  • 将 c++ 异常传播到 cython - python 异常

    我的 Cython 0 17 1 有问题 我的函数抛出一个std runtime error如果文件不存在 我想以某种方式将此异常传播到我的 Cython 代码 void loadFile const string filename som
  • 字符串在内部存储为单独的字符,内存中的每个字符都由其他类似的字符串共享吗?

    例如 是字符串var1 ROB 存储为 3 个内存位置 R O 和 B 每个位置都有自己的地址和变量var1指向内存位置R 那它怎么指向O和B呢 并执行其他字符串 例如 var2 BOB 指向内存中相同的 B 和 Ovar1指的是 字符串如
  • 如何将多个 Excel 工作表转换为 csv python

    我想转换所有的excel文档 xls 将工作表转换为 csv 如果 excel 文档只有一张工作表 那么我将进行如下转换 wb open workbook path1 sh wb sheet by name Sheet1 csv file
  • 无法启动 Windows 快捷方式

    我正在尝试使用 python 启动 Windows 我已经尝试了 os system subprocess call os startfile 等多种方法 但总是收到错误消息 指出路径不存在 我知道路径是正确的 因为我尝试在 CMD EXE
  • 将 Python 列表(JSON 或其他)插入 MySQL 数据库

    所以我在Python中有一堆数组数据 嗯 相反 我有一个清单 我试图将此数组存储到 MySQL 数据库中的单个单元格中 我尝试使用 JSON 来序列化我的数据 但也许我不明白 JSON 是如何工作的 因此 在连接到我的数据库后 我尝试了上游
  • [matplotlib]:理解“set_ydata”方法

    我试图了解如何使用 set ydata 方法 我在 matplotlib 网页上找到了很多示例 但我只找到了 set ydata 被 淹没 在大型且难以理解的代码中的代码 我想要一个简短且易于理解的代码来帮助我理解 set ydata 的工
  • Python 中 Matlab 'fscanf' 的等价物是什么?

    Matlab函数fscanf 似乎很强大 python 或numpy 中是否有相同的等效项 具体来说 我想从文件中读取矩阵 但我不想迭代每一行来读取矩阵 类似的东西 来自 matlab 用于读取 2D 1000x1000 矩阵 matrix
  • 字段“id”期望一个数字,但得到“natsu”django

    我想创建一个 user posts 视图 其中包含与特定用户相关的所有帖子 假设有用户 Natsu 撰写的博客帖子 那么登录用户 Testuser 将能够查看所有帖子由该用户发布 即用户 Natsu 的所有帖子 blog models py
  • 谷歌colab录音,如何实现更精确的方式告诉用户开始对着麦克风说话

    我正在尝试创建一个为机器学习项目录制音频的程序 我想使用 google colab 这样人们就不必在他们的系统上安装或运行任何东西 我在网上找到了这个录制和播放音频的示例 单元格 1 包含用于录制音频的 js 代码和用于将其转换为字节对象的
  • 使用 Django 添加额外 \\ 字符的 JSON 编码

    我正在尝试创建一个函数 将包含消息和 Django 模型实例的字典转换为 JSON 然后我可以将其传回客户端 例如 我在 models py 中定义了模型 Test from django db import models class Te
  • 如何在Python Selenium中获取WebElement的类名?

    我使用 Selenium WebDriver 来抓取从网页中获取的 用 JavaScript 编写的表格 我正在迭代表行列表 每行可能属于不同的类别 我想获取此类的名称 以便我可以为每一行选择适当的操作 table body table f
  • Spyder 内联绘图

    设置 Anaconda 2 0 0 Win 64 Spyder Anaconda 附带的 2 3 0rc 我配置图形 工具 gt 首选项 gt iPython 控制台 gt 图形 gt 图形后端 gt 内联 但无论我做什么 图形总是在单独的
  • Django 自定义文件存储系统

    我有一个自定义存储 import os from django core files storage import Storage class AlwaysOverwriteFileSystemStorage Storage def get
  • 2D 矩阵上的 Numpy where()

    我有一个像这样的矩阵 t np array 1 2 3 foo 2 3 4 bar 5 6 7 hello 8 9 1 bar 我想获取行包含字符串 bar 的索引 在一维数组中 rows np where t bar 应该给我索引 0 3

随机推荐

  • 求一个数阶乘末尾有几个零

    昨天校赛有一道题 是求一个数的阶乘 末尾有几个零 当时是没有做出来的 今天网上看了下 明白了原理 其实很多人都写过了 自己之所以再写 一是为了加强自己的理解 二是有的地方或许可以写得更详细 也写出自己思考的一些误区 回到题目本身 求一个数的
  • VTK库的编译和安装

    一 准备工具 CMake工具 Visual Studio 2013 VTK 8 1 0 The Visualization Toolkit 最新版源码 或者其他版本 二 使用CMake生成VTK的MS VS工程文件 打开CMake 设置源码
  • 基于CUDA的GPU优化建议

    l GPU硬件特性 n 存储层次 u Global memory l 大小一般为几GB l chip off的DRAM介质存储器 l 访问速度慢 是shared memory的上百倍 l 对于是否对齐和连续访问敏感 由DRAM的性质决定 l
  • 非常适合金融人的副业,不用坐班,时间自由!

    最近在论坛上看到一个测试 特扎心 以下三种情况 哪个让你最绝望 月薪4500 花呗欠了10000 被领导骂到哭 因为没钱不敢裸职 租房子的中介公司突然倒闭 房东逼你搬出去 你却拿不出押一付三的费用 说实话 我真的选不出 每一个都让我崩溃 0
  • 什么是白盒测试?什么是黑盒测试?两者的主要区别

    从测试方法上分 软件测试可分为白盒测试和黑盒测试 1 白盒测试 白盒测试 又称结构测试 主要用于单元测试阶段 它的前提是可以把程序看成装在一个透明的白箱子里 测试者完全知道程序的结构和处理算法 这种方法按照程序内部逻辑设计测试用例 检测程序
  • R语言—数据框

    文章目录 数据框 Dataframe 创建数据框 数据框的访问 通过组件的索引值来访问组件 通过组件的组件名来访问组件 通过访问矩阵的方式来访问组件 数据筛选 扩展数据框 添加列 添加行 使用apply 函数 数据框 Dataframe 数
  • 机器学习路径

    文章目录 前言 1 课前准备 2 主流的学习过程 3 具体内容 4 主要方向 体系 自然语言处理 知识图谱 计算机视觉 人机交互 参考资料 前言 1 机器学习到底应该怎么去学 机器学习的学习没有想象中的那么困难 当然也没有外面宣传的那么容易
  • R语言中的参数估计

    R语言中的参数估计 一直想要写博客来着 一直没有实现 昨天看室友写了 借着复习R语言考试 来开启我的第一篇博客叭 以下我将从点估计 区间估计来介绍区间估计 本文主要介绍R代码 具体的统计知识 详情可参考相关数理统计的专业书嗷 参数估计 R语
  • Day2 剑指offer

    30题 栈 定义栈的数据结构 请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中 调用 min push 及 pop 的时间复杂度都是 O 1 示例 MinStack minStack new MinStack minStac
  • 【0007】由于找不到MSVCR100.dll,无法继续执行代码

    下载安装Microsoft Visual C 2010 VC2010运行库 程序语言编译环境就能解决 官网下载地址 https www microsoft com zh CN download details aspx id 14632
  • 机器学习历程——人工智能基础与应用导论 专题篇(statsmodel)(3)

    目录 一 介绍 1 官网 2 主要功能 3 安装 二 t检验 1 概念 2 假设条件 3 单样本t检验 4 配对样本t检验 三 McNemar检验与Nemenyi检验 四 Friedman检验 一 介绍 1 官网 Introduction
  • Vue:统计代码行数

    1 在代码目录下打开git bash 2 在代码目录下打开git bash find name html or name js or name css or name vue print xargs wc l 运行结果 3 命令解析 fin
  • 中国银行业发展前景预测与未来战略规划建议报告2022-2028年版

    中国银行业发展前景预测与未来战略规划建议报告2022 2028年版 报告目录 第一章 2020 2022年国际银行业分析 1 1 2020 2022年全球银行业运行状况分析 1 1 1 全球宏观经济 1 1 2 金融市场波动 1 1 3 行
  • vue监听watch使用

    watch监听一定要监听 属性值 也就是data值 案例 data return language methods handleSetLanguage lang this i18n locale lang this language lan
  • cJSON介绍及使用

    JSON JavaScript Object Notation 是一种轻量级的文本数据交换格式 易于让人阅读 同时也易于机器解析和生成 尽管JSON是Javascript的一个子集 但JSON是独立于语言的文本格式 并且采用了类似于C语言家
  • 面向对象&类和对象

    一 面向对象的概念 概念 面向对象是基于万物皆对象这个哲学观点 在Python中 一切皆对象 说明 案例 我想要吃大盘鸡 面向过程 面向对象 1 自己去买菜 1 委托一个会砍价的人帮忙去买菜 2 自己择菜 2 委托一个临时工帮忙择菜 3 自
  • 认知与思考-190820

    首先我觉得人应该读自己能驾驭的书 或者说自己的人格坚固 道家讲道心 佛家讲慧根 其实就是自己的本心不为所动 如果能 读各种书只会增加你处事能力和分辨万物的能力 你是主体 知识只是你解决方式的手段 向阳而生 你要知道 世间万物本就存在 你读不
  • 【第60篇】多目标跟踪:文献综述

    文章目录 摘要 1 简介 1 1 与其他相关综述的区别 1 2 贡献 1 3 综述的结构 1 4 外延 2 MOT问题 2 1 问题公式化 2 2 MOT的分类 2 2 1 初始化方法 2 2 2 处理方式 2 2 3 输出类型 2 2 4
  • 3 Decomposition Methods

    分解方法是解决问题的一般方法 其将问题分解为更小的问题并且并行地或者顺序地解决每个更小的问题 当采用顺序的方式时 优点是问题的复杂性呈超线性增长 more than linearly 如果问题在单步操作中分解有效 那么我称该问题为 块 可分
  • 数据分析36计(20):优化新财年广告预算,乘法营销组合模型的Python实现

    目录 文末附数据和代码 1 简介 如果你有做过FB广告投放 对 ROI 和 ROAS 这两个词一定不陌生 因为招聘的时候肯定会问你两个问题 你接触过多大的盘子 即花过多少预算 你的ROI一般是多少 广告客户使用营销组合模型 MMM 来衡量其