小P:小H,我又来了。。。最近在做ROI数据,但是有个问题。。。
小H:什么问题,不就是收入/成本吗?
小P:是的,每个渠道的成本很容易计算,但是收入就有点问题了。
小H:是不是不知道怎么分配啊?
小P:不愧是你,对的,用户在付费前经历过很多渠道,我感觉把收入分给谁都不好说
小H:这个也不复杂,关于渠道归因的方式有很多种,比如传统渠道归因、基于马尔可夫链、基于shapley value甚至是基于Attention-RNN深度学习。
说到渠道归因,那最容易想到的就是传统的渠道归因,这种方法一般是基于业务决策的。
首次归因:首次点击渠道赋予全部转化
末次归因:末次点击渠道赋予全部转化
线性(平均)归因:每个渠道均分转化
位置归因:自定义位置的权重,一般首位占50%,其余为0
时间衰减归因:距离转化的时间越短的渠道,可以获得越多的功劳权重,权重自定义
# pip install Cython
# pip install ChannelAttribution
import pandas as pd
from ChannelAttribution import *
Looking for attribution at path level? Try markov_model_local_api() or ask for ChannelAttributionPro at [email protected]! Visit https://channelattribution.io for more information.
Version: 2.1.3
本文所有数据如果有需要的同学可关注公众号HsuHeinrich,回复【数据挖掘-渠道归因】自动获取~
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 |
# 传统启发式算法计算各渠道转化次数和转化收益
# first_touch:首次点击模型;last_touch:末尾点击模型;linear_touch:线性(平均)点击模型
heuristic_models(Data,"path","total_conversions", var_value='total_conversion_value')
# 自定义位置归因函数,设置首尾权重各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
# 位置归因(首尾归因)
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 |
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from pandas.api.types import is_string_dtype, is_numeric_dtype
import warnings
import pandas as pd
# 读取数据 数据为自定义的
df=pd.read_excel('datas.xlsx')
df.head()
# 自定义时间衰减归因 衰减权重为半衰。例如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
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 |
传统渠道归因还是需要依据业务决定的,只要你能说服业务按照其中一种方式进行收入分配,那到这一步基本就够了。实际上,传统的渠道归因是易于理解、好操作、结果接受程度高的~
共勉~