案例目录:
一、单变量分析——用户首逾率增高问题
二、用户群组分析——对相同生命周期阶段的用户进行垂直分析
三、用户行为路径漏斗转化分析
一. 单变量分析——用户首逾率增高
单变量分析:
- 单变量分析的目的是,通过对数据的整理、加工、组织和展示,并计算反应数据的集中趋势和离散程度的指标,对变量分布的特征和规律进行刻画和描述。不同类型的变量需要使用不同的方法和指标。
- 单变量分析又称“单变量统计分析”,就是在一个时间点上对某一变量所进行的描述和统计,因而又可以分为单变量描述统计和单变量推论统计两种方式。
1.案例背景
日常监控数据时,发现某款消费贷产品首逾率有逐渐升高趋势,需要把首逾率降下来减少产品带来的损失。
2.分析目标
在客户申请时用来判断客户是否会逾期的条件,通过数据探查分析制定出可以有效降低首逾率的策略。
3.分析思路
在客户申请时,还原客户各个维度的数据,用单变量分析法从各个维度进行分析,找到区分好坏客户的变量,制定策略。
3.1 数据观察处理
-
对字段进行更名处理
3.2 总体逾期率情况
dt['是否逾期(1是,0否)'].sum()/dt.shape[0]
[out]:0.307584667705824
- 总体预期率达到30%,属于非常高的情况,下面需要使用单变量分析法,从各个维度单独分析,查看对预期的影响。
3.3 筛选有效变量
3.3.1 征信查询次数影响
首先对客户的征信查询次数字段进行分组,统计每个分组区间的逾期人数。
#征信查询次数分组
def judge_zhengxin(x):
try:
x = int(x)
if 0 <= x and x < 3:
return '1:[0,3)'
elif 3 <= x and x < 6:
return '2:[3,6)'
elif 6 <= x and x < 12:
return '3:[6,12)'
elif 12 <= x and x < 21:
return '4:[12,21)'
elif 21 <= x:
return '5:[21,∞)'
# 如果 x 不为int类型,则返回错误,即输出"缺失"
except Exception as e:
return '6:缺失'
# 对征信查询次数字段进行分组
dt['征信分组'] = dt['近半年征信查询次数'].apply(lambda x: judge_zhengxin(x))
# 聚合统计
dt_info_zhengxin = dt.groupby('征信分组').agg({'用户id':'count','是否逾期(1是,0否)':'sum'}).reset_index().rename(columns = {'用户id':"区间客户数","是否逾期(1是,0否)":"逾期人数"})
dt_info_zhengxin
接下来计算区间用户占比、首逾率情况:
dt_info_zhengxin['区间用户占比'] = dt_info_zhengxin['区间客户数'].div(dt_info_zhengxin['区间客户数'].sum())
dt_info_zhengxin['首逾率'] = dt_info_zhengxin['逾期人数'] / dt_info_zhengxin['区间客户数']
# 绘图展示
plt.figure(figsize = (15,6))
plt.rcParams["font.size"] = 15
plt.subplot(121)
dt_info_zhengxin["区间客户数"].plot(kind = "pie",autopct='%.2f%%')
plt.legend(dt_info_zhengxin["征信分组"],loc = 3, fontsize = 11)
plt.subplot(122)
plt.title("首逾率")
dt_info_zhengxin["首逾率"].plot(kind = "bar")
plt.xticks(range(6),dt_info_zhengxin["征信分组"],rotation =0)
plt.tight_layout(pad = 2)
plt.show()
- 大部分客户查询次数均在12次以下,其中0-3,3-6,6-12次区间人数相差不大;
- 首逾率基本跟随征信查询次数增长而增长,查询次数越大,首逾率越高,其中查询21+人次的总体首逾率达到了惊人的60%左右;
- 可以初步判断征信查询次数与首逾率是呈正相关的。
3.3.2 信用评级影响
将信用评级划分为5个分组,并进行聚合统计
def judge_pingji(x):
if x =='A':
return 'A'
elif x == 'AA':
return 'AA'
elif x in ['B','C','D']:
return 'BCD'
elif x in ['E','HR','NC']:
return 'ERC'
else:
return '缺失'
# 分组
dt['信用评级分组'] = dt['信用评级'].apply(lambda x:judge_pingji(x))
dt_info_pingji = dt.groupby('信用评级分组').agg({'用户id':'count','是否逾期(1是,0否)':'sum'}).reset_index().rename(columns = {'用户id':"区间客户数",'是否逾期(1是,0否)':'逾期人数'})
dt_info_pingji['区间客户占比'] = dt_info_pingji['区间客户数']/dt_info_pingji['区间客户数'].sum()
dt_info_pingji['首逾率'] = dt_info_pingji['逾期人数']/dt_info_pingji['区间客户数']
#绘图
plt.figure(figsize = (15,6))
plt.rcParams["font.size"] = 15
plt.subplot(121)
dt_info_pingji["区间客户数"].plot(kind = "pie",autopct='%.2f%%')
plt.legend(dt_info_pingji["信用评级分组"],loc = 3, fontsize = 13)
plt.subplot(122)
plt.title("首逾率")
dt_info_pingji["首逾率"].plot(kind = "bar")
plt.xticks(range(5),dt_info_pingji["信用评级分组"],rotation =0)
plt.tight_layout(pad = 2)
- 除开缺失字段客户数,客户占比最高为评级BCD的用户,其次ERC,整体用户评级都比较低;
- ERC评级用户首逾率最高达到52%左右,其次为BCD评级用户首逾率在36%;
3.3.3 年龄影响
先对年龄进行分组,并聚合统计分析
bins = [0,25,30,35,40,45,100]
labels = ["25岁及以下","26-30","31-35","36-40","41-45","45+"]
dt["年龄分组"] = pd.cut(dt["年龄"],bins = bins, labels = labels)
dt_info_age = dt.groupby("年龄分组").agg({"用户id":"count","是否逾期(1是,0否)":"sum"}).rename(columns={"用户id":"区间客户数","是否逾期(1是,0否)":"逾期人数"}).reset_index()
dt_info_age["区间客户占比"] = dt_info_age["区间客户数"]/dt_info_age["区间客户数"].sum(0)
dt_info_age["首逾率"] = dt_info_age["逾期人数"] / dt_info_age["区间客户数"]
plt.figure(figsize = (15,6))
plt.rcParams["font.size"] = 15
plt.subplot(121)
dt_info_age["区间客户数"].plot(kind = "pie",autopct='%.2f%%')
plt.legend(dt_info_age["年龄分组"],loc = 3, fontsize = 13)
plt.subplot(122)
plt.title("首逾率")
dt_info_age["首逾率"].plot(kind = "bar")
plt.xticks(range(5),dt_info_age["年龄分组"],rotation =0)
plt.tight_layout(pad = 2)
plt.show()
- 客户中25岁及以下相对较多,其余人数占比均差不多
- 首逾率情况都在30%左右,较为均衡
- 初步判断首逾率与年龄关系不大
3.4 计算提升度
在进行变量分析之后,这时我们就要从中筛选中较为有效的变量了,这里涉及到一个衡量变量是否有效的指标,提升度。
提升度:通俗的来说就是衡量拒绝最坏那一部分的客户之后,对整体的风险控制的提升效果。 提升度越高,说明该变量可以更有效的区分好坏客户,能够更少的误拒好客户。
计算公式:提升度 = 最坏分箱的首逾客户占总首逾客户的比例 /该分箱的区间客户数占比
例如:上表中征信总查询次数中,最坏分箱为4:[21,∞),首逾客户为1923,总逾期客户为17365,该分箱区间客户数占比为5.69%,所以提升度就是(1923/17365)/5.69%=11%/5.69%=1.94。
注意:
提升度不是和逾期率成正比的,提升度说明的是这个变量下面有很大一部分人是会逾期的,它的大小是告诉我们这个变量有必要写到放贷策略里面去做优化,但是如果这部分人占整体的比例不高,那最终对逾期率影响也不大,但确实是能为企业减少风险。
计算征信查询次数的提升度:(1.94)
p1 = dt_info_zhengxin.iloc[dt_info_zhengxin['首逾率'].idxmax()]['逾期人数']/dt_info_zhengxin['逾期人数'].sum()
p2 = dt_info_zhengxin.iloc[dt_info_zhengxin['首逾率'].idxmax()]['区间用户占比']
up_rate1 = p1/p2
up_rate1
# 提升度
[out]:1.9458254325820934
计算信用评级的提升度:(1.71)
p1 = dt_info_pingji.iloc[dt_info_pingji['首逾率'].idxmax()]['逾期人数']/dt_info_pingji['逾期人数'].sum()
p2 = dt_info_pingji.iloc[dt_info_pingji['首逾率'].idxmax()]['区间客户占比']
up_rate2 = p1/p2
up_rate2
# 提升度
[out]:1.7147127611157038
计算年龄的提升度:(1.08)
p1 = dt_info_age.iloc[dt_info_age["首逾率"].idxmax()]["逾期人数"]/dt_info_age["逾期人数"].sum()
p2 = dt_info_age.iloc[dt_info_age["首逾率"].idxmax()]["区间客户占比"]
up_rate3 = p1/p2
up_rate3
[out]:1.0786323478681992
结果:征信查询次数提升度为1.94,信用评级提升度为1.71,年龄的提升度为1.08,选择征信查询次数的提升度。
3.5 解决方案
在以上过程中,我们根据计算得知提升度最高的征信查询次数,也就是说征信查询次数对于首逾率的影响最大。我们不妨将其最坏分箱的人全部拒绝,计算提出后的首逾率降幅为多少。
new_yuqi_nums = dt_info_zhengxin["逾期人数"].sum() - dt_info_zhengxin.iloc[dt_info_zhengxin["首逾率"].idxmax()]["逾期人数"]
new_yuqi_rate = new_yuqi_nums / (dt_info_zhengxin["区间客户数"].sum() - dt_info_zhengxin.iloc[dt_info_zhengxin["首逾率"].idxmax()]["区间客户数"])
# 原始整体首逾率为:
old_rate = dt['是否逾期(1是,0否)'].sum()/dt.shape[0]
# 下降幅度
diff = (dt['是否逾期(1是,0否)'].sum()/dt.shape[0]) - new_yuqi_rate
print("新的首逾率:",new_yuqi_rate)
print("- "*20)
print("原始的首逾率:",old_rate )
print("- "*20)
print("首逾率下降幅度:",diff )
新的首逾率: 0.2900287361718911
- - - - - - - - - - - - - - - - - - - -
原始的首逾率: 0.307584667705824
- - - - - - - - - - - - - - - - - - - -
首逾率下降幅度: 0.017555931533932867
- 通过对征信次数大于21次的用户拒绝后,首逾率为29%,下降了1.76%;
- 虽然首逾率下降比例较少,但这部分的确能够起到影响作用。
二、用户群组分析——对相同生命周期阶段的用户进行垂直分析
群组分析:
- 通过字面意思即可理解,群组分析法就是按某个特征对数据进行分组,通过分组比较,得出结论的方法。
- 简单举例:将用户数据按性别特征,可以分组为男性和女性,将用户注册时间作为特征,按月份分组,可以分为1月,2月,3月进行环比比较,以及对他的留存率、活跃率、付费率等进行分析。
群组分析的作用:
1.对处于相同生命周期阶段的用户进行垂直分析,从而比较得出相似群体随时间的变化。
2.通过比较不同的同期群,可以从总体上看到,应用的表现是否越来越好了。从而验证产品改进是否取得了效果。
1.案例目的
通过用户的订单消费情况,对比同一月份的新用户留存率的变化趋势,以及不同时间期的新用户在同周期时的留存率情况
2.案例过程
- 数据一共有7个字段
orderid:订单编号
orderdate:订单日期
userid:用户编号
totalcharges:消费金额
因为在这里分析的是用户留存率情况,其他字段咱不需要
2.1 数据处理
需要从月份维度进行分析,先根据用户订单编号增加一个年月字段,再选择用户最小消费月份为首次消费时间
# 增加年月字段
df['orderperiod'] = df.orderdate.apply(lambda x:x.strftime("%Y-%m"))
#增加最早消费时间
# 根据索引对齐,需先将orderid设置为索引列
df.set_index("userid",inplace = True)
df["chortgroup"] = df.groupby("userid").agg({"orderperiod":"min"})
df.reset_index(inplace = True)
orderperiod:用户消费月份
chortgroup:用户最早消费时间(出现的时间点)
2.2 按用户按照最早消费时间分组并编号
cohorts = df.groupby(['chortgroup','orderperiod',]).agg({'userid':pd.Series.nunique,'orderid':pd.Series.nunique,'totalcharges':'sum'})
cohorts.rename(columns={"userid":"totalusers",
"orderid":"totalorders"},inplace=True)
# 定义编号函数
def cohorts_period(x):
x['cohortperiod'] = np.arange(len(x)) + 1
return x
# 编号
#cohorts.groupby('chortgroup') 后 每一个小群组分别是以orderperiod为index的群组
cohorts = cohorts.groupby('chortgroup').apply(cohorts_period)
cohorts = cohorts.reset_index().set_index(['chortgroup','cohortperiod'])
cohorts
- 上图中,已经按照用户首月时间对随后几个月的消费情况进行了统计
- 但其中可能是数据缺失的原因,消费金额列出现为0的情况,但这并不影响我们对留存率的计算
2.3 计算用户留存率
每个月的首月用户数
cohort_group_size = cohorts["totalusers"].groupby(level=0).first()
chortgroup
2009-01 20
2009-02 28
2009-03 12
2009-04 8
Name: totalusers, dtype: int64
计算每月留存率
cohorts_liucun = cohorts["totalusers"].unstack(0).div(cohort_group_size,axis = 1).fillna(0)
cohorts_liucun
绘图展示:
# 绘图
plt.rcParams["font.size"] = 14
plt.rcParams["font.sans-serif"] = ["SimHei"]
fig, ax = plt.subplots(1,figsize = (10,6),dpi = 80)
ax.plot(cohorts_liucun)
ax.set_xticks(range(1,13))
ax.set_title('留存率')
ax.grid(0.5)
ax.legend(cohorts_liucun.columns)
plt.show()
# 热力图
import seaborn as sns
sns.set(style="white")
plt.rcParams["font.size"] = 16
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.figure(figsize=(12,6))
plt.title("用户留存率:热力图")
sns.heatmap(cohorts_liucun.T,mask=cohorts_liucun.T.isnull(),annot=True,fmt=".0%")
plt.show()
3.总结
- 整体用户留存率偏低,在5月就已经没有用户;
- 其中3、4月份用户在3月已经消失,而1、2月用户生命周期相对较长,在5月才消失;
- 预测可能1月、2月有活动,特别是1月份的,能够让用户的留存较高,对于此类情况的产生需要想办法增加用户留存,比如持续推出新品、给用户发短信、推出优惠活动等。
三、用户行为路径漏斗转化分析
用户行为路径分析:
用户行为路径分析是一种监测用户流向,从而统计产品使用深度的分析方法。它主要根据每位用户在App或网站中的点击行为日志,分析用户在App或网站中各个模块的流转规律与特点,挖掘用户的访问或点击模式,进而实现一些特定的业务用途,如App核心模块的到达率提升、特定用户群体的主流路径提取与浏览特征刻画,App产品设计的优化与改版等。
行为路径分析有如下作用:
1.可视化用户流向,对海量用户的行为习惯形成宏观了解。
2.定位影响转化的主次因素,使产品的优化与改进有的放矢。
用户路径的分析转化结果通常以桑基图形式展现,以目标事件为起点/终点,详细查看后续/前置路径的流向,可以详细查看某个节点事件的转化情况。
桑基图
1.案例背景
案例基于网络消费贷款形式,对消费贷借款进行复盘分析,增加用户借贷率。
2.案例过程
2.1 数据源观察
每日访问信息 | 用户信息 |
---|
- data:日期
- PV:访问量
- UV:独立用户访问量(访问用户数)
- rigist_cnt:注册数
- regist_rate:访客注册率
- active_cnt:激活数
- new_cus:是否为新用户(1:是,0:否)
- lending:是否放贷(1:是,0:否)
2.2 计算新、老用户的放贷数和申请数
新用户:
dt_check_1 = dt_check.query("new_cus == 1")
pt_1 = pd.pivot_table(data=dt_check_1,index='date',values='lending',aggfunc=[np.sum,'count'])
pt_1.columns = pt_1.columns.droplevel(1)
pt_1.columns = ['新用户放贷数','新用户申请数']
pt_1['放贷率'] = pt_1['新用户放贷数'] / pt_1['新用户申请数']
pt_1 = pt_1.reset_index()
pt_1.head()
# 平均放贷率
pt_1["新用户放贷率"].mean()
# 平均放贷率
[out]:0.18942741473488545
老用户:
dt_check_0 = dt_check.query("new_cus == 0")
pt_0 = pd.pivot_table(dt_check_0,index = 'date',values='lending',aggfunc=[np.sum,'count'])
pt_0.columns = pt_0.columns.droplevel(1)
pt_0.columns = ['老用户放贷数','老用户申请数']
pt_0['放贷率'] = pt_0['老用户放贷数'] / pt_0['老用户申请数']
pt_0.reset_index(inplace = True)
pt_0.head()
pt_0['放贷率'].mean()
# 平均放贷率
[out]:0.28226736226736227
- 老用户的平均放贷率比新用户要高出许多,这也是对于老用户的信赖。
2.3 计算复借率
老用户定义:在这里,我们定义前一天借贷的新用户,第二天继续借款就为老用户
先创建老用户人数列表,5.1-5.29的新用户为5.2-5.30日的老用户,再在首位随机插入一个数值表示5.1日的老用户
old = list(pt_1['新用户放贷数'])[0:29]
old.insert(0,24)
将数据与老用户放贷率表按日期进行匹配,计算复借率(复借率 = 老用户申请数 / 老用户数)
data = {'date':pt_1['date'],'老用户数':old}
dt_old = pd.DataFrame(data)
pt_0_m = pd.merge(pt_0,dt_old,on='date')
pt_0_m['老用户复借率'] = pt_0_m['老用户申请数'] / pt_0_m['老用户数']
pt_0_m['老用户复借率'].mean()
复借率走势 |
---|
# 平均复借率
[out]:0.3471876898455787
- 5月复借率走势跌宕起伏,最低不到10%,最高却超过90%,猜测在复借率较高的那几天可能有营销活动在促进借贷,
- 整月平均复借率为34.7%左右
2.4 计算各节点转换率并绘制漏斗图
节点结算:
计算当月每日PV、UV、注册数、活跃数、新用户申请数、新用户放贷数
dt = pd.merge(pt_1,dt_flow,on='date',how='left') #合并新客户
dt_1 = pd.merge(dt,pt_0_m,on='date',how='left') #合并老客户复借率
# 汇总
dt_sum = dt_1.drop('date',axis=1)
dt_sum.loc['Row_sum'] = dt_sum.apply(lambda x:x.sum())
# 提取需要的字段
dt_desc = dt_sum[dt_sum.index == 'Row_sum'][['PV','UV','regist_cnt','active_cnt','新用户申请数','新用户放贷数']]
dt_desc = dt_desc.T.reset_index()
dt_desc.columns = ['指标','汇总']
当月总体指标汇总
绘制漏斗图:
from plotly import graph_objects as go
trace = go.Funnel(
y = dt_desc['指标'],
x = dt_desc['汇总'],
# 表示图片展示内容样式 “value+percent previous”:数值+百分比 占前一层比例(可选)
textinfo = 'value+percent previous',
marker = dict(color=["deepskyblue", "lightsalmon", "tan", "teal", "silver", "yellow"]), #颜色参数
connector = {"line": {"color": "royalblue", "dash": "solid", "width": 2}})
data = [trace]
fig = go.Figure(data)
fig.show()
月度各指标漏斗图
- 转换率在 UV → regist_cnt 即访问用户→注册用户这一步骤转换率很低,需要进行策划活动提高用户注册数,比如新用户注册送礼等;
- 注册用户转为活跃用户,以及活跃用户转为申请用户指标均处于较高的水平,需要维持下去;
- 放贷成功率比较低,可以优化算法模型,在保证资金安全的情况下提高放贷率。
网友评论