XGBoost 与 信用卡诈骗数据集

在Github 上面找到了一个信用卡诈骗数据集:

https://github.com/georgymh/ml-fraud-detection

数据源于 kaggle 的信用卡诈骗数据。

其中给出了三种大方法,分别是神经网络,kmeans,以及逻辑回归。

但是今天我想要用XGBoost 试一试。

import sklearn as sk 
import xgboost as xgb 
import numpy as np 
import pandas as pd 
from sklearn.model_selection import train_test_split # 功能:数据集按比例切分为训练集和测试集
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.preprocessing import scale # 数据集标准化
import matplotlib.pyplot as plt
from pandas_ml import ConfusionMatrix # 引入混淆矩阵
# https://github.com/pandas-ml/pandas-ml/

df = pd.read_csv('creditcard.csv', low_memory=False)

X = df.iloc[:,:-1] # 基于位置的纯整数索引
y = df['Class'] # 类别
X_scaled = scale(X) # 标准化

train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.35 ,random_state = 12) 

dtrain = xgb.DMatrix(train_X, label = train_y)
dtest = xgb.DMatrix(test_X, label = test_y)

param = {                          
    # --------------- Tree Booster 参数  --------------- 
    'eta':0.3,                     # 每个循环的学习步长,就是sklearn的learning_rate
    'booster':'gbtree',            # gbtree使用基于树的模型进行提升计算,gblinear使用线性模型进行提升计算
    'max_depth':5,                 # 每棵树的最大深度,默认6
    'silent':1,                    # 默认0,而1表示静默模式开启,不会输出任何信息
    # ---------------------------------------------------------------------
    'num_class':2,                 # 类别个数,记得改!
    # ---------------------------------------------------------------------
    'min_child_weight':1.0,        # 决定最小叶子节点样本权重和
    # 'max_leaf_nodes':            # 树上最大的节点或叶子的数量。 可以替代max_depth的作用。
    'scale_pos_weight':1.0,        # 调节正负样本不均衡问题
    'gamma':0.1,                   # 这个参数的值越大,算法越保守,默认0
    'max_delta_step':0,            # 这参数限制每棵树权重改变的最大步长。0意味着没有约束。
    'subsample':1.0,               # 控制对于每棵树,随机采样的比例。 
                                   # 减小这个参数的值,算法会更加保守,避免过拟合。
                                   # 如果这个值设置得过小,它可能会导致欠拟合。一般0.5-1
    'colsample_bytree':1.0,        # 用来控制每棵随机采样的列数的占比(每一列是一个特征)。一般0.5-1
    'colsample_bylevel':1.0,       # 控制树的每一级的每一次分裂,对列数的采样的占比。
    # 'scale_pos_weight':1,          # 在各类别样本十分不平衡时,把这个参数设定为一个正值,可以使算法更快收敛
    # --------------- Linear Booster 参数 ---------------
    # 'lambda_bias':0,             # 在偏置上的L2正则
    # 'lambda':1,                  # 权重的L2正则化项。默认1
    # 'alpha':1,                   # 权重的L1正则化项。默认1
    # --------------- Task 参数 ---------------
    'objective':'multi:softprob',   # 定义学习任务及相应的学习目标
            
    #'objective':'reg:linear',      # 线性回归
    #'objective':'reg:logistic',    # 逻辑回归
    #'objective':'binary:logistic', # 二分类的逻辑回归问题,输出为概率
    #'objective':'binary:logitraw', # 二分类的逻辑回归问题,输出结果为 wTx,wTx指机器学习线性模型f(x)=wTx+b
    #'objective':'count:poisson'    # 计数问题的poisson回归,输出结果为poisson分布
    #'objective':'multi:softmax'    # 让XGBoost采用softmax目标函数处理多分类问题,同时需要设置参数num_class
    #'objective':'multi:softprob'   # 和softmax一样,但是输出的是ndata * nclass的向量,
                                    # 可以将该向量reshape成ndata行nclass列的矩阵。
                                    # 每行数据表示样本所属于每个类别的概率。
                
    'base_score':0.5,               # 所有实例的初始预测评分, global bias
    # 'eval_metric'
    'seed':0                        # 默认为0
}
num_round = 20  # 循环次数

bst = xgb.train(param, dtrain, num_round) # 参数 + 训练集 + 循环次数
preds = bst.predict(dtest) # 对测试集作出预测
print("训练完成")

best_preds = np.asarray([np.argmax(line) for line in preds]) # np.argmax(line) 返回沿着line轴的最大值的索引
                                                             # np.asarray 将列表转换为数组

# 精确度(Precision):
# P = TP/(TP+FP) ;  反映了被分类器判定的正例中真正的正例样本的比重
print("精确度(Precision):", precision_score(test_y, best_preds, average='macro')) # 97.32%
print("召回率(Recall):", recall_score(test_y, best_preds, average='macro')) # 90.34%

predicted_y = np.array(best_preds)
right_y = np.array(test_y)

# 混淆矩阵的每一列代表了预测类别,
# 每一列的总数表示预测为该类别的数据的数目;
# 每一行代表了数据的真实归属类别,
# 每一行的数据总数表示该类别的数据实例的数目。
confusion_matrix = ConfusionMatrix(right_y, predicted_y)
# print("Confusion matrix:\n%s" % confusion_matrix)
# confusion_matrix.plot(normalized=True)
# plt.show()
confusion_matrix.print_stats()

'''
population: 99683
P: 176
N: 99507
PositiveTest: 150
NegativeTest: 99533
TP: 142
TN: 99499
FP: 8
FN: 34
TPR: 0.806818181818
TNR: 0.999919603646
PPV: 0.946666666667
NPV: 0.99965840475
FPR: 8.03963540253e-05
FDR: 0.0533333333333
FNR: 0.193181818182
ACC: 0.999578664366
F1_score: 0.871165644172
MCC: 0.87374835762
informedness: 0.806737785464
markedness: 0.946325071417
prevalence: 0.00176559694231
LRP: 10035.5071023
LRN: 0.193197350544
DOR: 51944.3308824
FOR: 0.000341595249817
'''

讲道理注释已经很清楚了,最后的结果也不差。

进一步的问题在于,如何使用类似 SKlearn 中的 balance 参数,让少数的诈骗1和大多数的非诈骗0均衡一下,让1的学习权重更重。

这样的后果就是 False Negative 值降低,但是False Positive 值急剧增高。关键看采用哪种策略吧。


目前的研究在于这个

'scale_pos_weight':1.0,        # 调节正负样本不均衡问题

这个参数是 XGBoost 的 SKlearn API中的,如果直接使用XGBoost好像就没有这个参数?当然也可能是我不明白。反正目前的参数是不错的。


相对的,在 Github 中的程序有一个线性回归的例子就带有这个 balance 参数,效果很奇妙...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章