金融风控实战——异常检测(一)

为什么反欺诈检测难度很高?

反欺诈项目很多情况下就是客户根本不知道什么是欺诈,什么不是。换句话说,诈骗的定义很模糊。

往小了说,反诈骗似乎是一个二分类问题(binary classification),但你仔细想想后会发现其实这是个多分类问题(multi-class classification),因为可以每种不同的诈骗都当做一种单独的类型。除了欺诈手段多样且持续变化,欺诈检测一般还面临以下问题:

  • 大部分情况下数据是没有标签(label)的,各种成熟的监督学习(supervised learning)没有用武之地。
  • 区分噪音(noise)和异常点(anomaly)时难度很大,甚至需要发挥一点点想象力和直觉。
  • 当多种诈骗数据混合在一起,区分不同的诈骗类型更难。根本原因还是因为我们并不了解每一种诈骗定义。
  • 即使我们真的有诈骗的历史数据,即在有标签的情况下用监督学习,也存在很大的风险。用这样的历史数据学出的模型只能检测曾经出现过与历史诈骗相似的诈骗,而对于变种的诈骗和从未见过的诈骗,我们的模型将会无能为力。

因此,在实际情况中,我不建议直接用任何监督学习,至少不能单纯依靠一个监督学习模型来奢求检测到所有的诈骗。

这就陷入了一个死循环,因为没有历史标签和对诈骗的理解,我们无法做出能对诈骗细分的模型。因此我们一般使用无监督学习(unsupervised learning),且需要领域专家(domain experts)也就是对这个行业非常了解的人来验证我们的预测,提供反馈,以便于及时的调整模型。

拿到含有欺诈的数据后我们该做些什么?

  • 相关矩阵(Correlation Matrix)
  • 多维尺度变换(Multidimensional Scaling)
from IPython.display import Image
Image(filename='./image/12.png', width=400) 

在这里插入图片描述
首先思考,当我们有一个场景需要做预判的时候,又完全没有标签,我们能做什么?

  • 迁移学习
  • 专家模型
  • 无监督算法

迁移学习

源域样本和目标域样本分布有区别,目标域样本量又不够。通过算法缩小边缘分布之间和条件分布下的差异。

  • 基于实例迁移
  • 基于特征的迁移
  • 基于模型的迁移

缺点:需要拥有与当前目标场景相关的源域数据。

专家模型

家经验判断是根据信贷专家多年从业经验进行定性判断。与我们常用的模型不同,它是根据主观经验进行打分,而不是根据统计分析或者模型算法来进行客观的计算。

操作:

  • 凭经验判断特征重要性
  • 凭经验为变量加权

缺点:需要大量的行业经验积累,有时候很难让人信服。

无监督算法

缺乏足够的先验知识,无法对数据进行标记时,使用的一种机器学习方法。代表有聚类、降维等。在风控领域中我们主要使用的是聚类无监督异常检测。而聚类是发现样本间的相似性,异常检测则是发现样本间的相异性。

聚类

  • K-Means
  • 均值漂移
  • DBSCAN
  • EM
  • 凝聚层次
  • 社区发现

在相当长的一段时间我们主要靠对负样本聚类,将我们的逾期客群描述成欺诈风险信用风险两部分。社区发现算法也是当前识别团伙欺诈的主要手段之一,主要思想是通过知识图谱将小团体筛选出来。在金融领域,聚集意味着风险。请记住这句话,这将是知识图谱应用时候的核心思想之一。

异常检测

异常点检测(Outlier detection),又称为离群点检测,是找出与预期对象的行为差异较大的对象的一个检测过程。这些被检测出的对象被称为异常点或者离群点。异常点检测在生产生活中有着广泛应用,比如信用卡反欺诈、工业损毁检测、广告点击反作弊等。异常点(outlier)是一个数据对象,它明显不同于其他的数据对象。如下图1所示,N1、N2区域内的点是正常数据。而离N1、N2较远的O1、O2、O3区域内的点是异常点。

Image(filename='./image/6.png', width=300) 

在这里插入图片描述
和不均衡学习不同的是异常检测一般是无监督的,和普通的二分类问题也不大相同,因为异常检测往往看似是二分类,但其实是多分类(造成异常的原因各不相同)。

算法假设

  • 异常数据跟样本中大多数数据不太一样。
  • 异常数据在整体数据样本中占比比较小。

主要思想

主流异常检测方法都是基于样本(小群体)间的相似度(proximity)

  • 距离
  • 密度
  • 角度
  • 隔离所需的难度

