消费金融案例分析总结

本文目录如下:

  • 用户行为路径漏斗转化计算分析
  • 单变量分析
  • 用户群组分析

一 用户行为路径漏斗转化计算分析

在开始分析之前,我们需要先理清楚贷款业务的流程,也就是每个用户从进件到最终还款之间所涉及到的所有环节。一般情况下,网贷的流程可以概述为以下形式:


流程.png

通过用户行为路径分析,我们可以得到:

  • 可视化用户流向,对海量用户的行为习惯形成宏观了解。
  • 定位影响转化的主次因素,使产品的优化与改进有的放矢。
    转化漏斗是针对特定模块与事件节点的路径分析。无论是新用户的引导、某个业务流程还是某一次运营活动,涉及到有流程转化的都可以建立漏斗来分析。在分析的过程中,可以观察整体的转化率是否符合行业水准,哪些步骤转化率还有优化空间?可以通过细分维度发现导致转化率低的因素是哪些,也可以通过查看流失环节的其他使用路径,做出针对性的引导。

它适用于对产品运营中的关键环节进行分析、监控,找到其中薄弱的环节,通过用户引导或者产品迭代来优化,提升转化效果。

1 、读取数据

# 使用sql读取数据
engine = sqlalchemy.create_engine('mysql+pymysql://***:******@localhost:3306/')
sql_flow = "select * from plat_flow"
sql_check = "select * from loans_check"

# 执行sql语句,获取数据
dt_flow = pd.read_sql(sql=sql_flow, con=engine)
dt_check = pd.read_sql(sql=sql_check, con=engine)

# 从新命名列名
dt_flow.rename(columns={
    "date":"日期",
    "PV":"PV",
    "UV":"UV",
    "regist_cnt":"注册数",
    "regist_rate":"访客注册率",
    "active_cnt":"激活数",
    "active_rate":"激活访问率"
},inplace=True)

dt_check.rename(columns={
    "ID":"用户ID",
    "date":"申请日期",
    "new_cus":"是否新用户(1为是,0为否)",
    "lending": "是否放贷"
},inplace=True)

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=["是否放贷"], aggfunc=[np.sum,'count'])
pt_1.columns = pt_1.columns.droplevel(0)
pt_1.columns = ["新用户放贷数","新用户申请数"]
pt_1["新用户放贷率"] = pt_1["新用户放贷数"] / pt_1["新用户申请数"]
pt_1 = pt_1.reset_index()
pt_1.head()

选取子集,将新用户和老用户分开统计每天申请贷款人数和审批放贷人数,然后计算新用户放贷率。最后使用merge函数将新用户结果表和老用户结果表拼接。结果如下:


总结表.png

接下来,计算用户复借率,需要知道每天的老用户数目,这里的老用户定义是:#前一天的放款的新用户第二天继续借款就是老用户#,对存量老用户我们暂时不考虑,就看前一天贷款的人第二天是否还继续贷款,贷款的就认为是老用户复借,所以取新用户放贷透视表的前29天数据+5月1日的人构成老客户数量,我们看这些客户是否还继续贷款。

#分析5月1日-5月30日的复借率
old = [pt_1["新用户放贷数"]]
old = list(pt_1["新用户放贷数"])[0:29]

# 假设5月1日有24个人
old.insert(0,24)
data={'申请日期':list(pt_1["申请日期"]),'老客户数':old} 
dt_old = pd.DataFrame(data)
pt_0_m = pd.merge(pt_0, dt_old, how='left', on=["申请日期"])

pt_0_m["老客户复借率"] = pt_0_m["老用户申请数"] / pt_0_m["老客户数"]

3、计算各节点路径转化率并绘图

组成一张用户路径总表,计算各节点转化率。

dt = pd.merge(dt_flow, pt_1, how='left', on=None, left_on="日期", right_on="申请日期" )
dt_1 = pd.merge(dt, pt_0_m, how='left', on=None, left_on="日期", right_on="申请日期" )
dt_1 = dt_1.drop(['申请日期_x', '申请日期_y'], axis=1)
dt_1.head()

计算转化漏斗,计算汇总数据:

