美文网首页
星巴克广告宣传策略探索

星巴克广告宣传策略探索

作者: 愤怒的果壳 | 来源:发表于2019-09-25 21:23 被阅读0次
New-Starbucks-Logo-1200x969.jpg

背景介绍

本数据原是星巴克的面试数据,包含 120,000 个数据点,按照 2:1 的比例划分为训练文件和测试文件。数据模拟的实验测试了一项广告宣传活动,看看该宣传活动能否吸引更多客户购买定价为 10 美元的特定产品。由于公司分发每份宣传资料的成本为 0.15 美元,所以宣传资料最好仅面向最相关的人群。每个数据点都有一列表示是否向某个人发送了产品宣传资料,另一列表示此人最终是否购买了该产品。每个人还有另外 7 个相关特征,表示为 V1-V7。

优化策略

通过训练数据了解 V1-V7 存在什么规律表明应该向用户分发宣传资料。具体而言,目标是最大化两项指标:

  • 增量响应率 (IRR)

IRR 表示与没有收到宣传资料相比,因为推广活动而购买产品的客户增加了多少。从数学角度来说,IRR 等于推广小组的购买者人数与购买者小组客户总数的比例 (treatment) 减去非推广小组的购买者人数与非推广小组的客户总数的比例 (control)。

IRR = \frac{purch_{treat}}{cust_{treat}} - \frac{purch_{ctrl}}{cust_{ctrl}}

  • 净增量收入 (NIR)

NIR 表示分发宣传资料后获得(丢失)了多少收入。从数学角度来讲,NIR 等于收到宣传资料的购买者总人数的 10 倍减去分发的宣传资料份数的 0.15 倍,再减去没有收到宣传资料的购买者人数的 10 倍。

NIR = (10\cdot purch_{treat} - 0.15 \cdot cust_{treat}) - 10 \cdot purch_{ctrl}

  • 测试策略
    实际推广客户与预测推广客户表格:
5.jpg

针对预测应该包含推广活动的个人比较指标,即第一象限和第二象限。由于收到宣传资料的第一组客户(在训练集中)是随机收到的,因此第一象限和第二象限的参与者人数应该大致相同。 比较第一象限与第二象限可以知道宣传策略未来效果如何即可。 也就是说,我们对预测参与宣传推广活动的客户应用两项指标计算,力争使其最大化。

设计构想

  • 根据增量响应率和净增量收入两项指标计算可以看出:在未寄送传单情况下购买人数为0时,两项指标达到最大。即理想情况下:我们准确预测到相应宣传购买的所有顾客,精准寄送传单。
  • 基于这个判断,我们应该选择预测收到宣传之后更可能会去购买的客户,同时他最好在没有收到宣传时不太可能购买。
  • 本次使用两个简单的计算策略:
    1.预测在收到宣传资料更可能会购买的客户,参与推广活动;
    2.预测在收到宣传资料更倾向购买且未收到宣传资料不会主动购买的客户,参与推广活动。

构想实施

导入数据并查看

# 导入工具包
import numpy as np
import pandas as pd
import scipy as sp
import sklearn as sk

from matplotlib import pyplot as plt
import seaborn as sns
%matplotlib inline
# 加载数据
train_data = pd.read_csv('./training.csv')
test_data = pd.read_csv('./Test.csv')
# 查看训练集
train_data.head()
6.png
train_data.info()
7.png
train_data['purchase'].value_counts()

0  83494
1   1040

train_data['Promotion'].value_counts()

Yes  42364
No  42170

# 查看特征分布
feature_list = ['V1', 'V2', 'V3', 'V4', 'V5', 'V6','V7']
# 查看收到推广信息并购买用户的特征分布
train_data.query('Promotion == "Yes" and purchase == 1')[feature_list].hist(figsize=(12,12));
# 查看收到推广未购买的客户特征分布
train_data.query('Promotion=="Yes" and purchase==0')[feature_list].hist(figsize=(12,12));
# 查看未收到宣传资料而购买的用户特征
train_data.query('Promotion=="No" and purchase==1')[feature_list].hist(figsize=(12,12));
# 查看未收到宣传资料也未购买的用户特征
train_data.query('Promotion=="No" and purchase==0')[feature_list].hist(figsize=(12,12));

收到宣传且购买的用户特征

1.png

收到宣传未购买的用户特征

2.png

未收到宣传购买的用户特征

3.png

未收到宣传未购买的用户特征

4.png
发现:
  • V2,V3特征分布略有不同;
  • V4的第一分类,V5的第二分类表现出一定差异;
  • 但整体来说,没有特别显著的差别;
  • 综上,我们尝试使用xgb这样分类能力较强的集成算法。