为什么要用无监督异常检测方法?

  • 样本群体有异构成分,可以对样本做筛选
  • 很多场景没有标签或者标签很少,不能训练监督模型(比如冷启动项目、欺诈模型)
  • 样本总是在发生变换,只能从一个小群体内部发现异常(比如欺诈检测,手段多变,团伙欺诈通常集中在某段时间内)
  • 异常检测假设异常样本占比很少,并且从某种度量上远离其他样本,这符合我们个体欺诈的先验知识。但是在团体欺诈检测中就不太适用了

今天这节课主要涉及四个检验算法:

  • Z-score检验
  • KNN算法
  • Local Outlier Factor
  • 孤立森林
import pandas as pd
from sklearn.metrics import roc_auc_score,roc_curve,auc
from sklearn.model_selection import train_test_split
from sklearn import metrics
from sklearn.linear_model import LogisticRegression
import numpy as np
import random
import mathdata = pd.read_csv('Acard.txt')
data.head()

在这里插入图片描述

train = data[data.obs_mth != '2018-11-30'].reset_index().copy()
val = data[data.obs_mth == '2018-11-30'].reset_index().copy()
feature_lst = ['person_info','finance_info','credit_info','act_info']x = train[feature_lst]
y = train['bad_ind']val_x =  val[feature_lst]
val_y = val['bad_ind']lr_model = LogisticRegression(C=0.1,class_weight='balanced')
lr_model.fit(x,y)
y_pred = lr_model.predict_proba(x)[:,1]
fpr_lr_train,tpr_lr_train,_ = roc_curve(y,y_pred)
train_ks = abs(fpr_lr_train - tpr_lr_train).max()
print('train_ks : ',train_ks)y_pred = lr_model.predict_proba(val_x)[:,1]
fpr_lr,tpr_lr,_ = roc_curve(val_y,y_pred)
val_ks = abs(fpr_lr - tpr_lr).max()
print('val_ks : ',val_ks)
from matplotlib import pyplot as plt
plt.plot(fpr_lr_train,tpr_lr_train,label = 'train LR')
plt.plot(fpr_lr,tpr_lr,label = 'evl LR')
plt.plot([0,1],[0,1],'k--')
plt.xlabel('False positive rate')
plt.ylabel('True positive rate')
plt.title('ROC Curve')
plt.legend(loc = 'best')
plt.show()
#train_ks :  0.4482453222991063
#val_ks :  0.4198642457760936

在这里插入图片描述

z-score异常检测

假设样本服从正态分布,用于描述样本偏离正态分布的程度。

通过计算 μ \mu μ σ \sigma σ得到当前样本所属于的正态分布的表达式,然后分别计算每个样本在这个概率密度函数下被生成的概率,当概率小于某一阈值我们认为这个样本是不属于这个分布的,因此定义为异常值。

计算公式:

μ = 1 m ∑ i = 0 m x ( i ) \mu=\frac{1}{m} \sum_{i=0}^{m} x^{(i)} μ=m1i=0mx(i)

σ 2 = 1 m ∑ i = 1 m ( x ( i ) − μ ) 2 \sigma^{2}=\frac{1}{m} \sum_{i=1}^{m}\left(x^{(i)}-\mu\right)^{2} σ2=m1i=1m(x(i)μ)2

一旦我们获得了平均值和方差的估计值,给定了新的一个训练实例,根据模型计算p(x) p(x)p(x):
p ( x ) = ∏ j = 1 n p ( x j ; μ j , σ j 2 ) = ∏ j = 1 1 1 2 π σ exp ⁡ ( − ( x − μ ) 2 2 σ 2 ) p(x)=\prod_{j=1}^{n} p\left(x_{j} ; \mu_{j}, \sigma_{j}^{2}\right)=\prod_{j=1}^{1} \frac{1}{\sqrt{2 \pi} \sigma} \exp \left(-\frac{(x-\mu)^{2}}{2 \sigma^{2}}\right) p(x)=j=1np(xj;μj,σj2)=j=112π σ1exp(2σ2(xμ)2)

当p(x)<ε p(x)&lt\varepsilonp(x)<ε时,数据为异常。

缺点:需要假设样本满足正态分布,而我们大部分场景都不满足这种假设条件。

KNN异常检测

KNN算法专注于全局异常检测,所以无法检测到局部异常。

首先,对于数据集中的每条记录,必须找到k个最近的邻居。然后使用这K个邻居计算异常分数。

