异动分析(四)利用Python计算指标贡献度

小P:有些异动的原因是多方面的,我看网上说可以通过计算贡献度进行量化。

小H:是的,容我想想~

虽然不是必要的,但有时候异动的原因多个,通过计算每个原因的贡献程度即可以很好的分清主次。这里主要根据博客如何快速量化增长指标的各因子贡献进行python化计算,主要采取的是相对贡献,即在指定维度下,各细分维度的总贡献为100%。

⚠️注意:绝对贡献只需要去除共同的分母即可,读者可自行尝试~

指标拆解计算各子指标贡献

这里采用LMDI法,一种指数分解法,可以计算乘法公式中每个因子对整体变动的贡献度,将变动分解到因子

  1. 计算目标变量y的变化率: r Δ y = y 1 y 0 − 1 r_{\Delta y} =\frac{y_1}{y_0}-1 rΔy​=y0​y1​​−1
  2. 计算目标变量y的变化对数: l n Δ y = l n ( y 1 − y 0 ) ln{\Delta y}=ln(y_1-y_0) lnΔy=ln(y1​−y0​)
  3. 计算各因子的权重: W l n ( Δ X i ) = l n ( X i 1 − X i 0 ) / l n Δ y W_{ln(\Delta X_i)}=ln(X_{i1}-X_{i0})/ln{\Delta y} Wln(ΔXi​)​=ln(Xi1​−Xi0​)/lnΔy,其中i为第i个子指标
  4. 计算各因子贡献: C o n t r i b u t e X i = W l n ( Δ X i ) ∗ r Δ y Contribute_{X_i}=W_{ln(\Delta X_i)}*r_{\Delta y} ContributeXi​​=Wln(ΔXi​)​∗rΔy​
import pandas as pd
import numpy as np
import random
import itertools
from numpy.random import choice
from random import randint, random
# 构造数据
month=[5,6]
sales=[450, 686]
enter_uv=[60000, 65000]
click_rate=[0.1, 0.11]
paid_rate=[0.05, 0.06]
per_buy_cnt=[1.5, 1.6]
data=pd.DataFrame(data={'month':month,'sales':sales,'enter_uv':enter_uv,'click_rate':click_rate,'paid_rate':paid_rate,'per_buy_cnt':per_buy_cnt,
})
data

def cal_metric_contribute(df, period, base_date, cont_date, X, y):'''df:数据集,只包含两期数据period:日期字段base_date:基期时间cont_date:对照期时间X:指标列y:结果列'''df=df.copy()# 构造基期与对照期数据集df_base=df[df[period]==base_date]df_cont=df[df[period]==cont_date]# 计算y的变换率y_change_rate=df_cont[y].values[0]/df_base[y].values[0]-1# 计算y的自然对数差值ln_y_change=np.log(df_cont[y].values[0]/df_base[y].values[0])# 计算X的自然对数差值ln_x_change=[]for j in X:ln_x_change.append(np.log(df_cont[j].values[0]/df_base[j].values[0]))# 计算X的自然对数差权重ln_x_weight=ln_x_change/ln_y_change# 计算指标贡献度x_contribute=ln_x_weight*y_change_rate# 导出dfdf_result=pd.DataFrame(x_contribute, index=X, columns=['contribute'])return df_result
period='month'
y='sales'
X=['enter_uv', 'click_rate', 'paid_rate', 'per_buy_cnt']
base_date=5
cont_date=6
cal_metric_contribute(data, period, base_date, cont_date, X, y).sort_values(by='contribute', ascending=False)
contribute
paid_rate 0.226781
click_rate 0.118552
enter_uv 0.099561
per_buy_cnt 0.080276

维度下钻衡量各维度权重

