业务相关--vintage

article/2025/9/4 16:06:47

vintage整理

--------仅用于个人学习知识整理和sas/R语言/python代码整理


####1 . 前言
Vintage表,将不同时间层面的顾客拉平到同一时间周期上进行比较,观察不同入口时间的顾客在不同生命周期上的表现。
vintage一般有三种用法:
1.横看:得到同一时间入口的顾客,在不同生命周期上回来购买的表现
2.竖看:不同时间入口客人质量的差别
3.斜看:可以直观地看出不同时期公司的营销活动的效果

下图是一个实例(以下数字为模拟数据)
在这里插入图片描述

2. 代码分享

2.1 大促期间顾客vintage

需求:需要分新客的入口产品统计,首单购买后的mob时间段内,二回的人数,花费等指标
注意点:
2.1.1. 这里多了一个大促时间段内回柜的概念(mob0.5),以及mob1及之后的时间判定是以大促结束时间求间隔的
2.1.2. 二回的定义会有修改:因为给品牌做的目标是提升新客二回,在看二回的时候,只想看二回的时间段-----所以就只看顾客第一次及第二次回来的交易

def vintage(promotion_start,promotion_end,sales_start,sales_end,repeat_flag):###加一步判断 要算回来一次即可还是算多次if repeat_flag=='repeat_once':trans_cus=trans_cus_raw\.join(first_date,['md5'],'left')\.withColumn('first_purchase_date',when(col('mindate_fromtrans')<col('first_purchase_date'),col('mindate_fromtrans')).\otherwise(col('first_purchase_date')))\.withColumn('rnk',dense_rank().over(Window.partitionBy('md5').orderBy('purchase_date')))\.where(col('rnk')<=2)else:trans_cus=trans_cus_raw\.join(first_date,['md5'],'left')\.withColumn('first_purchase_date',when(col('mindate_fromtrans')<col('first_purchase_date'),col('mindate_fromtrans')).otherwise(col('first_purchase_date')))#########销售占比大于1%sales_per=trans_cus\.where(col('purchase_date').between(sales_start,sales_end))\.groupBy('productname_std').agg(sum('amount').alias('sales'))\.withColumn('sales0',sum('sales').over(Window.partitionBy().orderBy()))\.withColumn('per',col('sales')/col('sales0')).where(col('per')>=0.01)\.agg(collect_set('productname_std')).collect()[0][0]###首单 及 购买产品first_pur=trans_cus\.where(col('purchase_date')==col('first_purchase_date'))\.where(col('first_purchase_date').between(promotion_start,promotion_end))\.groupBy('md5','productname_std').count().drop('count').where(col('productname_std').isin(sales_per))###匹配trans 计算mob ###在大促时间内回柜的人 记为0.5mob_trans=trans_cus\.groupBy('md5','purchase_date','first_purchase_date')\.agg(sum('amount').alias('amount'),sum('quantity').alias('quantity'))\.join(first_pur,['md5'],'inner')\.withColumn('mob_raw',floor(datediff(col('purchase_date'),lit(promotion_end))/7))\.withColumn('mob',when((col('mob_raw')<=0) & (col('purchase_date')==col('first_purchase_date')),0)\.otherwise(when((col('mob_raw')<=0) & (col('purchase_date')<=promotion_end),0.5).otherwise(col('mob_raw')+lit(1))))\.withColumn('promotion_end',lit(promotion_end))\.withColumn('period_start',when(col('mob')<1,promotion_start).otherwise(expr('date_add(promotion_end,7*(mob-1))')))\.withColumn('period_end',when(col('mob')<1,promotion_end).otherwise(expr('date_add(promotion_end,7*(mob))')))
2.2 正常vintage的变种

需求的更改:
2.2.1. mob月份算的是自然月/ 差额周
2.2.2. 计算二回的时候 回来一次还是回来多次