我们有三种方法

  • 最大:使用到第k个邻居的距离作为离群值得分
  • 平均值:使用所有k个邻居的平均值作为离群值得分
  • 中位数:使用到k个邻居的距离的中值作为离群值得分

在实际方法中后两种的应用度较高。然而,分数的绝对值在很大程度上取决于数据集本身、维度数和规范化。

参数k的选择当然对结果很重要。如果选择过低,记录的密度估计可能不可靠。(即过拟合)另一方面,如果它太大,密度估计可能太粗略。K值的选择通常在10<k<50这个范围内。所以在分类方法中,选择一个合适的K值,可以用交叉验证法。

但是,事实上基于KNN的算法都是不适用于欺诈检测的,因为他们本身就对噪声比较敏感。

Local Outlier Factor

LOF是基于密度的经典算法(Breuning et. al. 2000), 文章发表于 SIGMOD 2000, 到目前已经有 3000+ 的引用。在 LOF 之前的异常检测算法大多是基于统计方法的,或者是借用了一些聚类算法用于异常点的识别(比如 ,DBSCAN,OPTICS)。但是,基于统计的异常检测算法通常需要假设数据服从特定的概率分布,这个假设往往是不成立的。而聚类的方法通常只能给出 0/1 的判断(即:是不是异常点),不能量化每个数据点的异常程度。相比较而言,基于密度的LOF算法要更简单、直观。它不需要对数据的分布做太多要求,还能量化每个数据点的异常程度(outlierness)。

算法介绍

LOF 是基于密度的算法,其最核心的部分是关于数据点密度的刻画。如果对 distanced-based 或者 density-based 的聚类算法有些印象,你会发现 LOF 中用来定义密度的一些概念似曾相识。了解了这些核心概念,整个算法也就显而易见了。而整个算法,最主要的是下面四个概念:

1)K-邻近距离(k-distance):在距离数据点 p 最近的几个点中,第 k 个最近的点跟点 p 之间的距离称为点 p 的 K-邻近距离,记为 k-distance § 。

2)可达距离(rechability distance):可达距离的定义跟K-邻近距离是相关的,给定参数k时, 数据点 p 到 数据点 o 的可达距离 reach-dist(p, o)为数据点 o 的K-邻近距离 和 数据点p与点o之间的直接距离的最大值。即:
r e a c h d i s t k ( p , o ) = max ⁡ { k − distance  ( o ) , d ( p , o ) } reachdist_{k}(p, o)=\max \{k-\text { distance }(o), d(p, o)\} reachdistk(p,o)=max{k distance (o),d(p,o)}3)局部可达密度(local rechability density):局部可达密度的定义是基于可达距离的,对于数据点 p,那些跟点p的距离小于等于 k-distance(p)的数据点称为它的 k-nearest-neighbor,记为 N k ( p ) N_k(p) Nk(p),数据点 p 的局部可达密度为它与邻近的数据点的平均可达距离的倒数,即:
lr ⁡ d k ( p ) = 1 ∑ o ∈ N k ( p ) reach dist  k ( p , o ) ∣ N k ( p ) ∣ \operatorname{lr} d_{k}(p)=\frac{1}{\frac{\sum_{o \in N_{k}(p)} \text {reach} \text { dist }_{k}(p, o)}{\left|N_{k}(p)\right|}} lrdk(p)=Nk(p)oNk(p)reach dist k(p,o)14)局部异常因子(local outlier factor):根据局部可达密度的定义,如果一个数据点跟其他点比较疏远的话,那么显然它的局部可达密度就小。但LOF算法衡量一个数据点的异常程度,并不是看它的绝对局部密度,而是看它跟周围邻近的数据点的相对密度。这样做的好处是可以允许数据分布不均匀、密度不同的情况。局部异常因子即是用局部相对密度来定义的。数据点 p 的局部相对密度(局部异常因子)为点p的邻居们的平均局部可达密度跟数据点p的局部可达密度的比值,即:
L O F k ( p ) = ∑ o ∈ N k ( p ) l r d ( o ) l r d ( p ) ∣ N k ( p ) ∣ = ∑ o ∈ N k ( p ) lr ⁡ d ( o ) ∣ N k ( p ) ∣ / lr ⁡ d ( p ) L O F_{k}(p)=\frac{\sum_{o \in N_{k}(p)} \frac{l r d(o)}{l r d(p)}}{\left|N_{k}(p)\right|}=\frac{\sum_{o \in N_{k}(p)} \operatorname{lr} d(o)}{\left|N_{k}(p)\right|} / \operatorname{lr} d(p) LOFk(p)=Nk(p)oNk(p)lrd(p)lrd(o)=Nk(p)oNk(p)lrd(o)/lrd(p)根据局部异常因子的定义,如果数据点 p 的 LOF 得分在1附近,表明数据点p的局部密度跟它的邻居们差不多;如果数据点 p 的 LOF 得分小于1,表明数据点p处在一个相对密集的区域,不像是一个异常点;如果数据点 p 的 LOF 得分远大于1,表明数据点p跟其他点比较疏远,很有可能是一个异常点。下面这个图来自 Wikipedia 的 LOF 词条,展示了一个二维的例子。上面的数字标明了相应点的LOF得分,可以让人对LOF有一个直观的印象。