# 自定义随机权重,用于定性的控制转化率差异
def rand_weight(x):wi=random()lift=[i*0.05 for i in range(5,-5,-1)]return wi+lift[x]
# 构造维度
ch=['A', 'B', 'C', 'D']
level=['l1', 'l2', 'l3']
gender=['F', 'M']
mon=['1月', '2月']# 构造基期数据
np.random.seed(4)
u1 = 1000
uc = choice(ch, size=u1, p=[0.6, 0.2, 0.15, 0.05])
ul = choice(level, size=u1, p=[0.7, 0.2, 0.1])
ug = choice(gender, size=u1, p=[0.6, 0.4])
s_rate1 = 0.4
s1 = np.random.binomial(1, s_rate1, u1)
# 自定义权重
w11 = {'A':3,'B':1,'C':2,'D':3
}w12 = {'l1':2,'l2':4,'l3':0
}w13 = {'F':1,'M':3
}df1 = pd.DataFrame(columns=['ch', 'level', 'gender'])
df1['ch'], df1['level'], df1['gender'] = uc, ul, ug
df1['w1'] = df1.apply(lambda x: rand_weight(w11[x['ch']])+rand_weight(w12[x['level']])+rand_weight(w13[x['gender']]), axis=1)
df1.sort_values(by="w1", ascending=False, inplace=True)
df1['if_pay'] = abs(np.sort(-s1))
df1_temp = df1.groupby(['ch', 'level', 'gender'])['if_pay'].agg(['count', 'sum']).reset_index()
df1_temp.columns = ['ch', 'level', 'gender', 'users', 'pays']
df1_temp['mon'] = '1月'# 构造对照期数据
np.random.seed(10)
u2 = 1100
uc = choice(ch, size=u2, p=[0.5, 0.25, 0.2, 0.05]) # 提高BC样本量
ul = choice(level, size=u2, p=[0.7, 0.2, 0.1])
ug = choice(gender, size=u2, p=[0.6, 0.4])
s_rate2 = 0.5
s2 = np.random.binomial(1, s_rate2, u2)
# 自定义权重
w21 = {'A':3,'B':1,'C':2,'D':3
}# 提高L1、L2权重
w22 = {'l1':1,'l2':3,'l3':0
}# 提高F权重
w23 = {'F':0,'M':3
}df2 = pd.DataFrame(columns=['ch', 'level', 'gender'])
df2['ch'], df2['level'], df2['gender'] = uc, ul, ug
df2['w2'] = df2.apply(lambda x: rand_weight(w21[x['ch']])+rand_weight(w22[x['level']])+rand_weight(w23[x['gender']]), axis=1)
df2.sort_values(by="w2", ascending=False, inplace=True)
df2['if_pay'] = abs(np.sort(-s2))
df2_temp = df2.groupby(['ch', 'level', 'gender'])['if_pay'].agg(['count', 'sum']).reset_index()
df2_temp.columns = ['ch', 'level', 'gender', 'users', 'pays']
df2_temp['mon'] = '2月'# 拼接数据
df_result = pd.concat([df1_temp, df2_temp])

衡量两样本的维度差异有很多方法,例如KS检验、相对熵,但大多数的目标变量是连续值。由于只是简单的考虑各维度变化的波动大小,所以这里采用计算变化值的方差衡量波动浮动。

def cal_s2(df, period, base_date, cont_date, X, y0, y1=None, calRate=None):'''df:数据集,只包含两期数据period:日期字段base_date:基期时间cont_date:对照期时间X:维度列y0:指标列-分子y1:指标列-分母'''df=df.copy()# 构造基期与对照期数据集df_base=df[df[period]==base_date]df_cont=df[df[period]==cont_date]# 计算波动值的方差s2=[]for j in X:if calRate:df_change=(df_cont.groupby(j)[y0].sum()/df_cont.groupby(j)[y1].sum())-(df_base.groupby(j)[y0].sum()/df_base.groupby(j)[y1].sum())else:df_change=df_cont.groupby(j)[y0].sum()-df_base.groupby(j)[y0].sum()s2.append(np.var(df_change))# 导出dfdf_result=pd.DataFrame(s2, index=X, columns=['s2']).sort_values(by='s2', ascending=False)return df_result
period='mon'
base_date='1月'
cont_date='2月'
X=['ch', 'level', 'gender']
y0='pays'
y1='users'# 计算各维度销售额方差
print(cal_s2(df_result, period, base_date, cont_date, X, y0=y1))
# 计算各维度购买率方差
print(cal_s2(df_result, period, base_date, cont_date, X, y0, y1, calRate=1))
                 s2