def vintage(repeat_flag,time_flag):
###加一步判断 要算回来一次即可还是算多次if repeat_flag=='repeat_once':trans_input=trans_input\.withColumn('rnk',dense_rank().over(Window.partitionBy('md5').orderBy('purchase_date')))\.where(col('rnk')<=2)\.withColumn('first_purchase_date',col('first_purchase_date').cast('date'))\.withColumn('purchase_year',year(col('purchase_date')))\.withColumn('purchase_month',month(col('purchase_date')))\.withColumn('first_year',year(col('first_purchase_date')))\.withColumn('first_month',month(col('first_purchase_date')))else:trans_input=trans_input\.withColumn('first_purchase_date',col('first_purchase_date').cast('date'))\.withColumn('purchase_year',year(col('purchase_date')))\.withColumn('purchase_month',month(col('purchase_date')))\.withColumn('first_year',year(col('first_purchase_date')))\.withColumn('first_month',month(col('first_purchase_date')))###自然月/mob差额月if time_flag='natural':total = trans_input\.withColumn('mob_months',12*(col('purchase_year')-col('first_year'))+col('purchase_month')-col('first_month'))\.withColumn('mob_months',when((col('purchase_date')==col('first_purchase_date')) & (col('rnk')==1),0).\otherwise(when((col('mob_months')==0) & (col('rnk')==2),0.5).otherwise(col('mob_months'))))\.withColumn('firstmonth',substring('first_purchase_date',1,7))else:####这里如果是mob 月 下边除以7应该改为30total = trans_cus\.withColumn('first_purchase_date',col('first_purchase_date').cast('date'))\.withColumn('mob_months',floor(datediff(col('purchase_date'),col('first_purchase_date'))/7))\.withColumn('mob_months',when((col('purchase_date')==col('first_purchase_date')) & (col('rnk')==1),0).\otherwise(when((col('mob_months')==0) & (col('rnk')==2),0.5).otherwise(col('mob_months'))))\.withColumn('firstmonth',substring('first_purchase_date',1,7))
2.3 基于2.1入口产品的修改

需求的更改:
2.3.1. 入口产品是一个集合,计算这个集合进来的顾客的回柜

trans_cus=trans_cus_raw\
.join(first_date,['md5'],'left')\
.withColumn('first_purchase_date',when(col('mindate_fromtrans')<col('first_purchase_date'),col('mindate_fromtrans')).\otherwise(col('first_purchase_date')))\
.withColumn('rnk',dense_rank().over(Window.partitionBy('md5').orderBy('purchase_date')))\
.where(col('rnk')<=2)
######
###销售占比大于1%
sales_per=trans_cus\.where(col('productname_std').rlike('防晒乳'))\.groupBy('productname_std').agg(sum('amount').alias('sales'))\.withColumn('sales0',sum('sales').over(Window.partitionBy().orderBy()))\.withColumn('per',col('sales')/col('sales0')).where(col('per')>=0.01)\.agg(collect_set('productname_std')).collect()[0][0]###首单 及 购买产品
first_pur=trans_cus\.where(col('productname_std').isin(sales_per))\.where(col('purchase_date')==col('first_purchase_date'))\.groupBy('md5').count().drop('count')###匹配trans 计算mob 
###在大促时间内回柜的人 记为0.5
mob_trans=trans_cus\.groupBy('md5','purchase_date','first_purchase_date')\.agg(sum('amount').alias('amount'),sum('quantity').alias('quantity'))\.join(first_pur,['md5'],'inner')\.withColumn('mob',floor(datediff(col('purchase_date'),col('first_purchase_date'))/30))\.withColumn('firstmonth',substring('first_purchase_date',1,7))
2.4 变种2 mob改为一年内的自然周

需求的更改:
2.4.1. mob月份算的是自然周—主要用到了weekofyear
2.4.2 入口月份变为自然周