Image(filename='./image/11.png', width=600) 

在这里插入图片描述
了解了 LOF 的定义,整个算法也就显而易见了:

  1. 对于每个数据点,计算它与其它所有点的距离,并按从近到远排序;

  2. 对于每个数据点,找到它的 k-nearest-neighbor,计算 LOF 得分。

from pyod.models.lof import LOF
clf = LOF(n_neighbors=20, algorithm='auto', leaf_size=30, metric='minkowski', p=2, metric_params=None, contamination=0.1, n_jobs=1)
clf.fit(x)
#LOF(algorithm='auto', contamination=0.1, leaf_size=30, metric='minkowski',
#  metric_params=None, n_jobs=1, n_neighbors=20, p=2)

算法应用

LOF算法中关于局部可达密度的定义其实暗含了一个假设,即:不存在大于等于 k 个重复的点。当这样的重复点存在的时候,这些点的平均可达距离为零,局部可达密度就变为无穷大,会给计算带来一些麻烦。在实际应用时,为了避免这样的情况出现,可以把 k-distance 改为 k-distinct-distance,不考虑重复的情况。或者,还可以考虑给可达距离都加一个很小的值,避免可达距离等于零。

LOF 算法需要计算数据点两两之间的距离,造成整个算法时间复杂度为 O ( n 2 ) O(n^2) O(n2) 。为了提高算法效率,后续有算法尝试改进。

FastLOF (Goldstein,2012)先将整个数据随机的分成多个子集,然后在每个子集里计算 LOF 值。对于那些 LOF 异常得分小于等于 1 的,从数据集里剔除,剩下的在下一轮寻找更合适的 nearest-neighbor,并更新 LOF 值。

这种先将数据粗略分成多个部分,然后根据局部计算结果将数据过滤来减少计算量的想法,并不罕见。比如,为了改进 K-means 的计算效率, Canopy Clustering 算法也采用过比较相似的做法。

Isolation Forest

我们先用一个简单的例子来说明 Isolation Forest 的基本想法。假设现在有一组一维数据(如下图所示),我们要对这组数据进行随机切分,希望可以把点 A 和点 B 单独切分出来。具体的,我们先在最大值和最小值之间随机选择一个值 x,然后按照 <x 和 >=x 可以把数据分成左右两组。然后,在这两组数据中分别重复这个步骤,直到数据不可再分。显然,点 B 跟其他数据比较疏离,可能用很少的次数就可以把它切分出来;点 A 跟其他数据点聚在一起,可能需要更多的次数才能把它切分出来。

Image(filename='./image/1.png', width=600) 

在这里插入图片描述
我们把数据从一维扩展到两维。同样的,我们沿着两个坐标轴进行随机切分,尝试把下图中的点A’和点B’分别切分出来。我们先随机选择一个特征维度,在这个特征的最大值和最小值之间随机选择一个值,按照跟特征值的大小关系将数据进行左右切分。然后,在左右两组数据中,我们重复上述步骤,再随机的按某个特征维度的取值把数据进行细分,直到无法细分,即:只剩下一个数据点,或者剩下的数据全部相同。跟先前的例子类似,直观上,点B’跟其他数据点比较疏离,可能只需要很少的几次操作就可以将它细分出来;点A’需要的切分次数可能会更多一些。

Image(filename='./image/2.png', width=600)

在这里插入图片描述
按照先前提到的关于“异常”的两个假设,一般情况下,在上面的例子中,点B和点B’ 由于跟其他数据隔的比较远,会被认为是异常数据,而点A和点A’ 会被认为是正常数据。直观上,异常数据由于跟其他数据点较为疏离,可能需要较少几次切分就可以将它们单独划分出来,而正常数据恰恰相反。这其实正是Isolation Forest(IF)的核心概念。IF采用二叉树去对数据进行切分,数据点在二叉树中所处的深度反应了该条数据的“疏离”程度。整个算法大致可以分为两步:

  • 训练:抽取多个样本,构建多棵二叉树(Isolation Tree,即 iTree);
  • 预测:综合多棵二叉树的结果,计算每个数据点的异常分值。