gender  2704.000000
ch      1762.500000
level    574.888889s2
ch      0.003322
gender  0.002216
level   0.001378

绝对值指标贡献度计算

  1. 计算目标变量y的变化 Δ y = y 1 − y 0 \Delta y=y_1-y0 Δy=y1​−y0
  2. 计算维度各取值的变化 Δ X i j = X i j 1 − X i j 0 \Delta X_{ij} = X_{ij1}-X_{ij0} ΔXij​=Xij1​−Xij0​,其中i表示第i个维度,j表示该维度下的第j个取值
  3. 计算贡献度 C o n t r i b u t e X i j = Δ X i j / Δ y Contribute_{X_ij}=\Delta X_{ij}/\Delta y ContributeXi​j​=ΔXij​/Δy
def cal_abs_contribute(df, period, base_date, cont_date, X, y):'''df:数据集,只包含两期数据period:日期字段base_date:基期时间cont_date:对照期时间X:维度列y:指标列'''df=df.copy()# 构造基期与对照期数据集df_base=df[df[period]==base_date]df_cont=df[df[period]==cont_date]# 计算整体变化all_change=df_cont[y].sum()-df_base[y].sum()# 计算所有组合的贡献度df_contribute=pd.DataFrame(columns=['contribute', 'dim_value', 'dim_name', 'dim', 'base', 'change', 'all_base', 'all_change'])for i in range(len(X)):comb=itertools.combinations(X, i+1)for j in comb:# 计算贡献值dc=df_cont.groupby(list(j))[y].sum()-df_base.groupby(list(j))[y].sum()# 计算贡献百分比dr=dc/all_changedf_temp=pd.DataFrame(dr).reset_index(drop=True)df_temp['dim_value'] = dr.indexdf_temp['dim_name']=str(dr.index.names)df_temp['dim']=i+1df_temp['base']=df_base.groupby(list(j))[y].sum().valuesdf_temp['change']=dc.valuesdf_temp['all_base']=df_base[y].sum()df_temp['all_change']=all_changedf_temp.columns=['contribute', 'dim_value', 'dim_name', 'dim', 'base', 'change', 'all_base', 'all_change']df_contribute=df_contribute.append(df_temp)df_result=df_contribute[['dim', 'dim_name', 'dim_value', 'base', 'all_base', 'change', 'all_change', 'contribute']]return df_result
period='mon'
base_date='1月'
cont_date='2月'
X=['ch', 'level', 'gender']
y='pays'
cal_abs_contribute(df_result, period, base_date, cont_date, X, y).sort_values(by='contribute', ascending=False).head()

比率值指标贡献度计算

分别计算分母占比变化的贡献和指标变化的贡献,具体见下面的代码(这个公式写起来有点繁琐…)。