###### mob变成自然周
trans_raw=spark.read.parquet(trans_path2)\.where(col('cut')!='中小样')\.where(col('flag')==1).where(col('group_sale')==0)\.withColumn('week',weekofyear('purchase_date'))week_add=trans_raw\.groupBy('purchase_year','purchase_month','week')\.count().drop('count')\.withColumn('purchase_week',when((col('week')==52) & (col('purchase_month')==1),0).otherwise(col('week')))\.withColumn('purchase_week',when((col('week')==1) & (col('purchase_month')==12),53).otherwise(col('purchase_week')))\.withColumn('lag_week',lag('purchase_week').over(Window.partitionBy().orderBy('purchase_year','purchase_month','purchase_week')))\.withColumn('week_diff',when(-col('lag_week')+col('purchase_week')==-51,1).\otherwise(when(-col('lag_week')+col('purchase_week')==-52,0).otherwise(-col('lag_week')+col('purchase_week')))).fillna(1)\.orderBy('purchase_year','purchase_month','purchase_week')\.withColumn('purchase_week1',sum('week_diff').over(Window.orderBy('purchase_year','purchase_month','purchase_week').rangeBetween(Window.unboundedPreceding,0)))trans_raw=trans_raw\.join(week_add,['purchase_year','purchase_month','week'],'left')###人天销售大于0
cus_raw=trans_raw\.groupBy('customer_id','purchase_year','purchase_month','purchase_week1','purchase_date','first_purchase_date','productname_std')\.agg(sum('amount').alias('amount'),sum('quantity').alias('quantity'))\.withColumn('sales0',sum('amount').over(Window.partitionBy('customer_id','purchase_date').orderBy('customer_id')))\.where(col('sales0')>0)first_date=cus_raw\.groupBy('customer_id')\.agg(min('purchase_date').alias('mindate_fromtrans'))cus=cus_raw\.join(first_date,['customer_id'],'left')\.withColumn('first_purchase_date',when(col('mindate_fromtrans')<col('first_purchase_date'),col('mindate_fromtrans')).otherwise(col('first_purchase_date')))###trans首单时间
cus=cus\.withColumn('rnk',dense_rank().over(Window.partitionBy('customer_id').orderBy('purchase_date')))\
#   .where(col('rnk')<=2)total = cus\.withColumn('first_purchase_date',col('first_purchase_date').cast('date'))\.withColumn('first_year',year(col('first_purchase_date')))\.withColumn('first_month',month(col('first_purchase_date')))\.withColumn('first_week',weekofyear(col('first_purchase_date')))\.join(week_add.selectExpr('purchase_year as first_year','purchase_month as first_month','week as first_week','purchase_week1 as first_week1'),['first_year','first_month','first_week'],'left')\.where(col('first_purchase_date')>='2018-01-01')\.where(~col('first_week1').isNull())\.withColumn('mob_weeks',col('purchase_week1')-col('first_week1'))\.withColumn('mob_weeks',when((col('purchase_date')==col('first_purchase_date')) & (col('rnk')==1),0).\otherwise(when((col('mob_weeks')==0) & (col('rnk')==2),0.5).otherwise(col('mob_weeks'))))\.withColumn('firstweek',col('first_week1'))summary=total\.groupBy('mob_weeks','firstweek')\.agg(countDistinct('customer_id').alias('cnt'),sum('amount').alias('sales'),sum('quantity').alias('quantity'),max('purchase_date').alias('max_mobdate'),min('purchase_date').alias('min_mobdate'))

http://chatgpt.dhexx.cn/article/UAgsywN8.shtml

相关文章

vintage分析 风控建模系列 01

vintage分析 风控建模系列 01 在工作中发现&#xff0c;目前没有一个很好的系列帖子对风控建模中的各项细节做讲解&#xff0c;本人为一个金融科技公司的风控算法建模师&#xff0c;希望在此将风控建模的知识成体系、有深度、易吸收地分享给大家 vintage分析价值 在一场完整…

使用R语言creditmodel包进行Vintage分析或留存率分析