训练:构建一棵 iTree 时,先从全量数据中抽取一批样本,然后随机选择一个特征作为起始节点,并在该特征的最大值和最小值之间随机选择一个值,将样本中小于该取值的数据划到左分支,大于等于该取值的划到右分支。然后,在左右两个分支数据中,重复上述步骤,直到满足如下条件:

  • 数据不可再分,即:只包含一条数据,或者全部数据相同。
  • 二叉树达到限定的最大深度。

预测:计算数据 x 的异常分值时,先要估算它在每棵 iTree 中的路径长度(也可以叫深度)。具体的,先沿着一棵 iTree,从根节点开始按不同特征的取值从上往下,直到到达某叶子节点。假设 iTree 的训练样本中同样落在 x 所在叶子节点的样本数为 T.size,则数据 x 在这棵 iTree 上的路径长度 h(x),可以用下面这个公式计算:
h ( x ) = e + C ( T . size ) h(x)=e+C(T . \text {size}) h(x)=e+C(T.size)预测:计算数据 x 的异常分值时,先要估算它在每棵 iTree 中的路径长度(也可以叫深度)。具体的,先沿着一棵 iTree,从根节点开始按不同特征的取值从上往下,直到到达某叶子节点。假设 iTree 的训练样本中同样落在 x 所在叶子节点的样本数为 T.size,则数据 x 在这棵 iTree 上的路径长度 h(x),可以用下面这个公式计算:
h ( x ) = e + C ( T . size ) h(x)=e+C(T . \text {size}) h(x)=e+C(T.size)公式中,e 表示数据 x 从 iTree 的根节点到叶节点过程中经过的边的数目,C(T.size) 可以认为是一个修正值,它表示在一棵用 T.size 条样本数据构建的二叉树的平均路径长度。一般的,C(n) 的计算公式如下:
C ( n ) = 2 H ( n − 1 ) − 2 ( n − 1 ) n C(n)=2 H(n-1)-\frac{2(n-1)}{n} C(n)=2H(n1)n2(n1)其中,H(n-1) 可用 ln(n-1)+0.5772156649 估算,这里的常数是欧拉常数。数据 x 最终的异常分值 Score(x) 综合了多棵 iTree 的结果:
S core ⁡ ( x ) = 2 − E ( h ( x ) ) C ( φ ) S \operatorname{core}(x)=2^{-\frac{E(h(x))}{C(φ)}} Score(x)=2C(φ)E(h(x))公式中,E(h(x)) 表示数据 x 在多棵 iTree 的路径长度的均值, φ φ φ表示单棵 iTree 的训练样本的样本数, C ( φ ) C(φ) C(φ)表示用 φ φ φ条数据构建的二叉树的平均路径长度,它在这里主要用来做归一化。

从异常分值的公式看,如果数据 x 在多棵 iTree 中的平均路径长度越短,得分越接近 1,表明数据 x 越异常;如果数据 x 在多棵 iTree 中的平均路径长度越长,得分越接近 0,表示数据 x 越正常;如果数据 x 在多棵 iTree 中的平均路径长度接近整体均值,则打分会在 0.5 附近。

Image(filename='./image/7.png', width=650)

在这里插入图片描述

应用案例

1.清洗建模数据集,将异常样本通过无监督算法进行筛选

from pyod.models.iforest import IForest
clf = IForest(behaviour='new', bootstrap=False, contamination=0.1, max_features=1.0,max_samples='auto', n_estimators=500, n_jobs=-1, random_state=None,verbose=0)
clf.fit(x)
# IForest(behaviour='new', bootstrap=False, contamination=0.1, max_features=1.0,
#     max_samples='auto', n_estimators=500, n_jobs=-1, random_state=None,
#     verbose=0)
out_pred = clf.predict_proba(x,method ='linear')[:,1]
train['out_pred'] = out_predx = train[train.out_pred< 0.7][feature_lst]
y = train[train.out_pred < 0.7]['bad_ind']val_x =  val[feature_lst]
val_y = val['bad_ind']lr_model = LogisticRegression(C=0.1,class_weight='balanced')
lr_model.fit(x,y)
y_pred = lr_model.predict_proba(x)[:,1]
fpr_lr_train,tpr_lr_train,_ = roc_curve(y,y_pred)
train_ks = abs(fpr_lr_train - tpr_lr_train).max()
print('train_ks : ',train_ks)y_pred = lr_model.predict_proba(val_x)[:,1]
fpr_lr,tpr_lr,_ = roc_curve(val_y,y_pred)
val_ks = abs(fpr_lr - tpr_lr).max()
print('val_ks : ',val_ks)
from matplotlib import pyplot as plt
plt.plot(fpr_lr_train,tpr_lr_train,label = 'train LR')
plt.plot(fpr_lr,tpr_lr,label = 'evl LR')
plt.plot([0,1],[0,1],'k--')
plt.xlabel('False positive rate')
plt.ylabel('True positive rate')
plt.title('ROC Curve')
plt.legend(loc = 'best')
plt.show()
#train_ks :  0.4243417677672226
#val_ks :  0.4303193786076034

