【机器学习】Kaggle实战信用卡反欺诈预测(场景解析、数据预处理、特征工程、模型训练、模型评估与优化)
构建信用卡反欺诈预测模型
建模思路
本项目需解决的问题
本项目通过利用信用卡的历史交易数据,进行机器学习,构建信用卡反欺诈预测模型,提前发现客户信用卡被盗刷的事件。
项目背景
数据集包含由欧洲持卡人于2013年9月使用信用卡进行交的数据。此数据集显示两天内发生的交易,其中284,807笔交易中有492笔被盗刷。数据集非常不平衡,
积极的类(被盗刷)占所有交易的0.172%。
它只包含作为PCA转换结果的数字输入变量。不幸的是,由于保密问题,我们无法提供有关数据的原始功能和更多背景信息。特征V1,V2,… V28是使用PCA
获得的主要组件,没有用PCA转换的唯一特征是“时间”和“量”。特征’时间’包含数据集中每个事务和第一个事务之间经过的秒数。特征“金额”是交易金额,此特
征可用于实例依赖的成本认知学习。特征’类’是响应变量,如果发生被盗刷,则取值1,否则为0。
以上取自Kaggle官网对本数据集部分介绍(谷歌翻译),关于数据集更多介绍请参考《Credit Card Fraud Detection》。
场景解析(算法选择)
首先,我们拿到的数据是持卡人两天内的信用卡交易数据,这份数据包含很多维度,要解决的问题是预测持卡人是否会发生信用卡被盗刷。信用卡持卡人是否会发生被盗刷只有两种可能,发生被盗刷或不发生被盗刷。又因为这份数据是打标好的(字段Class是目标列),也就是说它是一个监督学习的场景。于是,我们判定信用卡持卡人是否会发生被盗刷是一个二元分类问题,意味着可以通过二分类相关的算法来找到具体的解决办法,本项目选用的算法是逻辑斯蒂回归(Logistic Regression)。
分析数据
数据是结构化数据 ,不需要做特征抽象。特征V1至V28是经过PCA处理,而特征Time和Amount的数据规格与其他特征差别较大,需要对其做特征缩放,将特征缩放至同一个规格。在数据质量方面 ,没有出现乱码或空字符的数据,可以确定字段Class为目标列,其他列为特征列。
模型评估
这份数据是全部打标好的数据,可以通过交叉验证的方法对训练集生成的模型进行评估。70%的数据进行训练,30%的数据进行预测和评估。
场景总结
现对该业务场景进行总结如下:
- 根据历史记录数据学习并对信用卡持卡人是否会发生被盗刷进行预测,二分类监督学习场景,选择逻辑斯蒂回归(Logistic Regression)算法。
- 数据为结构化数据,不需要做特征抽象,但需要做特征缩放。
数据文件
1、数据预处理
1.1、导包
import numpy as np
import pandas as pd
pd.set_option('display.float_format',lambda x :'%.4f' % x)import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import seaborn as sns
import missingno as msno # 可视化工具,pip install missingnofrom sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import train_test_splitfrom sklearn.metrics import auc,roc_auc_score,roc_curve,recall_score,accuracy_score,classification_reportfrom sklearn.preprocessing import StandardScaler
import warnings
warnings.filterwarnings('ignore')
1.2、解码数据
data = pd.read_csv('./creditcard.csv')
data.head()
data.tail()
5 rows × 31 columns
print(data.shape)
data.info()
(284807, 31)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 284807 entries, 0 to 284806
Data columns (total 31 columns):# Column Non-Null Count Dtype
--- ------ -------------- ----- 0 Time 284807 non-null float641 V1 284807 non-null float642 V2 284807 non-null float643 V3 284807 non-null float644 V4 284807 non-null float645 V5 284807 non-null float646 V6 284807 non-null float647 V7 284807 non-null float648 V8 284807 non-null float649 V9 284807 non-null float6410 V10 284807 non-null float6411 V11 284807 non-null float6412 V12 284807 non-null float6413 V13 284807 non-null float6414 V14 284807 non-null float6415 V15 284807 non-null float6416 V16 284807 non-null float6417 V17 284807 non-null float6418 V18 284807 non-null float6419 V19 284807 non-null float6420 V20 284807 non-null float6421 V21 284807 non-null float6422 V22 284807 non-null float6423 V23 284807 non-null float6424 V24 284807 non-null float6425 V25 284807 non-null float6426 V26 284807 non-null float6427 V27 284807 non-null float6428 V28 284807 non-null float6429 Amount 284807 non-null float6430 Class 284807 non-null int64
dtypes: float64(30), int64(1)
memory usage: 67.4 MB
data.describe().T
msno.matrix(data)
<AxesSubplot:>
data.isnull().sum().sum()
0
2、特征工程
2.1、目标变量
fig,axs = plt.subplots(1,2,figsize = (14,7))sns.countplot(x = 'Class',data = data,ax = axs[0])
axs[0].set_title('Frequency of each Calss')data['Class'].value_counts().plot(kind = 'pie',ax = axs[1],autopct = '%1.2f%%')
axs[1].set_title('Percent of each Class')
Text(0.5, 1.0, 'Percent of each Class')
data.groupby(by = 'Class').size()
Class
0 284315
1 492
dtype: int64
2.2、特征衍生
data.head() # 时间以秒为单位,离散性太强
5 rows × 31 columns
data['Hour'] = data['Time'].apply(lambda x : divmod(x,3600)[0])
data
284807 rows × 32 columns
2.3、特征选择
2.3.1、信用卡正常消费和盗刷对比
XFraud = data.loc[data['Class'] == 1] # 盗刷
XnonFraud = data.loc[data['Class'] == 0] # 正常消费correlationNonFraud = XnonFraud.loc[:,data.columns != 'Class'].corr()mask = np.zeros_like(correlationNonFraud)index = np.triu_indices_from(correlationNonFraud) # 右上部分的索引
mask[index] = True # mask 面具,0没有面具,1表示有面具kw = {'width_ratios':[1,1,0.05],'wspace':0.2}
f,(ax1,ax2,ax3) = plt.subplots(1,3,gridspec_kw=kw,figsize = (22,9))cmap = sns.diverging_palette(220,8,as_cmap = True) # 一系列颜色
sns.heatmap(correlationNonFraud,ax = ax1,vmin = -1,vmax = 1,square=False,linewidths=0.5,mask = mask,cbar=False,cmap= cmap)
ax1.set_title('Normal')correlationFraud = XFraud.loc[:,data.columns != 'Class'].corr()
sns.heatmap(correlationFraud,vmin = -1,vmax= 1,cmap = cmap,ax = ax2,square=False,linewidths=0.5,mask = mask,yticklabels=True,cbar_ax=ax3,cbar_kws={'orientation':'vertical','ticks':[-1,-0.5,0,0.5,1]})ax2.set_title('Fraud')
Text(0.5, 1.0, 'Fraud')
从上图可以看出,信用卡被盗刷的事件中,部分变量之间的相关性更明显。其中变量V1、V2、V3、V4、V5、V6、V7、V9、V10、V11、V12、V14、V16、V17和V18以及V19之间的变化在信用卡被盗刷的样本中呈性一定的规律。
特征V8、V13 、V15 、V20 、V21 、V22、 V23 、V24 、V25 、V26 、V27 和V28规律不明显!
from matplotlib import colors
plt.colormaps()
['Accent','Accent_r','Blues','Blues_r','BrBG',...'viridis','viridis_r','vlag','vlag_r','winter','winter_r']
2.3.2、交易金额和交易次数
f,(ax1,ax2) = plt.subplots(2,1,sharex=True,figsize = (16,6))ax1.hist(data['Amount'][data['Class'] == 1],bins = 30)
ax1.set_title('Fraud')
plt.yscale('log')ax2.hist(data['Amount'][data['Class'] == 0],bins = 100)
ax2.set_title('Normal')plt.xlabel('Amount($)')
plt.ylabel('count')
plt.yscale('log')
信用卡被盗刷发生的金额与信用卡正常用户发生的金额相比呈现散而小的特点,这说明信用卡盗刷者为了不引起信用卡卡主的注意,更偏向选择小金额消费。
2.3.3、信用卡盗刷时间
参数介绍:
- size 每个面的高度(英寸) 标量
- aspect 纵横比 标量
sns.factorplot(x = 'Hour',data = data,kind = 'count',palette = 'ocean',size = 6,aspect = 3)
<seaborn.axisgrid.FacetGrid at 0x292aee31670>
每天早上9点到晚上11点之间是信用卡消费的高频时间段。
2.3.4、交易金额和交易时间关系
f,(ax1,ax2) = plt.subplots(2,1,sharex=True,figsize = (16,6))cond1 = data['Class'] == 1
ax1.scatter(data['Hour'][cond1],data['Amount'][cond1])
ax1.set_title('Fraud')cond2 = data['Class'] == 0
ax2.scatter(data['Hour'][cond2],data['Amount'][cond2])
ax2.set_title('Normal')
Text(0.5, 1.0, 'Normal')
sns.catplot(x = 'Hour',kind = 'count',data = data[cond1],height=9,aspect=2)
<seaborn.axisgrid.FacetGrid at 0x292af9cd430>
从上图可以看出,在信用卡被盗刷样本中,离群值发生在客户使用信用卡消费更低频的时间段。信用卡被盗刷数量案发最高峰在第一天上午11点达到43次,其余发生信用卡被盗刷案发时间在晚上时间11点至第二早上9点之间,说明信用卡盗刷者为了不引起信用卡卡主注意,更喜欢选择信用卡卡主睡觉时间和消费频率较高的时间点作案;同时,信用卡发生被盗刷的最大值也就只有2,125.87美元。
data['Amount'][cond1].max()
2125.87
2.3.5、特征分布(帮助筛选特征!!!)
data.head()
5 rows × 32 columns
from matplotlib import font_manager
fm = font_manager.FontManager()
[font.name for font in fm.ttflist]
['DejaVu Serif Display','DejaVu Sans Mono','cmss10','DejaVu Serif','DejaVu Sans','STIXSizeFourSym','STIXNonUnicode','cmtt10',....'Century Schoolbook','Calisto MT','Calibri','Malgun Gothic','Britannic Bold','Matura MT Script Capitals']
sns.__version__
'0.11.1'
data
284807 rows × 32 columns
plt.rcParams['font.family'] = 'STKaiti'
v_feat = data.iloc[:,1:29].columns
plt.figure(figsize=(16,4 * 28))
cond1 = data['Class'] == 1
cond2 = data['Class'] == 0gs = gridspec.GridSpec(28,1) # 子视图
for i,cn in enumerate(v_feat):ax = plt.subplot(gs[i])sns.distplot(data[cn][cond1],bins = 50) # 欺诈sns.distplot(data[cn][cond2],bins = 100) # 正常消费ax.set_title('特征概率分布图' + cn)
上图是不同变量在信用卡被盗刷和信用卡正常的不同分布情况,我们将选择在不同信用卡状态下的分布有明显区别的变量。因此剔除变量V8、V13 、V15 、V20 、V21 、V22、 V23 、V24 、V25 、V26 、V27 和V28变量。这也与我们开始用相关性图谱观察得出结论一致。同时剔除变量Time,保留离散程度更小的Hour变量。
droplist = ['V8','V13','V15','V20','V21','V22','V23','V24','V25','V26','V27','V28','Time']data_new = data.drop(labels=droplist,axis = 1)
display(data.shape, data_new.shape)
(284807, 32)(284807, 19)
data_new.head()
特征从31个缩减至18个(不含目标变量)。
2.4、特征缩放
由于特征Hour和Amount的规格和其他特征相差较大,因此我们需对其进行特征缩放。
col = ['Amount','Hour']
sc = StandardScaler() # Z-score归一化data_new[col] = sc.fit_transform(data_new[col])
data_new.head()
data_new.describe().T
2.5、特征重要性排序
feture = list(data_new.columns)
print(feture)
['V1', 'V2', 'V3', 'V4', 'V5', 'V6', 'V7', 'V9', 'V10', 'V11', 'V12', 'V14', 'V16', 'V17', 'V18', 'V19', 'Amount', 'Class', 'Hour']
feture.remove('Class') # 特征名,修改原数据
feture
['V1','V2','V3','V4','V5','V6','V7','V9','V10','V11','V12','V14','V16','V17','V18','V19','Amount','Hour']
- 构建X变量和y变量
X = data_new[feture]
y = data_new['Class']
display(X.head(),y.head())
0 0
1 0
2 0
3 0
4 0
Name: Class, dtype: int64
- 利用随机森林的feature importance对特征的重要性进行排序
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier()clf.fit(X,y)
clf.feature_importances_
array([0.01974556, 0.015216 , 0.02202158, 0.03775329, 0.01995699,0.02257269, 0.02873717, 0.04056692, 0.08524621, 0.06078786,0.18454186, 0.12167233, 0.06079882, 0.19714222, 0.03220492,0.01833037, 0.01716956, 0.01553564])
plt.rcParams['figure.figsize'] = (12,6)
plt.style.use('fivethirtyeight')
from matplotlib import stylestyle.available
['Solarize_Light2','_classic_test_patch','bmh','classic','dark_background','fast','fivethirtyeight','ggplot','grayscale','seaborn','seaborn-bright','seaborn-colorblind','seaborn-dark','seaborn-dark-palette','seaborn-darkgrid','seaborn-deep','seaborn-muted','seaborn-notebook','seaborn-paper','seaborn-pastel','seaborn-poster','seaborn-talk','seaborn-ticks','seaborn-white','seaborn-whitegrid','tableau-colorblind10']
len(feture)
18
importances = clf.feature_importances_
feat_name = feture
feat_name = np.array(feat_name)
index = np.argsort(importances)[::-1]plt.bar(range(len(index)),importances[index],color = 'lightblue')
plt.step(range(18),np.cumsum(importances[index]))
_ = plt.xticks(range(18),labels=feat_name[index],rotation = 'vertical',fontsize = 14)
feat_name
['V1','V2','V3','V4','V5','V6','V7','V9','V10','V11','V12','V14','V16','V17','V18','V19','Amount','Hour']
3、模型训练
3.1、过采样
前面提到,目标列Class呈现较大的样本不平衡,会对模型学习造成困扰。样本不平衡常用的解决方法有过采样和欠采样,本项目处理样本不平衡采用的是过采样的方法,具体操作使用SMOTE(SyntheticMinority Oversampling Technique)
# pip install imblearn
from imblearn.over_sampling import SMOTE # 近邻规则,创造一些新数据
print('在过采样之前样本比例:\n',y.value_counts())
在过采样之前样本比例:0 284315
1 492
Name: Class, dtype: int64
smote = SMOTE()
# X,y是数据
X,y = smote.fit_resample(X,y)
print('在过采样之后样本比例是:\n',y)
在过采样之后样本比例是:0 0
1 0
2 0
3 0
4 0..
568625 1
568626 1
568627 1
568628 1
568629 1
Name: Class, Length: 568630, dtype: int64
y.value_counts()
0 284315
1 284315
Name: Class, dtype: int64
3.2、算法建模
3.2.1、准确率
model = LogisticRegression()
model.fit(X,y) # 样本是均衡的
y_ = model.predict(X)
print('逻辑斯蒂回归算准确率是:',accuracy_score(y,y_))
# 信用卡反欺诈,更希望算法,找到盗刷的交易!
# 正常交易,不关心!
逻辑斯蒂回归算准确率是: 0.9380581397393736
混淆矩阵和召回率
from sklearn.metrics import confusion_matrix # 混淆矩阵cm = confusion_matrix(y,y_)
print(cm)
recall = cm[1,1]/(cm[1,1] + cm[1,0])
print('召回率:',recall)
[[276963 7352][ 27870 256445]]
召回率: 0.9019749221813833
def plot_confusion_matrix(cm, classes,title='Confusion matrix',cmap=plt.cm.Blues):"""绘制预测结果与真实结果的混淆矩阵"""plt.imshow(cm, interpolation='nearest', cmap=cmap)plt.title(title)plt.colorbar()tick_marks = np.arange(len(classes))plt.xticks(tick_marks, classes, rotation=0)plt.yticks(tick_marks, classes)thresh = cm.max() / 2.for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):plt.text(j, i, cm[i, j],horizontalalignment="center",color="white" if cm[i, j] > thresh else "black")plt.tight_layout()plt.ylabel('True label')plt.xlabel('Predicted label')
import itertools
plot_confusion_matrix(cm,classes=[0,1])
3.2.2、ROC与AUC
proba_ = model.predict_proba(X)[:,1]# 索引1,表示获取类别1的概率,正样本,阳性,信用卡盗刷fpr,tpr,thesholds_ = roc_curve(y,proba_)roc_auc = auc(fpr,tpr) # 曲线下面积# 绘制 ROC曲线
plt.title('Receiver Operating Characteristic')
plt.plot(fpr, tpr, 'b',label='AUC = %0.5f'% roc_auc)
plt.legend(loc='lower right')
plt.plot([0,1],[0,1],'r--')
plt.xlim([-0.1,1.0])
plt.ylim([-0.1,1.01])
plt.ylabel('True Positive Rate')
plt.xlabel('False Positive Rate')
Text(0.5, 0, 'False Positive Rate')
4、模型评估与优化
上一个步骤中,我们的模型训练和测试都在同一个数据集上进行,这样导致模型产生过拟合的问题。
一般来说,将数据集划分为训练集和测试集有3种处理方法:
- 留出法(hold-out)
- 交叉验证法(cross-validation)
- 自助法(bootstrapping)
本次项目采用的是交叉验证法划分数据集,将数据划分为3部分:训练集(training set)、验证集
(validation set)和测试集(test set)。让模型在训练集进行学习,在验证集上进行参数调优,最后使用测试集数据评估模型的性能。
模型调优我们采用网格搜索调优参数(grid search),通过构建参数候选集合,然后网格搜索会穷举各种参数组合,根据设定评定的评分机制找到最好的那一组设置。
结合cross-validation和grid search,具体操作我们采用scikit learn模块model_selection中的GridSearchCV方法。
4.1、交叉验证
- 交叉验证筛选参数
%%time
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2)# 构建参数组合
param_grid = {'C': [0.01,0.1, 1, 10, 100, 1000,],'penalty': [ 'l1', 'l2']}# 确定模型LogisticRegression,和参数组合param_grid ,cv指定10折
grid_search = GridSearchCV(LogisticRegression(),param_grid,cv=10) grid_search.fit(X_train, y_train) # 使用训练集学习算法
Wall time: 1min 5sGridSearchCV(cv=10, estimator=LogisticRegression(),param_grid={'C': [0.01, 0.1, 1, 10, 100, 1000],'penalty': ['l1', 'l2']})
- 查看最佳参数
results = pd.DataFrame(grid_search.cv_results_)
display(results)
print("Best parameters: {}".format(grid_search.best_params_))
print("Best cross-validation score: {:.5f}".format(grid_search.best_score_))
Best parameters: {'C': 10, 'penalty': 'l2'}
Best cross-validation score: 0.93776
- 测评数据的评估
y_pred = grid_search.predict(X_test)print('准确率:',accuracy_score(y_test,y_pred))
准确率: 0.9391432038408104
- 分类效果评估报告
from sklearn.metrics import classification_report
print(classification_report(y_test,y_pred))
precision recall f1-score support0 0.91 0.98 0.94 569811 0.97 0.90 0.94 56745accuracy 0.94 113726macro avg 0.94 0.94 0.94 113726
weighted avg 0.94 0.94 0.94 113726
4.2、混淆矩阵
# 生成测试数据混淆矩阵
cnf_matrix = confusion_matrix(y_test, y_pred)
np.set_printoptions(precision=2)print("Recall metric in the testing dataset: ", cnf_matrix[1,1]/(cnf_matrix[1,0]+cnf_matrix[1,1]))# 绘制模型优化后的混淆矩阵
class_names = [0,1]
plt.figure()
plot_confusion_matrix(cnf_matrix, classes=class_names, title='Confusion matrix')
Recall metric in the testing dataset: 0.9031104062031897
从上可以看出,经过交叉验证训练和参数调优后,模型的性能有较大的提升,recall值从0.818上升到
0.9318,上升幅度达到11.34%。
4.3、模型评估
解决不同的问题,通常需要不同的指标来度量模型的性能。例如我们希望用算法来预测癌症是否是恶性的,假设100个病人中有5个病人的癌症是恶性,对于医生来说,尽可能提高模型的查全率(recall)比提高查准率(precision)更为重要,因为站在病人的角度,发生漏发现癌症为恶性比发生误判为癌症是恶性更为严重。
4.3.1、混淆矩阵
# 获得预测概率值
y_pred_proba = grid_search.predict_proba(X_test) thresholds = [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9] # 设定不同阈值plt.figure(figsize=(15,10))
np.set_printoptions(precision=2)
j = 1
for t in thresholds:# 根据阈值转换为类别 y_pred = y_pred_proba[:,1] > tplt.subplot(3,3,j)j += 1# 计算混淆矩阵cnf_matrix = confusion_matrix(y_test, y_pred)print("召回率是:", cnf_matrix[1,1]/(cnf_matrix[1,0]+cnf_matrix[1,1]),end = '\t')print('准确率是:',(cnf_matrix[0,0] + cnf_matrix[1,1])/(cnf_matrix.sum()))# 绘制混淆矩阵class_names = [0,1]plot_confusion_matrix(cnf_matrix, classes=class_names)
召回率是: 0.9837342497136311 准确率是: 0.8754814202557023
召回率是: 0.957952242488325 准确率是: 0.9291103177813341
召回率是: 0.9321878579610539 准确率是: 0.9376659690835869
召回率是: 0.9182835492113842 准确率是: 0.9406292316620649
召回率是: 0.9031104062031897 准确率是: 0.9391432038408104
召回率是: 0.8919904837430611 准确率是: 0.9371559713697836
召回率是: 0.8860516345052427 准确率是: 0.9368833863848196
召回率是: 0.8795312362322671 准确率是: 0.9348433955296063
召回率是: 0.8651158692395806 准确率是: 0.9291806622935829
从上可以看出,经过交叉验证训练和参数调优后,模型的性能有较大的提升,recall值从0.818上升到
0.9318,上升幅度达到11.34%。
4.3.2、精确率-召回率
from sklearn.metrics import precision_recall_curve
thresholds = [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]
colors = ['navy', 'turquoise', 'darkorange', 'cornflowerblue', 'teal', 'red', 'yellow', 'green', 'blue']plt.figure(figsize=(12,7))j = 1
for t,color in zip(thresholds,colors):y_pred = y_pred_proba[:,1] > t #预测出来的概率值是否大于阈值 precision, recall, threshold = precision_recall_curve(y_test, y_pred)area = auc(recall, precision)cm = confusion_matrix(y_test,y_pred)# TP/(TP + FN)r = cm[1,1]/(cm[1,0] + cm[1,1])# 绘制 Precision-Recall curveplt.plot(recall, precision, color=color,label='Threshold=%s, AUC=%0.3f, recall=%0.3f' %(t,area,r))plt.xlabel('Recall')plt.ylabel('Precision')plt.ylim([0.0, 1.05])plt.xlim([0.0, 1.0])plt.title('Precision-Recall Curve')plt.legend(loc="lower left")
4.3.3、ROC曲线
thresholds = [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]
colors = ['navy', 'turquoise', 'darkorange', 'cornflowerblue', 'teal', 'red', 'yellow', 'green', 'blue']plt.figure(figsize=(12,7))j = 1
for t,color in zip(thresholds,colors):
# y_pred = grid_search.predict(X_teste) # 算法预测测试数据的值y_pred = y_pred_proba[:,1] >= t #预测出来的概率值是否大于阈值 (人为) cm = confusion_matrix(y_test,y_pred)# TP/(TP + FP)precision = cm[1,1]/(cm[0,1] + cm[1,1])fpr,tpr,_ = roc_curve(y_test,y_pred)accuracy = accuracy_score(y_test,y_pred)auc_ = auc(fpr,tpr)# 绘制 ROC curveplt.plot(fpr, tpr, color=color,label='Threshold=%s, AUC=%0.3f, precision=%0.3f' %(t , auc_,precision))plt.xlabel('FPR')plt.ylabel('TPR')plt.ylim([0.0, 1.05])plt.xlim([0.0, 1.0])plt.title('ROC Curve')plt.legend(loc="lower right")
4.3.4、各评估指标趋势图
'''
true negatives:`C_{0,0}`
false negatives: `C_{1,0}`
true positives is:`C_{1,1}`
false positives is :`C_{0,1}`
'''
thresholds = [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]
recalls = [] # 召回率
precisions = [] # 精确度
aucs = [] # 曲线下面积
y_pred_proba = grid_search.predict_proba(X_test)
for threshold in thresholds:y_ = y_pred_proba[:,1] >= thresholdcm = confusion_matrix(y_test,y_)# TP/(TP + FN)recalls.append(cm[1,1]/(cm[1,0] + cm[1,1])) # 召回率,从真的癌症患者中找出来的比例,200,85个,42.5%# TP/(TP + FP)precisions.append(cm[1,1]/(cm[0,1] + cm[1,1])) # 精确率,找到癌症患者,100个,85个真的,15个没病,预测有病fpr,tpr,_ = roc_curve(y_test,y_)auc_ = auc(fpr,tpr)aucs.append(auc_)plt.figure(figsize=(12,6))
plt.plot(thresholds,recalls,label = 'Recall')
plt.plot(thresholds,aucs,label = 'auc')
plt.plot(thresholds,precisions,label = 'precision')
plt.legend()
plt.xlabel('thresholds')
Text(0.5, 0, 'thresholds')
4.4、最优阈值
precision和recall是一组矛盾的变量。从上面混淆矩阵和PRC曲线、ROC曲线可以看到,阈值越小,
recall值越大,模型能找出信用卡被盗刷的数量也就更多,但换来的代价是误判的数量也较大。随着阈值的提高,recall值逐渐降低,precision值也逐渐提高,误判的数量也随之减少。通过调整模型阈值,控制模型反信用卡欺诈的力度,若想找出更多的信用卡被盗刷就设置较小的阈值,反之,则设置较大的阈值。
实际业务中,阈值的选择取决于公司业务边际利润和边际成本的比较;当模型阈值设置较小的值,确实能找出更多的信用卡被盗刷的持卡人,但随着误判数量增加,不仅加大了贷后团队的工作量,也会降低误判为信用卡被盗刷客户的消费体验,从而导致客户满意度下降,如果某个模型阈值能让业务的边际利润和边际成本达到平衡时,则该模型的阈值为最优值。当然也有例外的情况,发生金融危机,往往伴随着贷款违约或信用卡被盗刷的几率会增大,而金融机构会更愿意不惜一切代价守住风险的底线。
相关文章:
【机器学习】Kaggle实战信用卡反欺诈预测(场景解析、数据预处理、特征工程、模型训练、模型评估与优化)
构建信用卡反欺诈预测模型 建模思路 本项目需解决的问题 本项目通过利用信用卡的历史交易数据,进行机器学习,构建信用卡反欺诈预测模型,提前发现客户信用卡被盗刷的事件。 项目背景 数据集包含由欧洲持卡人于2013年9月使用信用卡进行交的…...
Linux(Ubuntu)下ESP-IDF下载与安装完整流程(2)
接前一篇文章:Linux(Ubuntu)下ESP-IDF下载与安装完整流程(1) 本文主要看参考官网说明,如下: 快速入门 - ESP32-S3 - — ESP-IDF 编程指南 latest 文档 Linux 和 macOS 平台工具链的标准设置 - ESP32-S3 - — ESP-IDF 编程指南 latest 文档 一、安装准备 1. Linux用...
SpringBoot3 快速启动框架
文章目录 1 SpringBoot3 介绍 1.1 SpringBoot3 简介1.2 快速入门1.3 入门总结 2 SpringBoot3 配置文件 2.1 统一配置管理概述2.2 属性配置文件使用2.3 YAML配置文件使用2.4 批量配置文件注入2.5 多环境配置和使用 3 SpringBoot 整合 springMVC 3.1 实现过程3.2 web相关配置3.3…...
Enum枚举类,静态常量类,静态类的区别
Enum枚举类,静态常量类,静态类的区别 Enum枚举类静态常量类静态类Enum枚举类,静态常量类,静态类的区别 Enum枚举类 Enum枚举类的结构组成和用法使用可以查阅 Enum枚举类与静态变量和静态数组的区别 静态常量类 public class St…...
解锁专利世界的钥匙 ——famiwei 网
在知识经济的时代,专利作为创新成果的重要体现,无论是对于企业、科研人员乃至整个社会的发展都具有举足轻重的意义。而在众多的专利网站中,famiwei 网为用户提供了一个全面、精准且高效的专利信息交流与服务的舞台。 一、卓越功能,开启专利探索之门 famiwei 网拥有一套强大的专…...
金融租赁系统的创新与发展推动行业效率提升
金融租赁系统的技术升级与创新 在当今快速发展的金融市场中,金融租赁系统的技术升级与创新充满了无限可能。想象一下,传统的租赁方式就像一位沉闷的老师,而新兴技术就如同一位活泼的学生,不断追求新鲜事物。通过自动化、人工智能…...
SQL-Server链接服务器访问Oracle数据
SQL Server 链接服务器访问 Oracle 离线安装 .NET Framework 3.5 方法一:使用 NetFx3.cab 文件 下载 NetFx3.cab 文件,并将其放置在 Windows 10 系统盘的 C:Windows 文件夹中。 以管理员身份运行命令提示符,输入以下命令并回车: …...
Sonic:开源Go语言开发的高性能博客平台
Sonic:一个用Go语言开发的高性能博客平台 简介 Sonic,一个以其速度如声速般快速而命名的博客平台,是一个用Go语言开发的高性能博客系统。正如其名字所暗示的,Sonic旨在提供一个简单而强大的博客解决方案。这个项目受到了Halo项目…...
【react】常见的性能优化 1
目录 常见的 React 性能优化手段 1. 使用 useMemo 和 useCallback 缓存数据和函数 2. 使用 React.memo 缓存组件 3. 组件懒加载 4. 合理使用 key 5. 在组件销毁时清除定时器/事件 6. 使用 Suspense 和 Lazy 拆分组件 7. 使用 Fragment 避免额外标记 8. 避免使用内联函…...
SpringCloud源码-openFeign
LoadBalancer默认只有nacos服务发现器 openFeign与springcloud loadbalancer的结合点...
QLabel添加点击处理
在QLabel中添加点击事件有三种方式,分别是 使用LinkActivated信号连接槽函数(有缺限)注册事件分发器eventFilter创建类重写鼠标事件 1. 使用LinkActivated信号 QLabel类中有LinkActivated信号,是当标签中的链接被点击的时候触发…...
Markdown表格的使用
Markdown表格的使用 前言语法详解定义表格设定表格列内容的对齐方式 使用场景及实例小结其他文章快来试试吧 Markdown表格的使用👈点击这里也可查看 前言 表格通常作为一种布局的形式,用于结构化的数据展示。 Markdown表格包含三个部分:表头…...
时间序列预测算法介绍
时间序列预测是根据时间序列数据的历史变化规律,对未来数据进行预测的方法。在给定的代码中,使用的是自回归(AR)模型中的AR(4)模型来预测光伏功率。以下将详细解释这种算法: 1. 自回归模型(AR模型…...
加密流量TLS1.2 和TLS1.3的握手区别
加密流量TLS1.2 和TLS1.3的握手区别 TLS1.2 握手均是明文 1)Client Hello 2)Server Hello 3)Certificate TLS1.3 握手中Client Hello是明文,而Server Hello中Extensions以及后面的握手信息不可见 1)Client Hello…...
MySQL数据库——主从复制
本文详细介绍 MySQL的主从复制,从原理到配置再到同步过程。 文章目录 简介核心组件主从复制的原理作用主从复制的线程模型主从复制的模式形式复制的方式设计复制机制主从复制的配置步骤优化和改进总结 简介 MySQL 主从复制(Replication)是一…...
详细说明嵌入式linux中bootcmd与bootargs差异
bootcmd 和 bootargs 是在嵌入式系统开发,特别是基于U-Boot(一个广泛应用的开源引导加载程序)环境中常见的两个重要参数,它们的区别如下: 功能用途 bootcmd: 定义:bootcmd 是U-Boot中的一个环…...
【UE5】UnrealEngine源码构建2:windows构建unreal engine 5.3.2
参考大神知乎的文章:UE5 小白也能看懂的源码编译指南 据说会耗费400G的空间。 代码本身并不大,可能是依赖特别多,毕竟看起来UE啥都能干,核心还是c++的, 【UE5】UnrealEngine源码构建1:tag为5.3.2源码clone 本着好奇+ 学习的态度,想着也许有机会能更为深入的熟悉UE的机制…...
【YOLO算法改进】ALSS-YOLO:无人机热红外图像|野生动物小目标检测
目录 论文信息 论文创新点 1.自适应轻量通道分割和洗牌(ALSS)模块 2.轻量坐标注意力(LCA)模块 3.单通道聚焦模块 4.FineSIOU损失函数 摘要 架构设计 轻量高效网络架构 - ALSS模块 LCA模块 单通道聚焦模块 损失函数优…...
时间序列预测算法---LSTM
文章目录 一、前言1.1、深度学习时间序列一般是几维数据?每个维度的名字是什么?通常代表什么含义?1.2、为什么机器学习/深度学习算法无法处理时间序列数据?1.3、RNN(循环神经网络)处理时间序列数据的思路?1.4、RNN存在哪些问题?…...
【QT】:QT图形化界面概述
Qt背景介绍 1.1 什么是Qt Qt 是⼀个跨平台的C图形⽤⼾界⾯应⽤程序框架。它为应⽤程序开发者提供了建⽴艺术级图形 界⾯所需的所有功能。它是完全⾯向对象的,很容易扩展。Qt为开发者提供了⼀种基于组件的开发模 式,开发者可以通过简单的拖拽和组合来实现…...
[论文笔记]Representation Learning with Contrastive Predictive Coding
引言 今天带来论文 Representation Learning with Contrastive Predictive Coding的笔记。 提出了一种通用的无监督学习方法从高维数据中提取有用表示,称为对比预测编码(Contrastive Predictive Coding,CPC)。使用了一种概率对比损失, 通过使用负采样使…...
Redis相关
Redis相关 什么是redis?redis可以干什么? Redis是一个c语言编写的nosql数据库(不仅仅是sql,泛指非关系型数据库,一般把非关系型数据库称为nosql数据库),数据在内存中以键值对的形式存储,读写速度快,提供数据持久化方式. 常常被广泛应用到做缓存 Redis使用场景 1.缓存 2…...
【优选算法】Binary-Blade:二分查找的算法刃(上)
文章目录 1.概念解析2.二分查找的简单模版3.二分查找的进阶模版4.x的平方根5.搜索插入位置希望读者们多多三连支持小编会继续更新你们的鼓励就是我前进的动力! 本篇是优选算法之二分查找算法,该算法是一种高效的在有序数组中查找特定元素的搜索算法 1.概…...
Docker--Docker Network(网络)
Docker Network(网络)是Docker容器之间和容器与外部网络之间的通信和连接的一种机制。以下是对Docker Network的详细解释: 一、Docker网络的重要性 Docker容器网络是为应用程序所创造的虚拟环境的一部分,它能让应用从宿主机操作…...
转化率是衡量网页设计的一个重要指标,请问如何做?
AARRR是互联网产品运营中一个非常重要的模型,这些模型的每一个步骤都涉及到转化率问题,那么AARRR是是什么呢?转化漏斗是什么吗?转化率为什么重要?设计师在做网页设计的时候,如何提升转化率呢?本…...
运维工具之syncthing工具的安装和使用
一、syncthing工具简介 Syncthing是一款开源的文件同步工具,采用Go语言编写。它支持在多个操作系统上运行,包括Windows、macOS和Linux,以及BSD、Solaris和Android等。以下是对这款软件的详细介绍,主要功能: 实时文件同…...
国产数据库-崖山使用介绍
本文档基于崖山数据库23.3 个人版本,单机(主备)部署模式的情况下的使用介绍。 数据库实例状态: NOMOUNT:仅读取参数文件,不加载数据库 MOUNT:读取控制文件,加载数据库ÿ…...
primevue的<Menu>组件
1.使用场景 2.代码 1.给你的menu组件起个引用名 2.<Menu>组件需要一个MenuItem[] 3.你要知道MenuItem[ ]的特殊的数据格式,就像TreeNode[ ]一样,数据格式不对是不渲染的。。。。 常用的属性就这几种,js语言和java不一样,J…...
【玩转23种Java设计模式】行为型模式篇:备忘录模式
软件设计模式(Design pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。 汇总目录链接&…...
便捷饭店点餐小程序的设计与实现ssm+论文源码调试讲解
第4章 系统设计 一个成功设计的系统在内容上必定是丰富的,在系统外观或系统功能上必定是对用户友好的。所以为了提升系统的价值,吸引更多的访问者访问系统,以及让来访用户可以花费更多时间停留在系统上,则表明该系统设计得比较专…...
微信小程序Uniapp
使用命令行创建项目(vuets) npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project然后用HBX打开项目 再安装依赖 npm i 再运行开发版本,生成dist目录 pnpm dev:mp-weixin 注意要设置APPid 再用微信小程序打开...
Android GameActivity(NativeActivity)读写文件
最近研究native android相关内容,其中最棘手的就是文件读写问题,最主要的是相关的文档很少。这里写下我所知道的方法。 由于本人使用的是Android14[arm64-v8a]版本的设备,能访问的路径相当有限,如果想要访问更多的路径,就不得不申…...
《计算机网络A》单选题-复习题库解析-2
目录 51、下列关于以太网网卡地址特点的说法中,不正确的是( )。 52、当一个Web Browser向一个使用标准服务器端口的Web Server提出请求时,那么在服务返回的响应包中,所使用的源端口是( ࿰…...
GPU 进阶笔记(二):华为昇腾 910B GPU
大家读完觉得有意义记得关注和点赞!!! 1 术语 1.1 与 NVIDIA 术语对应关系1.2 缩写2 产品与机器 2.1 GPU 产品2.2 训练机器 底座 CPU功耗操作系统2.3 性能3 实探:鲲鹏底座 8*910B GPU 主机 3.1 CPU3.2 网卡和网络3.3 GPU 信息 3.3…...
如何利用 ClickHouse 实现高级分析:MySQL 到 ClickHouse 实时数据同步指南
在数据驱动的时代,企业必须依靠先进的数据分析能力来提升竞争力。随着数据量的激增和业务需求的复杂化,传统的关系型数据库已经无法满足高效处理和实时分析的需求。ClickHouse 作为一款高性能的列式数据库,凭借其卓越的查询性能和可扩展性&am…...
Python读取TIF文件
在Python中,逐帧读取TIFF文件(尤其是多页TIFF文件)可以使用tifffile库或Pillow库。以下是两种方法的示例: 方法 1:使用 tifffile 逐帧读取 tifffile 是一个专门用于处理TIFF文件的库,支持多页TIFF文件的逐…...
vue3+ts+element-plus 表单el-form取消回车默认提交
问题描述:在表单el-form中的el-input中按回车后,页面会刷新,url也会改变, 回车前: 回车后: 相关代码: 解决方法1:在 el-form 上阻止默认的 submit 事件,增加 submit.pre…...
面试经典150题——滑动窗口
文章目录 1、长度最小的子数组1.1 题目链接1.2 题目描述1.3 解题代码1.4 解题思路 2、无重复字符的最长子串2.1 题目链接2.2 题目描述2.3 解题代码2.4 解题思路 3、串联所有单词的子串3.1 题目链接3.2 题目描述3.3 解题代码3.4 解题思路 4、最小覆盖子串4.1 题目链接4.2 题目描…...
目标检测之DINO详解
相关链接 论文:[2203.03605] DINO: DETR with Improved DeNoising Anchor Boxes for End-to-End Object Detectionhttps://arxiv.org/abs/2203.03605 代码:...
Linux指令
1. 将一个文件夹中的前5000张图片移动到另一个文件夹 可以使用 find 和 mv 命令来实现将一个文件夹 folder1 中的前 5000 张 jpg 图片移动到另一个文件夹 folder2。下面是具体的步骤: 首先,确保 folder2 存在。如果不存在,可以使用 mkdir 命…...
groovy:多线程 简单示例
在Groovy中,多线程编程与Java非常相似,因为Groovy运行在Java虚拟机(JVM)上,并且可以利用Java的所有并发工具。以下是一些在Groovy中实现多线程编程的方法: class MyThread extends Thread {Overridevoid…...
硬件产品:做产品,不仅仅是产品思维
目录 前言 1. 产品思维阶段 2. 流量思维阶段 3. 用户思维阶段 作者简介 前言 从思维层面来看, 做产品会经历三个阶段,分别是: 1. 产品思维阶段; 2. 流量思维阶段; 3. 用户思维阶段。 如果不理解这三个思维…...
【小程序开发】解决 HBuilder X 提示“本项目类型无法运行到小程序模拟器”
今天在hbuilder引入一个项目时,准备将该项目在微信开发者工具上运行时,发现提示“本项目类型”,如何解决这个问题? 问题如下: 第一:检查一下文件夹是否为一级文件夹(如图) 不要有多个…...
RuoYi-Vue从http升级为https(Jar+Nginx)
一、前提条件 1.已通过数字证书管理服务控制台签发证书。 2.SSL证书绑定的域名已完成DNS解析,即域名与主机IP地址相互映射。 附:阿里云网站运维检测平台 3.已在Web服务器开放443端口(HTTPS通信的标准端口)。 如果使用的是阿里云ECS服务器,请确保已经在安全组规则入方向…...
探索 Yocto-Meta-OpenEuler:嵌入式开发的强大基石
title: 探索 Yocto-Meta-OpenEuler:嵌入式开发的强大基石 date: ‘2024-11-19’ category: blog tags: Yocto-Meta-OpenEuler嵌入式系统开源项目定制化开发 sig: EmbeddedTech archives: ‘2024-12’ author:way_back summary: Yocto-Meta-OpenEuler 为嵌入式系统开…...
leetcode 3219. 切蛋糕的最小总开销 II
题目:3219. 切蛋糕的最小总开销 II - 力扣(LeetCode) 排序贪心。 开销越大的越早切。 注意m或n为1的情况。 class Solution { public:long long minimumCost(int m, int n, vector<int>& horizontalCut, vector<int>&…...
UniApp 打开文件工具,获取文件类型,判断文件类型
注意:以下代码使用 typeScript 开发,如果想在 js 中使用,可参考 npm 已经发布的包:https://www.npmjs.com/package/uni-easy-file NPM 使用 如果想直接在 npm 项目中使用可以直接执行以下命令 npm i uni-easy-file然后直接使用 …...
webpack打包node后端项目
webpack打包后端项目 后端项目写好了,感觉也可以打包一下,然后就想到了用webpack试试 先要下载webpack和webpack-cli npm install webpack webpack-cli然后创建webpack配置文件webpack.config.js 核心配置为entry、output、target 但是因为咱们是后…...
《学习之道》
《学习之道》主要讲述了以下内容: 学习的原理 大脑的两种认知模式:介绍了专注模式和发散模式。专注模式适合集中精力解决具体问题、进行深度理解和记忆推理,但长时间使用易疲惫和陷入思维定式;发散模式则让大脑在更广泛的认知网…...
随笔 | 写在2024的最后一天
. 前言 转眼又到了一年的末端。过去这一年,和前些年有些不同,变化巨大,感触良多。多到一时竟不知从何开始写。今天这篇随笔,因为时间有限,可能文法也会有些凌乱,就是想到哪里写到哪里,如果未来…...