1 什么是vintage分析&#xff1f; Vintage分析&#xff08;账龄分析法&#xff09;被广泛应用于信用卡及信贷行业&#xff0c;这个概念起源于葡萄酒&#xff0c;即不同年份出产的葡萄酒的品质有差异&#xff0c;那么不同时期开户或者放款的资产质量也有差异&#xff0c;其核心…

Vintage分析和迁移率模型在网贷行业的运用

Vintage 分析和迁移率模型在网贷行业的运用 网贷业务的核心竞争力来自收益与风险之间平衡点的把握&#xff0c;其收到消费理念、市场策略、市场消费环节影响&#xff0c;贯穿于产品设计、营销审批、授信、支用、还款、催收以及客户服务的全过程。风控偏好和市场竞争策略会导致不…

一文彻底理解评分卡开发中——Y的确定(Vintage分析、滚动率分析等)

评分卡已经在各大银行和公司都实际运用于业务&#xff0c;也有很多前辈对它进行了详细的阐述。本文将从支付和信贷评分卡建立的角度&#xff0c;对比分析不同行业在建立评分卡时因变量Y确定的差异。让想了解评分卡的小伙伴&#xff0c;有一个更深刻的理解。并能举一反三&#x…

vintage的一点深入思考

vintage是资产质量分析中常用的指标&#xff0c;网上也有很多介绍vintage的含义、计算方法以及用法的文章。最近结合业务中的一个实际问题&#xff0c;对vintage曲线有了一些新的思考&#xff0c;所以写下来记录一下。 目录 1.业务问题 2.原因分析 3.总结 一、业务问题 业务的发…

ML之FE:Vintage曲线/Vintage分析(观察用户的全周期风险情况/明确用户风险的成熟期/确定逾期率何时趋向于稳定/从而选择合适的表现期)的简介、计算逻辑、案例应用之详细攻略

ML之FE&#xff1a;Vintage曲线/Vintage分析(观察用户的全周期风险情况/明确用户风险的成熟期/确定逾期率何时趋向于稳定/从而选择合适的表现期)的简介、计算逻辑、案例应用之详细攻略 目录 Vintage曲线简介—通过葡萄酒产业理解Vintage曲线 (1)、Vintage来源 (2)、Vintage曲…

vintage分析

vintage分析的由来 由于酿酒业&#xff0c;对于葡萄酒而言&#xff0c;年份不同&#xff0c;气候不同&#xff0c;生产的葡萄酒品质也不同&#xff0c;因此酿酒业常将葡萄的采摘年份作为品质的区分。同时&#xff0c;随着葡萄酒窖藏时间的增加&#xff0c;酒的品质也会提升。因…

对Vintage分析的一些学习理解

账龄分析&#xff08;Vintage Analysis&#xff09; 我目前工作主要是信贷业务相关的数据分析及算法构建&#xff0c;所以经常会接触到信贷风险管理分析方法&#xff0c;常见的包括账龄分析&#xff08;Vintage Analysis&#xff09;、滚动率分析&#xff08;Roll Rate Analys…

ACM学习经验

首先可以说&#xff0c;在我认识的顶尖的 ACMer 中&#xff0c;很多人走的都不是在 OJ 盲目刷题的路。&#xff08;当然也有特例&#xff0c;前提是他们的某方面基础或智商本身已经达到很高的水平。&#xff09;不盲目刷题&#xff0c;我想原因也很简单&#xff0c;OJ 题目质量…

如何进行算法比赛 (持续更新)ACMER

由数据范围反推算法复杂度以及算法内容 - AcWing 1.关于时间复杂度的分析y总的总结 变量要进行初始化否则会坑你一把 还有变量的命名要注意 https://www.acwing.com/blog/content/32/ 有时候n的范围很大&#xff0c;但是a[i]的范围很小就可以预处理 2.首先一些奇奇怪怪的方法…

关于ACMers