在这里插入图片描述
2.通过样本异常程度进行分析

train.out_pred.groupby(train.obs_mth).mean()
#obs_mth
#2018-06-30    0.192853
#2018-07-31    0.188666
#2018-09-30    0.240877
#2018-10-31    0.230139
#Name: out_pred, dtype: float64
train.out_pred.groupby(train.obs_mth).max()
#obs_mth
#2018-06-30    0.998090
#2018-07-31    0.994864
#2018-09-30    1.000000
#2018-10-31    0.968593
#Name: out_pred, dtype: float64
train.out_pred.groupby(train.obs_mth).var()
#obs_mth
#2018-06-30    0.025732
#2018-07-31    0.022533
#2018-09-30    0.037034
#2018-10-31    0.035351
#Name: out_pred, dtype: float64
train['for_pred'] = np.where(train.out_pred>0.7,1,0)
train.for_pred.groupby(train.obs_mth).sum()/train.for_pred.groupby(train.obs_mth).count()
#obs_mth
#2018-06-30    0.016825
#2018-07-31    0.010785
#2018-09-30    0.035111
#2018-10-31    0.028017
#Name: for_pred, dtype: float64

3.preA模型

  • 比如我们将上面建模的孤立森林模型作为preA
#看一下badrate
train.bad_ind.groupby(train.for_pred).sum()/train.bad_ind.groupby(train.for_pred).count()
#for_pred
#0    0.016417
#1    0.122995
#Name: bad_ind, dtype: float64

可也看到异常值超过0.7的客群badrate达到了12%,将这一部分人拒绝会使我们的收益有所提高。

4.冷启动项目/反欺诈模型

  • 假设前面的A卡没有标签,我们来看一下直接无监督建模的模型实际效果会是怎么样
y_pred = clf.predict_proba(x,method ='linear')[:,1]
fpr_lr_train,tpr_lr_train,_ = roc_curve(y,y_pred)
train_ks = abs(fpr_lr_train - tpr_lr_train).max()
print('train_ks : ',train_ks)y_pred = clf.predict_proba(val_x,method ='linear')[:,1]
fpr_lr,tpr_lr,_ = roc_curve(val_y,y_pred)
val_ks = abs(fpr_lr - tpr_lr).max()
print('val_ks : ',val_ks)
from matplotlib import pyplot as plt
plt.plot(fpr_lr_train,tpr_lr_train,label = 'train LR')
plt.plot(fpr_lr,tpr_lr,label = 'evl LR')
plt.plot([0,1],[0,1],'k--')
plt.xlabel('False positive rate')
plt.ylabel('True positive rate')
plt.title('ROC Curve')
plt.legend(loc = 'best')
plt.show()
#train_ks :  0.3302166460813136
#val_ks :  0.3233653844655018

在这里插入图片描述

model = clf
row_num, col_num = 0, 0
bins = 20
Y_predict = [s[1] for s in model.predict_proba(val_x)]
Y = val_y
nrows = Y.shape[0]
lis = [(Y_predict[i], Y[i]) for i in range(nrows)]
ks_lis = sorted(lis, key=lambda x: x[0], reverse=True)
bin_num = int(nrows/bins+1)
bad = sum([1 for (p, y) in ks_lis if y > 0.5])
good = sum([1 for (p, y) in ks_lis if y <= 0.5])
bad_cnt, good_cnt = 0, 0
KS = []
BAD = []
GOOD = []
BAD_CNT = []
GOOD_CNT = []
BAD_PCTG = []
BADRATE = []
dct_report = {}
for j in range(bins):ds = ks_lis[j*bin_num: min((j+1)*bin_num, nrows)]bad1 = sum([1 for (p, y) in ds if y > 0.5])good1 = sum([1 for (p, y) in ds if y <= 0.5])bad_cnt += bad1good_cnt += good1bad_pctg = round(bad_cnt/sum(val_y),3)badrate = round(bad1/(bad1+good1),3)ks = round(math.fabs((bad_cnt / bad) - (good_cnt / good)),3)KS.append(ks)BAD.append(bad1)GOOD.append(good1)BAD_CNT.append(bad_cnt)GOOD_CNT.append(good_cnt)BAD_PCTG.append(bad_pctg)BADRATE.append(badrate)dct_report['KS'] = KSdct_report['BAD'] = BADdct_report['GOOD'] = GOODdct_report['BAD_CNT'] = BAD_CNTdct_report['GOOD_CNT'] = GOOD_CNTdct_report['BAD_PCTG'] = BAD_PCTGdct_report['BADRATE'] = BADRATE
val_repot = pd.DataFrame(dct_report)
val_repot