def cal_rate_contribute(df, period, base_date, cont_date, X, y0, y1):'''df:数据集,只包含两期数据period:日期字段base_date:基期时间cont_date:对照期时间X:维度列y0:指标列-分子y1:指标列-分母'''df=df.copy()# 构造基期与对照期数据集df_base=df[df[period]==base_date]df_cont=df[df[period]==cont_date]# 计算指标基期、本期整体数据all_base=df_base[y0].sum()/df_base[y1].sum()all_cont=df_cont[y0].sum()/df_cont[y1].sum()# 计算整体变化all_change=all_cont-all_base# 计算所有组合的贡献度df_contribute=pd.DataFrame(columns=['contribute', 'dim_value', 'dim_name', 'dim', 'metric_base', 'rate_base', 'all_base', 'metric_change','rate_change', 'all_change', 'metric_contribute', 'rate_contribute'])for i in range(len(X)):comb=itertools.combinations(X, i+1)for j in comb:# 1、计算占比变化# 计算分母基期、本期数量df_y1_base=df_base.groupby(list(j))[y1].sum()df_y1_cont=df_cont.groupby(list(j))[y1].sum()# 计算分母基期、本期占比df_rate_base=df_y1_base/df_base[y1].sum()df_rate_cont=df_y1_cont/df_cont[y1].sum()# 计算占比变化df_rate_change=df_rate_cont-df_rate_base# 2、计算指标变化# 计算指标基期、本期数值df_metric_base=df_base.groupby(list(j))[y0].sum()/df_base.groupby(list(j))[y1].sum()df_metric_cont=df_cont.groupby(list(j))[y0].sum()/df_cont.groupby(list(j))[y1].sum()# 计算指标变化df_metric_change=df_metric_cont-df_metric_base# 计算指标变化贡献df_metric_contribute=df_metric_change*df_rate_base# 计算占比变化贡献df_rate_contribute=df_rate_change*(df_metric_cont-all_base)# 计算整体贡献值dc=(df_metric_contribute+df_rate_contribute)# 计算整体贡献百分比dr=dc/all_changedf_temp=pd.DataFrame(dr).reset_index(drop=True)df_temp['dim_value'] = dr.indexdf_temp['dim_name']=str(dr.index.names)df_temp['dim']=i+1df_temp['metric_base']=df_metric_base.valuesdf_temp['rate_base']=df_rate_base.valuesdf_temp['all_base']=all_basedf_temp['metric_change']=df_metric_change.valuesdf_temp['rate_change']=df_rate_change.valuesdf_temp['all_change']=all_changedf_temp['metric_contribute']=df_metric_contribute.valuesdf_temp['rate_contribute']=df_rate_contribute.valuesdf_temp.columns=['contribute', 'dim_value', 'dim_name', 'dim', 'metric_base', 'rate_base', 'all_base', 'metric_change','rate_change', 'all_change', 'metric_contribute', 'rate_contribute']df_contribute=df_contribute.append(df_temp)df_result=df_contribute[['dim', 'dim_name', 'dim_value', 'metric_base', 'rate_base', 'all_base', 'metric_change','rate_change', 'all_change', 'metric_contribute', 'rate_contribute', 'contribute']]return df_result
period='mon'
base_date='1月'
cont_date='2月'
X=['ch', 'level', 'gender']
y0='pays'
y1='users'
cal_rate_contribute(df_result, period, base_date, cont_date, X, y0, y1).sort_values(by='contribute', ascending=False).head()

