一、单变量分析——用户首逾率增高问题
二、用户群组分析——对相同生命周期阶段的用户进行垂直分析
三、用户行为路径漏斗转化分析
一、单变量分析——用户首逾率增高问题
单变量分析:
单变量分析的目的是,通过对数据的整理、加工、组织和展示,并计算反应数据的集中趋势和离散程度的指标,对变量分布的特征和规律进行刻画和描述。不同类型的变量需要使用不同的方法和指标。
单变量分析又称“单变量统计分析”,就是在一个时间点上对某一变量所进行的描述和统计,因而又可以分为单变量描述统计和单变量推论统计两种方式。
1.案例背景
日常监控发现某款消费贷产品首逾率有逐渐升高的趋势,需要把首逾率降下来以减少产品带来的损失。
2.分析目标及思路
● 分析目标:通过数据探查分析制定出可以有效降低首逾率的策略。
● 分析思路:分析的策略是在客户申请时用来判断客户是否会逾期的条件,所以需要还原这些有首逾表现的客户在申请时的数据,即提取出客户在申请时点各个维度的数据,然后利用这些数据去找出能够区分好坏客户的变量,从而制定策略。
3.数据加工
观察原数据,并对列名进行更改,方便理解。最终所得数据(部分)如下:
3.1 计算首逾率
# 计算总体首逾率 = 首逾客户数/总申请客户数
dt['是否逾期(1是,0否)'].sum()/dt.shape[0] #因为逾期是1,未逾期是0,所以求出来的和就是逾期的人数。
计算得到首逾率约为0.3076,属于过高的情况。下面将采取单变量分析法,从不同维度去分析,寻找解决方法。
3.2 筛选出有效变量
3.2.1 征信查询次数
# 定义一个信用评级分组的函数
# 定义一个征信分组的函数
def judge_zhengxin(nums):
try:
nums=int(nums)
if 0<= nums <3:
return '1:[0,3)'
elif 3<= nums <6:
return '2:[3,6)'
elif 6<= nums <12:
return '3:[6,12)'
elif 12<= nums <21:
return '4:[12,21)'
elif 21<=nums:
return '5:[21,无穷)'
except Exception as e:
return "6:缺失"
# 新建一个字段记录分组信息
dt['征信分组']=dt['近半年征信查询次数'].apply(judge_zhengxin)
# 分组统计各个分组的情况
# 区间用户占比、未逾期客户数要另外计算
dt_info=dt.groupby('征信分组').agg({'用户id':'count',
'是否逾期(1是,0否)':'sum'}).reset_index().rename(columns={'用户id':'区间客户数',
'是否逾期(1是,0否)':'区间逾期客户数'})
# 区间用户占比、未逾期客户数要另外计算
dt_info['区间用户占比']=dt_info['区间客户数']/dt_info['区间客户数'].sum()
dt_info['区间没有逾期客户数']=dt_info['区间客户数'] - dt_info['区间逾期客户数']
dt_info['区间首逾率']=dt_info['区间逾期客户数']/dt_info['区间客户数']
dt_info
所得结果如下:
由上图可以看出:
● 约80.51%的用户征信查询次数在12次以上;
● 首逾率与征信查询次数呈正相关的趋势:随着征信查询次数的不断增加,首逾率也呈现升高的趋势,且征信查询次数超过21次时,首逾率此时达到最高,约为59.85%。
3.2.2 信用评级分组
将信用评级划分为5个分组:AA、A、BCD、ERC、缺失,并进行聚合统计。
# 定义一个信用评级分组的函数
def judge_pingji(level):
if level == 'A':
return 'A'
elif level == 'AA':
return 'AA'
elif level in ('B','C','D'):
return 'BCD'
elif level in ('E','HR','NC'):
return 'ERC'
else:
return '缺失'
# 添加一列‘信用评级分组’
dt['信用评级分组']=dt['信用评级'].apply(judge_pingji)
# 分组统计各个分组的情况
dt_info2=dt.groupby('信用评级分组').agg({
'用户id':'count',
'是否逾期(1是,0否)':'sum'}).reset_index().rename(columns={'用户id':'区间客户数',
'是否逾期(1是,0否)':'区间逾期客户数'})
# 区间用户占比、未逾期客户数要另外计算
dt_info2['区间用户占比']=dt_info2['区间客户数']/dt_info2['区间客户数'].sum()
dt_info2['区间没有逾期客户数']=dt_info2['区间客户数']-dt_info2['区间逾期客户数']
dt_info2['区间首逾率']=dt_info2['区间逾期客户数']/dt_info2['区间客户数']
所得结果如下:
● 除去缺失字段,客户占比最高的是评级为BCD的用户,其次为ERC,整体用户评级偏低;
● 首逾率与评级档次呈正相关,其中ERC评级用户首逾率最高达到52.74%左右,其次为BCD评级用户首逾率在36.27%。
3.2.2 计算提升度
进行变量分析之后,这时我们就要从中筛选中较为有效的变量了,这里涉及到一个衡量变量是否有效的指标,提升度。
提升度:通俗的来说就是衡量拒绝最坏那一部分的客户之后,对整体的风险控制的提升效果。 提升度越高,说明该变量可以更有效的区分好坏客户,能够更少的误拒好客户。
计算公式:提升度=最坏分箱的首逾客户占总首逾客户的比例 /该分箱的区间客户数占比。
例如:上表中征信总查询次数的最坏分箱提升度就是(1923/17365)/(3213/56456)=11%/5.69%=1.93 提升度这个指标一般来说都是用来一批变量分析里做相对比较,很多时候都是在有限的变量里尽可能选提升度更高的变量来做策略。
分别计算征信总查询次数和客户信用评级的提升度:
征信总查询次数提升度
# 计算征信总查询次数最坏分箱的首逾客户占总首逾客户的比例。
bad_rate=dt_info.iloc[dt_info['区间首逾率'].idxmax()]['区间逾期客户数']/dt_info['区间逾期客户数'].sum()
# 计算该分箱的区间客户数占比
num_rate=dt_info.iloc[dt_info['区间首逾率'].idxmax()]['区间客户数']/dt_info['区间客户数'].sum()
# 计算提升度
bad_rate/num_rate
最终结果为1.9458。
信用评级提升度
bad_rate2=dt_info2.iloc[dt_info2['区间首逾率'].idxmax()]['区间逾期客户数']/dt_info2['区间逾期客户数'].sum()
num_rate2=dt_info2.iloc[dt_info2['区间首逾率'].idxmax()]['区间客户数']/dt_info2['区间客户数'].sum()
bad_rate2/num_rate2
最终结果为1.7147。
3.3 解决方案
在上文中, 通过上一步的单变量分析,我们筛出了“征信查询次数”、“信用评级”这两个提升度最高的变量。所以选择将其最坏分箱的人全部拒绝,计算提出后的首逾率降幅为多少。(这个影响就是指假设我们将‘征信总查询次数>=21的3213位客户全部拒绝’之后,剩下的客户逾期率相比拒绝之前的逾期率降幅是多少)
# 对征信分组的数据
# 排除最坏分箱后的逾期客户数
new_yuqi_nums=dt_info['区间逾期客户数'].sum() - dt_info.iloc[dt_info['区间首逾率'].idxmax()]['区间逾期客户数']
# 排除后的新逾期率
new_yuqi_rate=new_yuqi_nums/dt_info['区间客户数'].sum()
new_yuqi_rate
# 原有的逾期率
old_yuqi_rate=dt_info['区间逾期客户数'].sum()/dt_info['区间客户数'].sum()
old_yuqi_rate
# 新的逾期率下降数值
old_yuqi_rate - new_yuqi_rate
# 对评级分组的数据
new_yuqi_nums2=dt_info2['区间逾期客户数'].sum() - dt_info2.iloc[dt_info2['区间首逾率'].idxmax()]['区间逾期客户数']
# 排除后的新逾期率
new_yuqi_rate2=new_yuqi_nums2/dt_info2['区间客户数'].sum()
# 原有的逾期率
old_yuqi_rate2=dt_info2['区间逾期客户数'].sum()/dt_info2['区间客户数'].sum()
# 新的逾期率下降数值
old_yuqi_rate2 - new_yuqi_rate2
最终结果分别为“征信查询次数”:3.41%和“信用评级”:7.53%。
● 通过计算可得,通过拒绝最坏分组的客户,得到的最终首逾率分别下降了3.41%和7.53%,证明该方法确实能起到降低首逾率的效果。
二、用户群组分析——对相同生命周期阶段的用户进行垂直分析
群组分析法就是按某个特征对数据进行分组,通过分组比较,得出结论的方法。
群组分析的作用:
1.对处于相同生命周期阶段的用户进行垂直分析,从而比较得出相似群体随时间的变化。
2.通过比较不同的同期群,可以从总体上看到,应用的表现是否越来越好了。从而验证产品改进是否取得了效果。
1.案例背景
当我们在做用户分析时,会遇到这样的一个问题,一个用户使用APP时,会留下一连串的使用数据,可能是一月份的购买了1次,二月份购买了2次,三四月没有购买,五月份又购买了。也就是对于用户来说他的数据是一个时间面数据,而且不同用户的时间面是不相同的,开始时间经历时间都不一样,而如果我们分析的时候不考虑到这个因素而直接进行分析,显然是不够合理的,因为新用户和老用户经历的产品运营情况是不一样的。
那我们应该如何处理呢,这个时候就有一种分析方法,可以帮助我们在时间轴上对齐用户,这就是群组分析。
2. 分析目标及思路
通过用户的订单消费情况,对比同一月份的新用户留存率的变化趋势,以及不同时间期的新用户在同周期时的留存率情况
3. 数据加工
对数据进行观察,发现分析留存率只需要用到四个字段:
OrederId:订单编号
OrderDate:订单日期
UserId:用户编号
TotalCharges:消费金额
3.1 分组处理
# 生成一个新字段,用户订单月份(只要月份)
df['orderperiod']=df.orderdate.apply(lambda x:x.strftime('%Y-%m'))
# 设置userid为索引
df.set_index('userid',inplace=True)
# 这里的level=0表示第一层索引即userid(因为此时userid已经被设置为索引),并且每次分组之后都会形成很多个dataframe
# 按照每个用户的订单的最早时期,生成用户群组
df["cohortgroup"]=df.groupby(level=0)['orderdate'].min().apply(lambda x:x.strftime('%Y-%m'))
# 重设索引
df.reset_index(inplace=True)
# 根据用户群组和月份字段进行分组
grouped=df.groupby(['cohortgroup','orderperiod']) #1月份首次消费用户,在后续的1、2、3、4、5月的相关消费情况,所以对两列数据都要进行分组。
# 求每个用户群下每一个月份的用户数量、订单数量、购买金额
cohorts=grouped.agg({'userid':pd.Series.nunique,'orderid':pd.Series.nunique,'totalcharges':np.sum}) #因为有多个dataframe,所以用nunique和np.sum
#列重命名
cohorts.rename(columns={'userid':'totalusers','orderid':'totalorders'},inplace=True) #totalcharges无需重新命名
cohorts
orderperiod:用户消费月份
chortgroup:用户最早消费时间(出现的时间点)
3.2 计算留存率
# 把每个群组继续购买的日期字段进行改变。因为不同月份的客户,首次消费的月份也有不同(如2月份的客户,首次消费就是2月,而不是1月),所以重新编号。
def cohort_period(df):
# 给首次购买日期进行编号,第二次购买为2,第三次购买为3
df["cohortperiod"] = np.arange(len(df)) + 1 #len(df):有多少行。得到的结果命名为‘cohortperiod’。np.arange():列表函数,得到一个列表。
return df
# 注意的是apply后面传入的是一个个dataframe
cohorts = cohorts.groupby(level=0).apply(cohort_period) # level=0表示第一层索引,此时即'cohortgroup'。对该分组下的每个月进行编号。
# 得到每个群组的用户量,重新设置索引
cohorts.reset_index(inplace=True)
# 将"cohortgroup","cohortperiod"两列设为索引(level=0和level=1)。
cohorts.set_index(["cohortgroup","cohortperiod"],inplace=True)
# 得到每个群组的用户量,就是第一天的用户数据量,用作留存率的分母
cohort_group_size = cohorts["totalusers"].groupby(level=0).first()
# 计算每个群组的留存
cohorts["totalusers"].unstack(0).head() # unstack(0):对level=0的索引进行unstack操作。
# 计算留存
user_retention = cohorts["totalusers"].unstack(0).divide(cohort_group_size,axis=1).fillna(0)
3.3 总结和解决方案
● 整体用户留存率偏低,在5月就已经没有用户;
● 3、4月份的用户生命周期较短,而1、2月用户生命周期相对较长;
● 猜测可能1月、2月有活动,特别是1月份的,能够让用户的留存较高,对于此类情况的产生需要想办法增加用户留存,比如持续推出新品、进行短信营销、推出活动等。
三、用户行为路径漏斗转化分析
用户行为路径分析:用户行为路径分析是一种监测用户流向,从而统计产品使用深度的分析方法。它主要根据每位用户在App或网站中的点击行为日志,分析用户在App或网站中各个模块的流转规律与特点,挖掘用户的访问或点击模式,进而实现一些特定的业务用途,如App核心模块的到达率提升、特定用户群体的主流路径提取与浏览特征刻画,App产品设计的优化与改版等。
行为路径分析有如下作用:
1.可视化用户流向,对海量用户的行为习惯形成宏观了解。
2.定位影响转化的主次因素,使产品的优化与改进有的放矢。
1. 案例背景及目的
案例基于网络消费贷款形式,对消费贷借款进行复盘分析,增加用户借贷率。
2. 数据加工
2.1 数据观察及重命名
获取原始表格每日信息表dt_flow、用户信息表dt_check,如下所示
# 对列名进行重命名
dt_flow.rename(columns={'date':'日期',
'regist_cnt':'注册数',
'regist_rate':'访客注册率',
'active_cnt':'激活数'
},inplace=True)
dt_check.rename(columns={'ID':'用户ID',
'date':'申请日期',
'new_cus':'是否新用户(1为是,0为否)',
'lending':'是否放贷(1为是,0为否)'
},inplace=True)
2.2 计算每日申请贷款人数、审批贷款人数、放贷率
# 选取子集,将新用户和老用户分开统计每天申请贷款人数和审批放贷人数,然后计算新用户放贷率。
# 将新老用户分组
dt_check_1=dt_check[dt_check['是否新用户(1为是,0为否)']==1] # 新用户
dt_check_0=dt_check[dt_check['是否新用户(1为是,0为否)']==0] # 老用户
#对新用户数据透视计算放贷率。
pt_1=pd.pivot_table(data=dt_check_1,index='申请日期',values='是否放贷(1为是,0为否)',aggfunc=[np.sum,'count'])
# 删除指定的索引/列级别的数据。
pt_1.columns=pt_1.columns.droplevel(0)
# 改列名。由于此时列名一样,所以直接采用pt_1.columns来赋值,不用rename。
pt_1.columns=['新用户放贷数','新用户申请数']
# 增加一列为:新用户放贷率
pt_1['新用户放贷率']=pt_1['新用户放贷数']/pt_1['新用户申请数']
#重置索引
pt_1 = pt_1.reset_index()
pt_1
得到新用户表:
同理,也可以得到老用户表:
总体上来看,老用户的平均放贷率比新用户要高出许多。
2.3 计算老用户复借率
老用户定义:前一天的放款的新用户第二天继续借款就是老用户。
对存量老用户我们暂时不考虑,就看前一天贷款的人第二天是否还继续贷款,贷款的就认为是老用户复借
取新用户放贷透视表的5月前29天数据+4月30日的人(分析5月1日-5月30日的复借率)构成老客户数量,我们看这些客户是否还继续贷款。
# 先得到当月前29天的数据,得到的数据为list
old = list(pt_1["新用户放贷数"])[0:29]
# 4月30日有24个人,添加到old数据中
old.insert(0,24)
# 设置数据 data(字典)
data={'申请日期':list(pt_1["申请日期"]),'老客户数':old}
# 将data数据转换为DataFrame表格
dt_old=pd.DataFrame(data)
# 将老用户数据pt_0和dt_old拼接为一张表
pt_0_m=pd.merge(pt_0,dt_old,on=['申请日期'],how='left')
pt_0_m['老客户复借率']=pt_0_m['老用户申请数']/pt_0_m['老客户数']
pt_0_m.head()
得到复借率表和走势图:
● 从整体上看,5月复借率走势起伏不定,推测在复借率较高的时间段可能是因为营销活动的影响;
● 平均复借率约为34.72%。
2.4 计算各节点路径转化率并绘图
# pd.merge连接平台流量表,组成一张用户路径总表,计算各节点转化率。(所有表格连接起来
dt=pd.merge(dt_flow,pt_1,how='left',left_on='日期',right_on='申请日期')
dt_1=pd.merge(dt,pt_0_m,how='left',left_on='日期',right_on='申请日期')
dt_1=dt_1.drop(['申请日期_x','申请日期_y'],axis=1)
#计算转化漏斗。 计算汇总数据
# 删除‘日期’列。(因为属于日期型数据,计算时会报错)
dt_2=dt_1.drop('日期',axis=1)
#汇总求和
dt_2.loc['Row_sum'] = dt_2.apply(lambda x: x.sum())
# 将 "Row_sum"这一行这些列的数据取出来
dt_3 = dt_2[dt_2.index == "Row_sum"][["PV","UV","注册数","激活数","新用户申请数","新用户放贷数"]]
dt_3_s = pd.DataFrame(dt_3.stack()).reset_index().iloc[:,[1,2]]
dt_3_s.columns = ["指标","汇总"]
得到指标汇总图和漏斗图:
由上图可知:
● 转换率在 UV → 注册的转换率很低,需要采取针对性营销措施解决;
● 最终放贷成功率很低,可以优化继续模型,在保证资金安全的情况下提高放贷率。