在这里插入图片描述
相比于逻辑回归有监督的评分卡来看效果还是稍差一些的,但是对于无监督学习来说效果是非常不错的。当然实际场景可能没有这么好,毕竟这里面的变量是通过有监督的方式筛选出来的,缺失值也填补成了BIVAR图最好看的样子。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/66924.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

服务器系统杀毒系统崩溃怎么恢复,系统崩溃是什么原因导致的

大家在使用电脑的时候&#xff0c;经常都是需要安装一些软件和其他东西的。但是在安装软件的时候&#xff0c;很容易让一些病毒侵入电脑。一旦病毒侵入了电脑&#xff0c;就很容易让电脑系统崩溃。那么系统崩溃是什么原因导致的呢&#xff1f;下面就来告诉大家系统崩溃的原因及…

GitLab 用邮件找回密码

这两天登陆GitLab 死活进不去&#xff0c;使用邮件找回密码&#xff0c;也收不到邮件&#xff0c;后来我尝试用以下方式 就可以进去了 打开网址&#xff1a;https://about.gitlab.com/get-help/ 点进去 https://gitlab.com/users/confirmation/new 希望能帮到其他的遇到此类…

Mac自带的邮件 添加邮箱 无法验证账户或密码【已解决】

①首先登录你要添加的邮箱&#xff08;本文演示用的是网易邮箱&#xff09; ②在邮箱-设置 页面&#xff0c;找到POP3/SMTP/IMAP选项 ③POP3/SMTP/IMAP原本是关闭的&#xff0c;需要点击开启 ④手机扫码发送短信 ④验证成功之后有一串字母&#xff08;注意&#xff1a;这…

【mac 环境】邮箱密码修改后,foxmail无法正常接收邮件

原因&#xff1a;邮箱密码修改&#xff0c;max上的foxmail客户端无法正常收邮件&#xff0c;网页版的邮箱正常接收邮件 问题情况&#xff1a; 点击高级设置 解决方法&#xff1a; 1、登陆网页版邮箱》设置》POP3/SMTP/IMAP 2、开启IMAP/SMTP服务 3、通过短信验证&#xff0c;生…

如何整店导出天猫店铺商品主图及详情图

怎样一键导出天猫的整店商品图片包含主图、详情图、属性图、及主图视频&#xff0c;今天小编选用一个好方法并能快速导出并分类保存&#xff0c;一起来看看。 1.双击打开载图助手&#xff0c;还没有安装的朋友可在百度上搜索并安装&#xff0c;如图&#xff1a; 2.打开软件的整…

Android仿淘宝、京东Banner滑动查看图文详情

文章目录 写在前面效果图原理分析核心代码源码地址 写在前面 本文基于 ViewPager2 实现的 Banner 效果&#xff0c;进而实现了仿淘宝、京东Banner滑动至最后一页时继续滑动来查看图文详情的效果。关于 ViewPager2 的原理及其封装&#xff0c;可以参见之前的两篇文章&#xff1…

新锐潮流男装品牌CHINISM成功上线巨益全渠道电商中台

CHINISM是杭州麟术服饰有限公司旗下的潮流快时尚男装品牌&#xff0c;2012年创建于浙江杭州&#xff0c;经营产品包含服装、服饰、鞋帽、箱包等多项品类。致力于为青年一代提供全场景穿搭方案&#xff0c;通过简约舒适的服饰单品&#xff0c;构建“高级感衣橱”&#xff0c;将造…

跨境电商如何打造爆款主图

