前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >渠道归因(一)传统渠道归因

渠道归因(一)传统渠道归因

作者头像
HsuHeinrich
发布2023-08-10 11:05:18
2730
发布2023-08-10 11:05:18
举报
文章被收录于专栏:HsuHeinrichHsuHeinrich

渠道归因(一)传统渠道归因

小P:小H,我又来了。。。最近在做ROI数据,但是有个问题。。。 小H:什么问题,不就是收入/成本吗? 小P:是的,每个渠道的成本很容易计算,但是收入就有点问题了。 小H:是不是不知道怎么分配啊? 小P:不愧是你,对的,用户在付费前经历过很多渠道,我感觉把收入分给谁都不好说 小H:这个也不复杂,关于渠道归因的方式有很多种,比如传统渠道归因、基于马尔可夫链、基于shapley value甚至是基于Attention-RNN深度学习。

说到渠道归因,那最容易想到的就是传统的渠道归因,这种方法一般是基于业务决策的。

首次归因:首次点击渠道赋予全部转化 末次归因:末次点击渠道赋予全部转化 线性(平均)归因:每个渠道均分转化 位置归因:自定义位置的权重,一般首位占50%,其余为0 时间衰减归因:距离转化的时间越短的渠道,可以获得越多的功劳权重,权重自定义

首次/末次/线性归因

代码语言:javascript
复制
# pip install Cython
# pip install ChannelAttribution
代码语言:javascript
复制
import pandas as pd
from ChannelAttribution import *
代码语言:javascript
复制
Looking for attribution at path level? Try markov_model_local_api() or ask for ChannelAttributionPro at info@channelattribution.io! Visit https://channelattribution.io for more information.
Version: 2.1.3

本文所有数据如果有需要的同学可关注公众号HsuHeinrich,回复【数据挖掘-渠道归因】自动获取~

代码语言:javascript
复制
Data = pd.read_csv('./Markov/Data.csv',sep=";")
Data.head() 

数据格式要求: path:转化路径,以>连接 total_conversions:累计转化次数 total_conversion_value:累计转化收益 total_null:累计未转化次数

path

total_conversions

total_conversion_value

total_null

0

eta > iota > alpha > eta

1

0.244

3

1

iota > iota > iota > iota

2

3.195

6

2

alpha > iota > alpha > alpha > alpha > iota > ...

2

6.754

6

3

beta > eta

1

2.402

3

4

iota > eta > theta > lambda > lambda > theta >...

0

0.000

2

代码语言:javascript
复制
# 传统启发式算法计算各渠道转化次数和转化收益
# first_touch:首次点击模型;last_touch:末尾点击模型;linear_touch:线性(平均)点击模型
heuristic_models(Data,"path","total_conversions", var_value='total_conversion_value')

image-20230206153920384

位置归因

代码语言:javascript
复制
# 自定义位置归因函数,设置首尾权重各50%
def posAttribution(df, path, conversions):
    '''
    df:数据集
    path:用户旅程路径
    conversions:成功转化次数
    '''
    df=df.copy()
    df['leng']=df[path].map(lambda x: len(x.split(">")))
    df['first_touch']=df[path].map(lambda x: [x.strip() for x in x.split(">")][0])
    df['last_touch']=df[path].map(lambda x: [x.strip() for x in x.split(">")][-1])

    df['first_touch_conversions']=df[['leng',conversions]].apply(
        lambda x: x[conversions]*1 if x['leng']==1 else x[conversions]*0.5, axis=1)
    df['last_touch_conversions']=df[['leng',conversions]].apply(
        lambda x: 0 if x['leng']==1 else x[conversions]*0.5, axis=1)

    df1=df.groupby(['first_touch'])['first_touch_conversions'].sum()
    df2=df.groupby(['last_touch'])['last_touch_conversions'].sum()
    df_f=pd.merge(df1, df2, left_index=True, right_index=True, how = 'outer').reset_index()
    df_f['first_last_touch_conversions']=df_f['first_touch_conversions']+df_f['last_touch_conversions']
    df_f.drop(['first_touch_conversions','last_touch_conversions'], axis=1, inplace=True)
    
    return df_f
代码语言:javascript
复制
# 位置归因(首尾归因)
posAttribution(Data,"path","total_conversions")

first_touch

first_last_touch_conversions

0

alpha

7377.5

1

beta

1910.0

2

delta

3.0

3

epsilon

315.0

4

eta

3665.5

5

gamma

128.5

6

iota

3980.5

7

kappa

152.0

8

lambda

1054.5

9

mi

2.0

10

theta

1129.5

11

zeta

67.0

时间衰减归因

代码语言:javascript
复制
from sklearn.preprocessing import StandardScaler, MinMaxScaler 
from pandas.api.types import is_string_dtype, is_numeric_dtype
import warnings
import pandas as pd
代码语言:javascript
复制
# 读取数据 数据为自定义的
df=pd.read_excel('datas.xlsx')
df.head()

image-20230206153945877

代码语言:javascript
复制
# 自定义时间衰减归因 衰减权重为半衰。例如1->2,则1的权重是66.6%;1->2->3,则1的权重是50%,2的权重是33.3%
def lapsAttribution(df, path, conversions, last_time_lapse):
    def scum(l):
        s=0
        for i in range(1, len(l)+1):
            s+=i
        return s
    
    def lw(l):
        lw=[]
        n=scum(l)
        for i in range(1, len(l)+1):
            lw.append(1/n*i)
        return lw

    df['last_time_sp']=df[last_time_lapse].map(lambda x: str(x).split('>'))
    df['path_sp']=df[path].map(lambda x: [x.strip() for x in x.split(">")])
    df['lts_w']=df['last_time_sp'].map(lambda x:lw(x))
    df['conversions_sp']=df[[conversions,'lts_w']].apply(
            lambda x: [i*x[conversions] for i in x['lts_w']], axis=1)
    
    laps_touch=[]
    conversions_all=[]
    for i in df[['path_sp', 'conversions_sp']].values:
        for m in zip(i[0],i[1]):
            laps_touch.append(m[0])
            conversions_all.append(m[1])

    df_temp=pd.DataFrame({'laps_touch':laps_touch, 'laps_touch_conversions':conversions_all})
    df_f=df_temp.groupby(['laps_touch'])['laps_touch_conversions'].sum().reset_index()
    
    return df_f
代码语言:javascript
复制
lapsAttribution(df, 'path', 'total_conversions', 'last_time_lapse')

laps_touch

laps_touch_conversions

0

alpha

0.300000

1

beta

1.333333

2

eta

2.833333

3

iota

13.033333

4

kappa

0.500000

总结

传统渠道归因还是需要依据业务决定的,只要你能说服业务按照其中一种方式进行收入分配,那到这一步基本就够了。实际上,传统的渠道归因是易于理解、好操作、结果接受程度高的~

共勉~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-06-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 HsuHeinrich 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 渠道归因(一)传统渠道归因
    • 首次/末次/线性归因
      • 位置归因
        • 时间衰减归因
          • 总结
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档