策略一

  • 挑选收到推广更可能购买的用户参加活动,即将训练集中promotion==’yes‘且purchase==1的数据标签设为1,其他为0,进行二分类。
数据预处理
# 备份数据
train = train_data.copy()
test = test_data.copy()
from sklearn import preprocessing
# 对V2,V3变量进行标准化
train['V2'] = preprocessing.scale(train['V2'])
train['V3'] = preprocessing.scale(train['V3'])
# 对V1、V4、V5、V6、V7进行one_hot编码
dummy_fields = ['V1', 'V4', 'V5', 'V6','V7']
for V in dummy_fields:
    dummies = pd.get_dummies(train[V],prefix =V,drop_first = False)
    train = pd.concat([train,dummies],axis =1)
train = train.drop(dummy_fields,axis=1)
# 标记收到推送后购买的用户为1,其他为0
train['response'] = 0
train.loc[(train['Promotion']=='Yes') & (train['purchase']==1),'response'] = 1
# 将train数据分为训练集和验证集
from sklearn.model_selection import train_test_split
Train, Valid = train_test_split(train, test_size=0.2, random_state=0)
features = ['V2', 'V3', 'V1_0', 'V1_1', 'V1_2','V1_3', 'V4_1', 'V4_2','V5_1', 'V5_2', 
            'V5_3', 'V5_4', 'V6_1', 'V6_2','V6_3', 'V6_4', 'V7_1', 'V7_2']
X_train,X_valid = Train[features],Valid[features] 
y_train,y_valid = Train['response'],Valid['response']
Train.head(2)
# 观察训练集标签
y_train.value_counts()
8.png
对连续数据v2,v3进行标准化,其他分类特征one_hot编码,使用策略1对收到推广之后购买的客户标签记为1,其余记为0
标签:
  • 0 : 67040
  • 1 : 587
    可以看出:这是一个标签分布非常不平衡的数据集,0标签是1标签数据的110多倍
y_valid.value_counts()
  • 0 : 16773
  • 1 : 134
    验证数据的比例甚至更加悬殊
直接使用xgboost分类
from xgboost import XGBClassifier
from sklearn import metrics
eval_set_1 = [(X_train, y_train), (X_valid, y_valid)]
model_1 = XGBClassifier(  learning_rate = 0.05,
                          max_depth = 8,
                          min_child_weight = 1,
                          scale_pos_weight = 114, # 通过权重调节数据标签的不平衡,114是0标签/1标签的比值
                          objective = 'binary:logistic',
                          seed = 42,
                          gamma = 0.1,
                          silent = True,
                          n_jobs = -1,
                          n_estimators = 200
                           )
model_1.fit(X_train, y_train, eval_set=eval_set_1,
          eval_metric="auc", verbose=True, early_stopping_rounds=30)
valid_pred_1 = model_1.predict(X_valid, ntree_limit=model_1.best_ntree_limit)
sk.metrics.confusion_matrix(y_valid, valid_pred_1)
9.png

简单评估下这个分类结果,在标签比列为16773:134的数据集中,如果随机进行选择,我们期望应该是就像抛硬币,各占一半,也就是8387:8386:67:67,现在9057:7716:34:100的结果显然超过这个最低要求,说明在xgb算法中设置scale_pos_weight = 114这个权重参数起到了一定的调节作用。

# 创建获得增量响应率和净增量收入的函数
def get_irr_nir(y_pred,df_valid=Valid):
    # 选取预测为1作为计算样本
    df_pro = df_valid.iloc[np.where(y_pred==1)]
    
    cust_tre = df_pro.loc[df_pro['Promotion']=='Yes',:].shape[0]
    cust_con = df_pro.shape[0] - cust_tre
    purch_tre = df_pro.loc[df_pro['Promotion']=='Yes', 'purchase'].sum()
    purch_con = df_pro.loc[df_pro['Promotion']=='No', 'purchase'].sum()
    
    irr = purch_tre/cust_tre - purch_con/cust_con
    nir = 10*purch_tre - 0.15*cust_tre - 10*purch_con
    return irr,nir
irr,nir = get_irr_nir(valid_pred_1,Valid)
print('IRR: %.4f' % irr)
print('NIR: %.4f' % nir )

计算验证集指标

  • IRR: 0.0187
  • NIR: 145.0000
将模型应用到测试数据
df = test_data[['V1', 'V2', 'V3', 'V4', 'V5', 'V6', 'V7']]
# 对df数据进行标准化
V_col = ['V2', 'V3']
for v in V_col:
    df[v] = preprocessing.scale(df[v])