某种程度上来讲&#xff0c;一张好的主图决定了80%以上的点击率&#xff0c;如何设计出一张高点击率的主图是所有卖家最关心的问题。虽然你之前靠listing的优化让你进到了首页。然而你以为流量就会乖乖的来了吗&#xff1f;NO&#xff01;你只是带球到进区了&#xff0c;还差最…

电商女装评论数据集分析

探索女性服装电子商务数据集 背景描述 这是一个女性服装电子商务数据集&#xff0c;围绕客户的评论撰写。数据具有9个特征&#xff0c;可以从多个维度解析文本。 由于是真实的商业数据&#xff0c;所以做了匿名处理&#xff0c;评论文本和正文中对该公司的引用被替换为“零售商…

零门槛一键生成PPT,利用人工智能快速提高办公效率(无需第三方插件)

人工智能技术的发展正以惊人的速度改变着我们的世界&#xff0c;今天给大家介绍下利用ChatGPT快速生成PPT的方法&#xff0c;它能够帮助你一键生成PPT内容和漂亮的PPT文档&#xff0c;无需繁琐的设计和排版&#xff0c;只需要与ChatGPT交流&#xff0c;你就能轻松拥有一份令人赞…

面向开发者的 LLM 入门课程

文章目录 面向开发者的 LLM 入门课程项目简介项目意义项目受众项目亮点内容大纲一、面向开发者的 Prompt Engineering二、搭建基于 ChatGPT 的问答系统三、使用 LangChain 开发应用程序四、Prompt 高级技巧(暂未完成)配套视频致谢LICENSE面向开发者的 LLM 入门课程 项目简介…

安卓软件自动跳转和按钮跳转

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、创建项目与三个页面二、实现自动跳转三、实现点击跳转和传递内容与内容显示 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、创…

Android 从网页中跳转到APP

最近&#xff0c;在使用QQ和微信等SDK来实现分享网页的时候&#xff0c;发现&#xff0c;SDK已经为页面跳转回应用提供了基本的数据支持。我们只需在应用里和被分享的网页进行简单的设置&#xff0c;即可实现此功能。 那么我们先来看下网页跳转回应用的实现原理。 就Android平…

Android利用Intent实现Activity页面跳转闪退解决方案

当我们利用Intent跳转&#xff1a; btnLogin.setOnClickListener(new View.OnClickListener() {Overridepublic void onClick(View view) {//当点击了登入按钮&#xff0c;跳转到相应activity页面Intent intent new Intent(MainActivity.this, LoginActivity.class);startActi…

phonegap跳转Activity android插件调用原生

Phonegap的插件 调用本地的Activity 查看我上一篇插件开发的文章: http://blog.csdn.net/aaawqqq/article/details/20401111 本节主要记录调用Activity的方式; 并提供 插件Demo下载 插件开发4个步骤: 1 在assents 目录下的 cordova-plugins.js文件添加配置 2 在asse…

关于安卓手机的微信内置浏览器中页面跳转失效的问题

Write By Monkeyfly 以下内容均为原创&#xff0c;如需转载请注明出处。 前提 今天下午在JS前端群里有人问了一个问题&#xff1a; 在微信浏览器中&#xff0c;window.location.href这个跳转方法不能用吗&#xff1f;在安卓手机试过了不行&#xff0c;但是ios可以&#xff…

安卓页面的跳转(按钮点击跳转、自动跳转)

一.创建新页面 在eclipse中建立安卓工程后&#xff0c;默认会有一个页面MainActivity&#xff0c;要实现多个页面的跳转&#xff0c;首先需要建立新的页面 在eclipse建立新的页面过程如下&#xff1a; 要添加的新页面的工程下src 右键---->New—>Other—>选择Android…

安卓跳转按钮的闪退问题

不知道为什么 跳转按钮有时可以跳转有时会闪退 程序并没有报错&#xff0c;求大神指导&#xff01; 闪退的次数特别多&#xff01;

android app跳转到微信

今天写这片文章主要是记录下 app跳转到微信的实现方法&#xff0c;我的项目需求是跳转到微信公众号&#xff0c;由于微信官方关闭了这个直接可以跳到公众号的接口&#xff0c;只能 从app打开微信&#xff0c;让用户自己去搜索。 我的项目需求&#xff1a; 点击跳转微信的时候&…

Android页面跳转(Intent)

Android 意图的使用&#xff08;Intent&#xff09; 显式四种跳转方式一二三四布局代码效果 隐式意图和隐式意图的跳转Intent概述Action属性Data属性Category属性按home键时启动自己做的应用 Component属性Extra属性&#xff08;重点&#xff09;Bundle传递序列化对象 Type属性…