ACMers那些事 ACM是什么&#xff1f;能吃吗&#xff1f; 我们所说的ACM竞赛&#xff0c;通常指的是国际大学生程序设计竞赛&#xff08;International Collegiate Programming Contest&#xff0c;ICPC&#xff09;&#xff0c;ACM只是主办方的名字&#xff08;国际计算机协会…

一个合格的ACMer的代码当中,都藏着哪些秘密?

作者 | 梁唐 责编 | 欧阳姝黎 今天给大家聊聊C中的头文件&#xff0c;之前我在写算法专题展示源代码的时候&#xff0c;很多小伙伴给我留言说被我的头文件中的内容震惊了。其实之所以我的头文件这么复杂&#xff0c;完全是因为它是我一直从大学时期acm竞赛当中沿用下来的…

ACM模板(从小白到ACMer的学习笔记)

写在开头&#xff1a; 2020年ICPC银川站&#xff0c;现场赛&#xff0c;第三题的字典树没能过&#xff0c;首站打铁&#xff0c;不过这一场也让我看到铜牌其实没有想象中的那么难。 2020年ICPC沈阳站&#xff0c;现场赛&#xff0c;封榜后过两题&#xff0c;铜首&#xff0c;I题…

【转】 如何提高自己的acm个人能力

转载自 简单de数字 最终编辑 fading_code by zfy0701 本来以为HNU的huicpc035和我一样退役了&#xff0c;后来听说他组成了新的footman队&#xff0c;于是又关注了下他。 035体现了两个我觉得非常重要的品质&#xff1a; 1、刻苦的训练 2、有效的训练 &#xff08;本文将主…

ACMer必看的基础算法(附经典例题)

文章目录 一、排序算法1.冒泡排序2.选择排序3.快速排序4.桶排序 二、递归算法三、递推算法四、贪心算法五、动态规划基本模型区间dp背包问题01背包完全背包多重背包 六、分治算法二分三分 七、补充STL的简单应用结构体 一、排序算法 1.冒泡排序 【基本思想】 基本思想为两两比…

反向代理与正向代理区别

正向代理与反向代理的区别 正向代理是客户端与正向代理客户端在同一局域网&#xff0c;客户端发出请求&#xff0c;正向代理 替代客户端向服务器发出请求。服务器不知道谁是真正的客户端&#xff0c;正向代理隐藏了真实的请求客户端。 反向代理&#xff1a;服务器与反向代理在同…

Nginx反向代理与正向代理配置

一、Nginx主要功能 1、Nginx 简介 Nginx是一款轻量级的Web 服务器 、反向代理服务器及电子邮件(IMAP/POP3)代理服务器。主要有反向代理,负载均衡等功能。 官方网站:nginx news Nginx是一款免费开源的高性能 HTTP 代理服务器及反向代理服务器(Reverse Proxy)产品,它高…

如何解释反向代理与正向代理

概念 首先看看说明图&#xff0c;先有一个整体的理解。 正向代理&#xff08; Forward Proxy &#xff09;&#xff1a; 是指是一个位于客户端和原始服务器之间的服务器&#xff0c;为了从原始服务器取得内容&#xff0c; 客户端向代理发送一个请求并指定目标(原始服务器)&am…

反向代理设置

折腾家庭服务器&#xff0c;因只有一个公网ip&#xff0c;还要尝试设置私有云&#xff0c;博客&#xff0c;论坛&#xff0c;以及练习flask编程&#xff0c;又不想写各种端口访问&#xff0c;计划采取的方案是设置一个反向代理&#xff0c;使用子域名访问各个服务。 一、什么是…

知识积累3:什么是反向代理,如何区别反向与正向代理

一直对反射代理的反向不知道如何理解&#xff0c;经过百度知道&#xff0c;再结合下面这幅图&#xff0c;总算弄清楚一点了。简单的说从一个局域网出来到服务端为正向&#xff0c;从客户端要进入一个局域网为反向 概念&#xff1a; 反向代理&#xff08;Reverse Proxy&#xf…