# 对V1、V4、V5、V6、V7进行one_hot编码
dummy_fields = ['V1', 'V4', 'V5', 'V6','V7']
for V in dummy_fields:
    dummies = pd.get_dummies(df[V],prefix =V,drop_first = False)
    df = pd.concat([df,dummies],axis =1)
df = df.drop(dummy_fields,axis=1)

# 使用模型预测并输出结果
target_pred_1 = model_1.predict(df,ntree_limit=model_1.best_ntree_limit)
irr,nir = get_irr_nir(target_pred_1,test)
print('IRR: %.4f' % irr)
print('NIR: %.4f' % nir )

输出结果

  • irr: 0.0180
  • nir: 274.5
    这个结果似乎还不错,但还不是特别令人满意,再尝试下其他方法
smote过采样处理
# 使用smote方法过采样
from imblearn.over_sampling import SMOTE
sm = SMOTE(random_state=42)
X_train_over, y_train_over = sm.fit_sample(X_train, y_train)
X_train_over = pd.DataFrame(X_train_over, columns=features)
y_train_over = pd.Series(y_train_over)
y_train_over.value_counts()
  • 1: 67040
  • 0: 67040
    经过过采样处理之后的标签数量持平,这里简单介绍一下过采样和smote方法
    10.png
    过采样就是制作与原数据相似的或者相同的数据,增大其数量占比
    11.png
    smote是一种过采样方法,通过随机选择需要过采样的数据点,使用k近邻算法匹配附近的同类样本,并在他们之间添加新的样本
过采样之后使用xgb预测
eval_set_2 = [(X_train_over, y_train_over), (X_valid, y_valid)]
model_2 = XGBClassifier(learning_rate = 0.05,
                          max_depth = 8,
                          min_child_weight = 1,
                          objective = 'binary:logistic',
                          seed = 42,
                          gamma = 0.1,
                          silent = True,
                          n_estimators=200)
model_2.fit(X_train_over, y_train_over, eval_set=eval_set_2,
          eval_metric="auc", verbose=True, early_stopping_rounds=30)
valid_pred_2 = model_2.predict(X_valid, ntree_limit=model_2.best_ntree_limit)
sk.metrics.confusion_matrix(y_valid, valid_pred_2)
12.png
irr,nir = get_irr_nir(valid_pred_2,Valid)
print('IRR: %.4f' % irr)
print('NIR: %.4f' % nir )
  • IRR: 0.0207
  • NIR: 179.4500
    比之前略有提升,继续看测试结果
# 使用模型预测并输出结果
target_pred_2 = model_1.predict(df,ntree_limit=model_2.best_ntree_limit)
irr,nir = get_irr_nir(target_pred_2,test)
print('IRR: %.4f' % irr)
print('NIR: %.4f' % nir )
  • IRR: 0.0205
  • NIR: 435.05
    在测试集的表现较之前有很大提升

策略二

  • 挑选收到推广之后更可能购买且未收到推广更不可能购买的用户。即分别训练两个模型进行预测,一个在收到推广的数据集上训练,一个未收到推广数据集上训练,分别得到购买的可能性:Ptreat 和 Pcont,计算他们的差值deltaP = Ptreat - Pcont,选择deltaP前30%的用户。
数据预处理
# 选取两个模型的训练和验证数据
train_treat = Train[Train['Promotion']=='Yes']
train_cont = Train[Train['Promotion']=='No']
valid_treat = Valid[Valid['Promotion']=='Yes']
valid_cont = Valid[Valid['Promotion']=='No']

X_tt = train_treat[features_2]
X_tc = train_cont[features_2]
y_tt = train_treat['purchase']
y_tc = train_cont['purchase']
X_val_tt = valid_treat[features_2]
X_val_tc = valid_cont[features_2]
y_val_tt = valid_treat['purchase']
y_val_tc = valid_cont['purchase']

# 对训练数据使用smote方法过采样
#from imblearn.over_sampling import SMOTE
#sm = SMOTE(random_state=42)
X_tt_over, y_tt_over = sm.fit_sample(X_tt, y_tt)
X_tt_over = pd.DataFrame(X_tt_over, columns=features)
y_tt_over = pd.Series(y_tt_over)
X_tc_over, y_tc_over = sm.fit_sample(X_tc, y_tc)
X_tc_over = pd.DataFrame(X_tc_over, columns=features)
y_tc_over = pd.Series(y_tc_over)
模型训练

收到宣传用户模型

eval_set_3 = [(X_tt_over, y_tt_over), (X_val_tt, y_val_tt)]
model_3 = XGBClassifier(learning_rate = 0.05,
                          max_depth = 8,
                          min_child_weight = 1,
                          objective = 'binary:logistic',
                          seed = 42,
                          gamma = 0.1,
                          silent = True,
                          n_estimators=200)