异动分析(四)利用Python计算指标贡献度相关推荐

  1. 异动分析技术解决方案—异动归因之指标拆解

    简介:归因的方法有多种,这篇文章的重点是指标拆解,也是我们做业务分析时最常用到的方法.我们的目的是解放人力,将指标拆解实现自动化,一方面可以加快业务迭代速度,快速定位问题:另一方面可以对可能产生异动的 ...

  2. 【业务理解】指标异动分析

    作者:木兮 来源:木木自由公众号 这是加薪的第七篇推文,关于数据分析思维-数据指标异动分析.在日常生活工作中,我们经常会遇到"产品XX数据指标出现异常波动,或上升或下跌"的问题,X ...

  3. 数据分析思维|数据指标异动分析

    这是加薪的第七篇推文,关于数据分析思维-数据指标异动分析.在日常生活工作中,我们经常会遇到"产品XX数据指标出现异常波动,或上升或下跌"的问题,XX指标包括但不限于日活.次日留存率 ...

  4. 异动分析--基础指标监控及查因思路

    一.用户规模 dau 新用户 新户的情况较为简单 渠道投放,渠道的用户信息情况占比 新户的曝光和push 二.用户留存 三.收入 总结:异动分析框架

  5. 异动分析(一)如何快速进行异常定位

    异动分析(一)如何快速进行异常定位 小P:小H,最近X(某指标)下降的有点狠啊,帮忙找找看原因呗- 小O:小H,今天Y(某指标)怎么没数据了,帮忙查查呗,急- 小H:- 相信大家对这些话应该很熟悉吧, ...

  6. python ks值计算_利用Python计算KS的实例详解

    在金融领域中,我们的y值和预测得到的违约概率刚好是两个分布未知的两个分布.好的信用风控模型一般从准确性.稳定性和可解释性来评估模型.sOf免费资源网 一般来说.好人样本的分布同坏人样本的分布应该是有很 ...

  7. 利用Python计算UDP校验和

    UDP 检验和提供了差错检测的功能.这是基于端到端原则实现的.但是 UDP 的检验和并不提供差错回复的能力. 一.UDP结构 二.UDP校验和计算方法  计算校验和的过程很关键,主要分为以下几个步骤: ...

  8. 【python】利用python计算A类不确定度

    利用python计算A类不确定度 前言 在上学期大学物理实验课的时候发现经常要计算A类不确定度,而且这个不确定度计算又非常复杂,凑巧当时正在学习python,于是利用python实现了这一小小功能. ...

  9. 【数据应用案例】异动分析——指标逻辑树

    案例来源:@美团技术博客 案例地址:https://zhuanlan.zhihu.com/p/31676443 1. 目标:在BI实践中,快速定位到使某个业务指标发生异动的因素,并对该因素进行细分维度 ...

最新文章

  1. 简明现代魔法博客图书馆之php学习记录
  2. RGBD-SLAM 深度摄像机资料介绍
  3. 又是一个程序员粗心的代码引起频繁FullGC的案例
  4. java display.getdefault()_java基础(十一 )-----反射——Java高级开发必须懂的
  5. ConcurrentHashMap深入分析
  6. 利用Topshelf把.NET Core Generic Host管理的应用程序部署为Windows服务
  7. mysql报4934_mysql-Mariadb语法错误1064(42000)
  8. 20190719算法题存档
  9. 一个导出类的内部函数的dll
  10. 豆瓣评分9.9!国内外口碑炸裂的强化学习圣经中文版终于来了!
  11. 《深入浅出MFC》 第二版中文
  12. 数据分析中会常犯哪些错误,如何解决? 六
  13. 常用 ASCII 码整理
  14. docker mysql 镜像 下载_docker mysql 镜像下载
  15. python如何退出虚拟环境_python 虚拟环境
  16. 贷款用户逾期问题Task1
  17. 派安盈Payoneer要年费吗?
  18. 解决mkimage command not found - U-Boot images will not be buil
  19. 软件测试面试宝典(2022面试预测)——软件测试大厂试题
  20. 【台大郭彦甫】Matlab入门教程超详细学习笔记六:高阶绘图(附PPT链接)

热门文章

  1. 数据结构之折半查找法(Binary Search)
  2. CSS3--其他新增属性
  3. Web渗透实例复现(一)(通达OA11.2)
  4. 阿里P8架构师耗时三年总结:Java春招高频面试题库
  5. 【人工智能】揭秘华为云EI:华为人工智能发展路线与BAT大不相同
  6. 【论文泛读80】通过滚动交互预测文本可读性
  7. 夺神之权服务器维护,流放之路3月28日夺神之权停服更新介绍
  8. kingdee漏洞金蝶EAS存在命令执行漏洞
  9. 访问Google首页显示该页无法显示
  10. 在Vue项目中使用jsencrypt.js对数据进行加密传输