#计算转化漏斗。 计算汇总数据
dt_2 = dt_1.drop(['日期'], axis=1)
#汇总求和(数值汇总)
dt_2.loc['Row_sum'] = dt_2.apply(lambda x: x.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 = ["指标","汇总"]

dt_3_s

结果如下:


newplot.png

从结果来看,从PV到UV有一个很大幅度的下降,正常来讲,一个广告投放可能也就吸引10%-30%左右用户,但是点击量是非常巨大的数量,所以造成这样的结果。

从整体环节来看,很明显注册数量4%是比较低的,这说明很多用户去点击了,但是注册人数很少,是不是说明这个渠道有问题?我可以再通过不同渠道的转化漏斗分析再做对比,来看到底是整个行业的转化率偏低,还是单个渠道偏低,或者这个渠道用户群体不是我们想要的。

二、单变量分析

在消费金融公司里,经常会通过日常监控发现某款消费贷产品首逾率有逐渐升高的趋势,我们需要把首逾率降下来以减少产品带来的损失,同时通过率降幅不能太明显。
分析目标:通过数据探查分析制定出可以有效降低首逾率的策略。
分析思路:因为我们所要分析的策略时将要在客户申请时用来判断客户是否会逾期的条件,所以策略分析时的基本思路就是还原这些有首逾表现的客户在申请时的数据(这个还原是指提取出客户在申请时点各个维度的数据,越多越好) ,然后利用这些数据去找出能够区分好坏客户的变量,制定策略。

1、产品总体情况

# 读取数据
engine = sqlalchemy.create_engine()
sql_cmd = "select * from load_datas"

# 执行sql语句,获取数据
dt = pd.read_sql(sql=sql_cmd, con=engine)
dt.rename(columns={
    "user_id":"用户id",
    "age":"年龄",
    "occupation":"职业",
    "work_times":"工作时间",
    "credit_score":"芝麻信用分",
    "credit_level":"信用评级",
    "credit_check_times":"近半年征信查询次数",
    "credit_card_use_rate":"信用卡额度使用率",
    "is_overdue":"是否逾期(1是,0否)"
},inplace=True)

# 计算总体首逾率 = 首逾客户数/总申请客户数
dt["是否逾期(1是,0否)"].sum()/dt.shape[0]

可以得到,总体首逾率30.76%。

2、 筛选出有效变量

这里用到单变量分析的方法,单变量分析的主要目的是筛选出好坏区分度较好的变量以便制定策略。在消金公司的日常工作中,会有专门负责爬取变量和计算加工变量数据的团队,他们在不断的去获取加工很多可能对风险控制有帮助的数据提供给我们风控团队,而我们风控人员就需要从这成千上万个变量中探查出能够控制逾期风险但同时又不会误拒很多好客户的变量。

拿到数据的第一步就是针对每个变量单独分析,查看其对逾期的影响。

2.1、征信查询次数分组

# 定义一个征信分组的函数
def judge_zhengxin(nums):
    try:
        nums = int(nums)
        if 0<=nums and nums<3:
            return '1:[0,3)'
        elif 3<=nums and nums<6:
            return '2:[3,6)'
        elif 6<=nums and nums<12:
            return '3:[6,12)'
        elif 12<=nums and nums<21:
            return '4:[12,21)'
        elif 21<=nums:
            return '5:[21,无穷)'
    except Exception as e:
        return "6:缺失"
# 分组统计各个分组的情况
# 区间用户占比、未逾期客户数要另外计算
dt_info = dt.groupby("征信分组").agg({
    "用户id":'count',
    "是否逾期(1是,0否)":sum
}).reset_index().rename(columns={"用户id":"区间客户数",
                                "是否逾期(1是,0否)":"区间逾期客户数"})
dt_info
# 区间用户占比、未逾期客户数要另外计算
dt_info['区间用户占比']=dt_info["区间客户数"]/dt_info["区间客户数"].sum()
dt_info["区间没有逾期客户数"]=dt_info["区间客户数"]-dt_info["区间逾期客户数"]
dt_info["区间首逾率"]=dt_info["区间逾期客户数"]/dt_info["区间客户数"]
dt_info

统计结果如下:


征信结果.png

2.2、信用评级分组

# 定义一个征信分组的函数
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_info2 = dt.groupby("信用评级分组").agg({
    "用户id":'count',
    "是否逾期(1是,0否)":sum
}).reset_index().rename(columns={"用户id":"区间客户数",
                                "是否逾期(1是,0否)":"区间逾期客户数"})
dt_info2
# 区间用户占比、未逾期客户数要另外计算
dt_info2['区间用户占比']=dt_info2["区间客户数"]/dt_info2["区间客户数"].sum()
dt_info2["区间没有逾期客户数"]=dt_info2["区间客户数"]-dt_info2["区间逾期客户数"]
dt_info2["区间首逾率"]=dt_info2["区间逾期客户数"]/dt_info2["区间客户数"]
dt_info2

统计结果如下:


信用评级结果.png

3、计算提升度

在进行变量分析之后,这时我们就要从中筛选中较为有效的变量了,这里涉及到一个衡量变量是否有效的指标,提升度。通俗的来说就是衡量拒绝最坏那一部分的客户之后,对整体的风险控制的提升效果。 提升度越高,说明该变量可以更有效的区分好坏客户,能够更少的误拒好客户。如下,通过对所有变量的提升度进行倒序排列,发现个人征信总查询次数和客户信用评级的提升度最高,达到1.93和1.71。

# 征信查询次数的提升度
# 提升度=最坏分箱的首逾客户占总首逾客户的比例 /该分箱的区间客户数占比
# 这里最坏分箱就是根据征信分组后,首逾率最高的一组
dt_info["区间首逾率"].idxmax()
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

# 信用评级的提升度
# dt_info2.iloc[dt_info2["区间首逾率"].idxmax()]
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

4、制定策略

new_yuqi_nums1 = dt_info["区间逾期客户数"].sum() - dt_info.iloc[dt_info["区间首逾率"].idxmax()]["区间逾期客户数"]
new_yuqi_rate1 = new_yuqi_nums1 / dt_info["区间客户数"].sum()

old_yuqi_nums1 = dt_info["区间逾期客户数"].sum()
old_yuqi_rate1 = old_yuqi_nums1 / dt_info["区间客户数"].sum()

new_yuqi_rate1

通过上一步的单变量分析,我们筛出了’征信查询次数’、‘信用评级’这两个提升度最高的变量。如果将这两个变量的最坏分箱的客户都拒绝之后,对整体逾期的影响。 这个影响就是指假设我们将‘征信总查询次数>=21的3213位客户全部拒绝’之后,剩下的客户逾期率相比拒绝之前的逾期率降幅,最后,我们得到征信查询次数分组降幅3.4%,信用评级分组降幅7.5%。

三、用户群组分析

用户在产品使用中都有一个用户行为流程,不同时期的用户表现情况可能不一样,群组分析的主要目的是分析相似群体随时间的变化,核心就是对比、分析不同时间群组的用户,在相同周期下的行为差异, 所以也称同期群分析。
那么在金融风控领域,最常用的一个场景就是账龄分析,用来监测用户的逾期率变化状况。如下图, M2、M3的逾期率比较高,随后调整了风控策略,然后进行群组分析看策略是否有效。


账龄分析.png

1、读取数据

engine = sqlalchemy.create_engine()
sql_cmd = "select * from groups_data"
# 执行sql语句,获取数据
df = pd.read_sql(sql=sql_cmd, con=engine)
# 生成一个新字段,用户订单月份
df["orderperiod"] = df.orderdate.apply(lambda x:x.strftime("%Y-%m"))
# 设置userid为索引
df.set_index("userid",inplace=True)
# 这里的level=0表示第一层索引即userid,并且每次分组之后都会形成很多个dataframe
# 按照每个用户的订单的最早时期,生成用户群组
df["cohortgroup"]=df.groupby(level=0)["orderdate"].min().apply(lambda x:x.strftime("%Y-%m"))
df.reset_index(inplace=True)
df.head()

结果如下:


新字段.png

这里生成的新字段,orderperiod为用户订单月份,cohortgroup是按照每个用户的订单的最早时期,生成用户群组,两者是不一样的。

2、用户群组和月份字段进行分组

接下来,根据用户群组和月份字段进行分组:

grouped = df.groupby(["cohortgroup","orderperiod"])
# 求每个用户群下每一个月份的用户数量、订单数量、购买金额
cohorts = grouped.agg({"userid":pd.Series.nunique,
                      "orderid":pd.Series.nunique,
                      "totalcharges":np.sum})
# 重命名
cohorts.rename(columns={"userid":"totalusers",
                       "orderid":"totalorders"},inplace=True)

结果如下:


用户群组和月份字段进行分组.png

这里的orderperiod字段,我们可以看出2019-01对应的最早消费月份是2009-01,02,03,05,但是2009-02对应的却是最早消费月份2009-02,03,05,相对比来说,2009-02的第一个月份是在2月份,所以就会出现不对齐的现象,对于这个问题,我们可以orderperiod进行编号来解决:

# 把每个群组继续购买的日期字段进行改变
def cohort_period(df):
    # 给首次购买日期进行编号,第二次购买为2,第三次购买为3
    df["cohortperiod"] = np.arange(len(df)) + 1

    return df

# 注意的是apply后面传入的是一个个dataframe
cohorts = cohorts.groupby(level=0).apply(cohort_period)
# 得到每个群组的用户量
# 重新设置索引
cohorts.reset_index(inplace=True)
cohorts.set_index(["cohortgroup","cohortperiod"],inplace=True)

得到:


cohortperiod.png

3、计算留存率

# 得到每个群组的用户量,就是第一天的用户数据量,用作留存率的分母
cohort_group_size = cohorts["totalusers"].groupby(level=0).first()
cohort_group_size.head()
# 计算每个群组的留存
user_retention = cohorts["totalusers"].unstack(0).divide(cohort_group_size,axis=1)

结果得到:


留存率.png

注意,上图中每个column代表最早在当月的消费群组,cohortperiod表示最早消费群组在第1,2,3,4月的情况,比如2019-01月表示最早在1月消费群组的第1,2,3,4月的情况。

总结来看:

对处于相同生命周期阶段的用户进行垂直分析,从而比较得出相似群体随时间的变化,上图可以看到用户留存率随着时间推移在下降。

同时,通过比较不同时间的同期群,可以看出留存率的表现忽高忽低,上图可以看到2019-02月走低后2019-04月又走高,
可能在2019-03月的时候做了用户活动导致了这样的结果,从而验证活动改进取得了明显效果。

你可能感兴趣的:(消费金融案例分析总结)