model_3.fit(X_tt_over, y_tt_over, eval_set=eval_set_3,
          eval_metric="auc", verbose=True, early_stopping_rounds=30)
valid_pred_3 = model_3.predict(X_val_tt, ntree_limit=model_3.best_ntree_limit)
sk.metrics.confusion_matrix(y_val_tt, valid_pred_3)
13.png

未收到宣传用户模型

eval_set_4 = [(X_tc_over, y_tc_over), (X_val_tc, y_val_tc)]
model_4 = XGBClassifier(learning_rate = 0.01,
                          max_depth = 7,
                          min_child_weight = 5,
                          objective = 'binary:logistic',
                          seed = 42,
                          gamma = 0.2,
                          silent = True,
                          n_estimators=200)
model_4.fit(X_tc_over, y_tc_over, eval_set=eval_set_4,
          eval_metric="auc", verbose=True, early_stopping_rounds=30)
14.png
# 使用模型预测概率
p_treat = model_3.predict_proba(df, ntree_limit=model_3.best_ntree_limit)[:,1]
p_cont = model_4.predict_proba(df, ntree_limit=model_4.best_ntree_limit)[:,1]
# 计算概率差值
delta_p = p_treat - p_cont
# 计算70%分位数
cut_num = np.percentile(delta_p,70)
# 选择用户
test_pred = np.where(delta_p > cut_num,1,0)
# 计算指标
irr,nir = get_irr_nir(test_pred,test)
print('IRR: %.4f' % irr)
print('NIR: %.4f' % nir )
  • IRR: 0.0229
  • NIR: 457.4000
    策略二获得了更高指标分数,甚至没有进行迭代调优,没有收到推广的用户模型auc值仅达到0.54,但它仍然轻松超过了策略一的分数,不过策略二直接使用了策略一的部分参数设置,可以说是在策略一基础上的一个发展策略

总结

本次星巴克客户宣传推广策略的探索,其实是一个很有代表性的问题,商家谋求精准定位潜在营销对象,实施精准推广宣传,降低转化成本和行为成本,但是用户特征往往差异很小,极难做出精确分辨,尤其是类似数据很不平衡的分类问题,准确率是一个误导指标,xgboost的scale_pos_weight权重指标和SMOTE过采样方法提供了一个比较好的解决方案,可以帮助快速实现分类性能的提升,但最重要的还是策略的内在逻辑,好的方法与好的逻辑相结合,才能获得好的结果。

相关文章

  • 星巴克广告宣传策略探索

    背景介绍 本数据原是星巴克的面试数据,包含 120,000 个数据点,按照 2:1 的比例划分为训练文件和测试文件...

  • 性价比高?有可能是价格锚点

    最近看星巴克的文章,认识了一个关于“价格锚点”的词汇和概念,不得不佩服星巴克关于依云矿泉水的营销策略。 星巴克将价...

  • 跟着星巴克买房策略

    按:本文作者@Shawn,是我通过网络认识的好友。去年,他独立在重庆完成选房、购房和装修后顺利入住。而这一经历,也...

  • 一个杯子测试的故事---基于质量模型的测试策略

    常见的测试策略有基于需求的测试策略、基于风险的测试策略、基于模型的测试策略和探索性测试策略等。下面我们就用纸杯测试...

  • 2019-06-15

    瑞幸咖啡思考: 1、瑞幸放言对标星巴克,是个很好的策略。因为有争议所以有话题性,而且星巴克是行业龙头,咖啡品质代表...

  • 星巴克中国的营销策略

    (一)品牌价值策略 星巴克咖啡这一品牌在中国有着十六年的发展历史,在咖啡行业的中占据了主导的地位,有着一流的品牌形...

  • 重在卖对需求

    记得《抢占心智》中江南春提到广告宣传策略曾提过这种概念,广告销售重点是你要卖什么,而不是要民众买什么。 “怕上火,...

  • 广告宣传的七个绝密策略

    现在我们谈到的宣传是什么?宣传单、DM、广告车、腰鼓队、搭台,是不是这样,那你说这是对呢还是不对呢?有效还是没效呢...

  • 模拟策略游戏《孢子》体验报告

    游戏标签:模拟 策略 进化 冒险 生命 文明 宇宙 探索 创造 《孢子》是由Maxis开发的一款策略类游戏,于20...

  • 【面试准备02】江西2016年

    1.我会采用以下三种方式宣传: (1)电视广告宣传 (2)海报广告宣传 (3)网络渠道宣传 第一,电视广告宣传主要...

网友评论

      本文标题:星巴克广告宣传策略探索

      本文链接:https://www.haomeiwen.com/subject/ajleuctx.html