(二十七)项目实战|交易数据异常检测(二)-python数据分析与机器学习实战(学习笔记)

文章原创,最近更新:2018-06-4

1.交叉验证
2.模型评估方法
3.正则化惩罚
4.逻辑回归模型
课程来源: python数据分析与机器学习实战-唐宇迪

课程资料:这里所涉及到的练习资料creditcard.csv相关的链接以及密码如下:
链接: https://pan.baidu.com/s/1APgU4cTAaM9zb8_xAIc41Q 密码: xgg7

1.交叉验证

这节课的主要内容是交叉验证的学习.首先要了解交叉验证,具体如下:

  • 什么是交叉验证法?

在建立分类模型时,交叉验证(Cross Validation)简称为CV,CV是用来验证分类器的性能。它的主体思想是将原始数据进行分组,一部分作为训练集,一部分作为验证集。利用训练集训练出模型,利用验证集来测试模型,以评估分类模型的性能。

训练数据上的误差叫做训练误差,它对算法模型的评价过于乐观。利用测试数据测量的是测试误差,我门报告的是测试误差。有的时候训练集上的正确率可能达到100%,但是在测试集上可能和随机猜测差不多。

  • 为什么用交叉验证法?

交叉验证用于评估模型的预测性能,尤其是训练好的模型在新数据上的表现,可以在一定程度上减小过拟合。
还可以从有限的数据中获取尽可能多的有效信息。

  • 交叉验证常用的几种方法:

    • 1.去一法 Leave-One-Out Cross Validation(记为LOO-CV)**
      它的做法是,从训练集中拿出一个样本,并在缺少这个样本的数据上训练出一个模型,然后看模型是否能对这个样本正确分类。假设样本个数有N个,则该方法一共要训练出N个模型,利用这N个模型最终的验证集的分类准确率的平均数作为此下LOO-CV分类器的性能指标。然而随着数据量的增大,工作量会剧增,在时间是处于劣势。但是它具有显著德尔优点:
      1)每一回合中几乎所有的样本皆用于训练模型,因此最接近原始样本的分布,这样评估所得的结果比较可靠。
      2)实验过程中没有随机因素会影响实验数据,确保实验过程是可以被复制的。

    • 2、k折交叉验证 K-fold Cross Validation(记为K-CV)
      K折交叉验证是以部分代价去获得去一法的大部分收益,这里的k折是吧数据分为k组。它的做法是将k-1组作为训练集训练出一个模型,然后将剩下的一组用做测试集。利用这k个模型最终的平均正确率来衡量模型的正确率。常使用的一般是5折10折,5折交叉验证是将数据分为5组。实际做法是把20%的数据拿出去作为测试集,将剩下的80%数据训练模型。使用80%或者90%的数据与使用所有数据的效果比较接近。
      使用交叉验证时,需要谨慎保持数数据的分布平衡,不能在某一折中全部是一类的数据。

学习参考链接:
1、为什么要用交叉验证
2、一篇文章,带你明白什么是过拟合,欠拟合以及交叉验证


比如有个集合叫data,通常建立机器模型的时候,先对数据进行切分或者选择,取前面80%的数据当成训练集,取20%的数据当成测试集。80%的数据是来建立一个模型,剩下的20%的数据是用来测试模型的表达效果是怎么样的?

  • 因此第一步是将数据进行切分,切分成训练集以及测试集。这部分操作是必须要做的。
  • 第二步还要在训练集进行平均切分,比如平均切分成3份,分别是数据集1,2,3。为什么要进行随机的切分呢?因为最终的测试数据集,只能够在一个最终的测试阶段,在模型以及参数都调整好之后,才能用测试集去测试当前模型的效果是怎么样的?

在建立模型的时候,不管建立什么样的模型,这个模型伴随着很多参数,有不同的参数进行选择,这个参数选择大比较好,还是选择小比较好一些?从经验值角度来说,肯定没办法很准的,怎么样去确定这个参数呢?只能通过交叉验证的方式。

那什么又叫交叉验证呢?

  • 第一次:将数据集1,2分别建立模型,用数据集3在当前权重下一个验证的效果。数据集3是个验证集,验证集是训练集的一部分。用验证集去收集模型是好还是坏?
  • 第二次:将数据集1,3分别建立模型,用数据集2在当前权重下一个验证的效果。
  • 第三次:将数据集2,3分别建立模型,用数据集1在当前权重下一个验证的效果。

为什么要验证模型3次呢?其实这些操作并非是重复的,每一次的训练集是不一样的。(比如第一次的训练集是1和2,第二次的训练集是1和3,第三次的训练集是3和2)此外验证集也是不一样的。(比如第一次的验证集是3,第二次的验证集是2,第三次的验证集是1)

现在是比较求稳的操作,如果只是求一次的交叉验证,这样的操作会存在风险。比如只做第一次交叉验证,会使3验证集偏简单一些。会使模型效果偏高,此外模型有些数据是错误值以及离群值,如果把这些不太好的数据当成验证集,会使模型的效果偏低的。模型当然是不希望偏高也不希望偏低,那就需要多做几次交叉验证模型,求平均值。这里有1,2,3分别求验证集,每个验证集都有评估的标准。最终模型的效果将1,2,3的评估效果加在一起,再除以3,就可以得到模型一个大致的效果。

交叉验证只是做一步求稳的操作,要让模型的评估效果是可信的。既不能偏高也不能偏低,就这样求了平均值来当模型的效果。

之前说到要做数据交叉验证,要对原始数据集进行切分。

  • sklearn.cross_validation是交叉验证模块,train_test_split对原始数据集有进行切分的操作。
  • test_size = 0.3实际做法是把30%的数据拿出去作为测试集,将剩下的70%数据训练模型。这个可以根据实际需求进行修改。
  • random_state = 0,为了使训练集以及测试集一样,设置随机状态为0,这样就抛开了样本对模型的影响。(之前有对原始数据集进行洗牌,再切分测试集以及训练集,才能保证随机切分。)
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size = 0.3, random_state = 0)

之前做了下采样的数据集,让0和1都比较少,要对下采样数据集进行的交叉切分相同的操作。

X_train_undersample, X_test_undersample, y_train_undersample, y_test_undersample = train_test_split(X_undersample
                                                                                                   ,y_undersample
                                                                                                   ,test_size = 0.3
                                                                                                   ,random_state = 0)

为什么同时要对下采样以及原始的数据进行交叉切分呢?

现在要拿下采样的数据进行模型训练的操作,但是模型训练完要进行测试,那么测试的时候拿什么数据集进行测试呢?是拿下采样切分的测试数据集进行测试么?二下采样切分的测试数据数量比较少,而且也是下采样的测试数据集,不具备原始数据的分布规则.最终的测试集是拿原始数据集中的测试数据集再进行测试.

因此这里有2种切分的方式,第一种是对原始数据集即28万个数据进行交叉切分.然后有对984个下采样数据集又进行了一次交叉切分,

from sklearn.cross_validation import train_test_split

# Whole dataset
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size = 0.3, random_state = 0)

print("Number transactions train dataset: ", len(X_train))
print("Number transactions test dataset: ", len(X_test))
print("Total number of transactions: ", len(X_train)+len(X_test))

# Undersampled dataset
X_train_undersample, X_test_undersample, y_train_undersample, y_test_undersample = train_test_split(X_undersample
                                                                                                   ,y_undersample
                                                                                                   ,test_size = 0.3
                                                                                                   ,random_state = 0)
print("")
print("Number transactions train dataset: ", len(X_train_undersample))
print("Number transactions test dataset: ", len(X_test_undersample))
print("Total number of transactions: ", len(X_train_undersample)+len(X_test_undersample))

输出结果如下:

Number transactions train dataset:  199364
Number transactions test dataset:  85443
Total number of transactions:  284807

Number transactions train dataset:  688
Number transactions test dataset:  296
Total number of transactions:  984

后面会拿原始数据中的85443的数据集进行测试操作,而下采样的数据总共有984个,训练集的数据共有668个,测试集有296个,上面已经将数据集进行了切分,就可以进行建模的操作,在建模的过程中要使用逻辑回归.

2.模型评估方法

假设有1000个病人的数据,要对1000个病人进行分类,有哪些是癌症的?哪些不是患有癌症的?

假设有990个人不患癌症,10个人是患癌症.用一个最常见的评估标准,比方说精度,就是真实值与预测值之间的差异.真实值用y来表示,预测值用y1来表示.y真实值1,2,3...10,共有10个样本,y1预测值1,2,3...10,共有10个样本.精度就是看真实值y与预测值y1是否一样的.要么都是0,要么都是1,如果是一致,就用=表示,比如1号真实值样本=预测值的1号样本,如果不相等就用不等号来表示.如果等号出现了8个,那么它的精确度为8/10=80%,从而确定模型的精度.

990个人不患癌症,10个人是患癌症建立一个模型,所有的预测值都会建立一个正样本.对1000个样本输入到模型,它的精确度是多少呢?990/1000=99%
这个模型把所有的值都预测成正样本,但是没有得到任何一个负样本.在医院是想得到癌症的识别,但是检查出来的结果是0个,虽然精度达到了99%,
但这个模型是没有任何的含义的,因为一个癌症病人都找不出来.在建立模型的时候一定要想好一件事,模型虽然很容易建立出来,那么难点是应该怎么样去评估这样的模型呢?

刚才提到了用精度去评估模型,但是精度有些时候是骗人的.尤其是在样本数据不均衡的情况下.

接下来要讲到一个知识点叫recall,叫召回率或叫查全率.recall有0或者1,我们的目标是找出患有癌症的那10个人.因此根据目标制定衡量的标准.就是有10个癌症病人,能够检测出来有几个?如果检测0个癌症病人,那么recall值就是0/10=0;如果检测2个癌症病人,那么recall值就是2/10=20%.用recall检测模型的效果更科学一些.

建立模型无非是选择一些参数,如果精度专用recall来表示,也并非那么容易.在统计学中会经常提到的4个词,分别如下:


比如一个班级有80个男生,20个女生,共100个人,在100多个人中有个目标,把所有的女生都抓出来.建立一个模型,挑选50个人,预测结果是20个是女的,剩下30个是男的.

  • TP:表示预测对的正例结果,比如判断成正例,20个女生,当成正例.
  • FP:表示预测错的正例结果,把负例判断成正例,比如把男生判断成女生,共有30个.
  • FN:就是把女生错当成男生的例子为0个.
  • TN:就是把男生判断成了男生,因此等于50.

这里的Recall = TP/(TP+FN)

3.正则化惩罚

先导入机器学习建模的库

from sklearn.linear_model import LogisticRegression
from sklearn.cross_validation import KFold, cross_val_score
from sklearn.metrics import confusion_matrix,recall_score,classification_report 
  • from sklearn.linear_model import LogisticRegression逻辑回归

  • from sklearn.cross_validation import KFold, cross_val_score,

    • 这里的KFold是指交叉验证的时候,可以选择做几倍的交叉验证.之前有提到将原始的训练集切分成3份,不光可以切分成3份,也可以切分成4份或者5份都可以的,可以根据自己的喜好,任意的切分.
    • cross_val_score值是指交叉验证评估得到的结果,
  • from sklearn.metrics import confusion_matrix,recall_score,classification_report

    • confusion_matrix是混淆矩阵

在机器建模的时候需要做这样的一件事,要做交叉验证,要把原始的数据集切分成几部分,fold = KFold(len(y_train_data),5,shuffle=False) ,这里将原始数据传进来,并切分成了5部分.

在逻辑回归当中,需要有写参数传进来,今天的参数叫做正则化惩罚项,什么叫正则化惩罚?

比如有A模型:ø1、ø2、ø3...ø10,比如还有B模型:ø1、ø2、ø3...ø10,这两个模型的recall值都是等于90%。如果两个模型的recall值都是等于90%,是不是随便选一个都可以呢?
比如A模型的原点浮动比较大,具体如截图:



比如B模型的原点浮动比较小,具体如截图:


虽然两个模型的recall值都是等于90%,A模型的浮动范围太大了,都希望模型更加稳定一些,不光满足训练的数据,还要尽可能的满足测试数据。因此希望模型的浮动差异更小一些,差异小可以使过度拟合的风险更小一些。

过度拟合的意思是在训练集表达效果很好,但是在测试集表达效果很差,因此这组模型发生了过拟合。过拟合是非常常见的现象,很大程度上是因为权重参数浮动较大引起的,因此希望得到B模型,因为B模型的浮动差异比较小。

那么怎么样能够得到B模型呢?从而就引入了正则化的东西,惩罚模型的ø,因为模型的数据有时候分布大,有时候分布小。希望大力度惩罚A模型,小力度惩罚B模型,可不可以呢?

  • L2正则化

首先介绍一些L2正则化,对于目标损失函数来说,希望目标函数是越低越好的,在惩罚的过程中,需要在(loss)损失目标函数中+1/2w*w,即就是如下截图:


对于A模型,w值浮动比较大,如果计算w*w的话,这样的话计算的目标损失函数的值就会更大。对于B模型而言,计算的目标损失函数的值也是如此。

分别计算A、B模型中的loss+1/2w*w中的值,哪个值更加低?

  • L1正则化

(loss)损失目标函数中+|w|,去计算当前的惩罚力度是多少?

因此有两种惩罚函数,一种是L2正则化,一种是L1正则化。

在判断之前需要设置好参数,需要设置当前惩罚的力度有多大?可以设置成0.1惩罚力度比较小,也可以设置惩罚力度为1,也可以设置惩罚力度为10。但是惩罚力度等于多少的时候,效果比较好呢?具体多少也不知道,需要通过交叉验证,去评估一下什么样的参数达到更好的效果。

c_param_range = [0.01,0.1,1,10,100]这里就是前面提到的那一章的惩罚力度。需要将这5个参数不断的尝试。

这一部分内容是可视化显示,具体如下:

    results_table = pd.DataFrame(index = range(len(c_param_range),2), columns = ['C_parameter','Mean recall score'])
    results_table['C_parameter'] = c_param_range

在循环里面利用惩罚力度的参数,看一下那个参数的取值效果更好.

    for c_param in c_param_range:
        print('-------------------------------------------')
        print('C parameter: ', c_param)
        print('-------------------------------------------')
        print('')

下面的循环是对数据进行交叉验证,具体如下:

  • lr = LogisticRegression(C = c_param, penalty = 'l1')首先建立逻辑回归模型,在逻辑回归函数,传进C这个惩罚力度参数.惩罚的方式可以选择l1惩罚或者l2惩罚.

  • lr.fit(x_train_data.iloc[indices[0],:],y_train_data.iloc[indices[0],:].values.ravel())这个语句是对模型进行训练,用交叉验证的方式建立一个模型.

  • y_pred_undersample = lr.predict(x_train_data.iloc[indices[1],:].values),建立完模型之后就可以进行预测.

  • 比如在C=0的情况下,它的效果是多少的?并计算recall的值,

recall_acc = recall_score(y_train_data.iloc[indices[1],:].values,y_pred_undersample)
            recall_accs.append(recall_acc)
            print('Iteration ', iteration,': recall score = ', recall_acc)

4.逻辑回归模型

完整的案例代码如下:

def printing_Kfold_scores(x_train_data,y_train_data):
    fold = KFold(len(y_train_data),5,shuffle=False) 

    # Different C parameters
    c_param_range = [0.01,0.1,1,10,100]

    results_table = pd.DataFrame(index = range(len(c_param_range),2), columns = ['C_parameter','Mean recall score'])
    results_table['C_parameter'] = c_param_range

    # the k-fold will give 2 lists: train_indices = indices[0], test_indices = indices[1]
    j = 0
    for c_param in c_param_range:
        print('-------------------------------------------')
        print('C parameter: ', c_param)
        print('-------------------------------------------')
        print('')


        recall_accs = []
        for iteration, indices in enumerate(fold,start=1):

            # Call the logistic regression model with a certain C parameter
            lr = LogisticRegression(C = c_param, penalty = 'l1')

            # Use the training data to fit the model. In this case, we use the portion of the fold to train the model
            # with indices[0]. We then predict on the portion assigned as the 'test cross validation' with indices[1]
            lr.fit(x_train_data.iloc[indices[0],:],y_train_data.iloc[indices[0],:].values.ravel())

            # Predict values using the test indices in the training data
            y_pred_undersample = lr.predict(x_train_data.iloc[indices[1],:].values)

            # Calculate the recall score and append it to a list for recall scores representing the current c_parameter
            recall_acc = recall_score(y_train_data.iloc[indices[1],:].values,y_pred_undersample)
            recall_accs.append(recall_acc)
            print('Iteration ', iteration,': recall score = ', recall_acc)

        # The mean value of those recall scores is the metric we want to save and get hold of.
        results_table.ix[j,'Mean recall score'] = np.mean(recall_accs)
        j += 1
        print('')
        print('Mean recall score ', np.mean(recall_accs))
        print('')

best_c = printing_Kfold_scores(X_train_undersample,y_train_undersample)

输出结果如下:

-------------------------------------------
C parameter:  0.01
-------------------------------------------

Iteration  1 : recall score =  0.958904109589
Iteration  2 : recall score =  0.917808219178
Iteration  3 : recall score =  1.0
Iteration  4 : recall score =  0.972972972973
Iteration  5 : recall score =  0.954545454545

Mean recall score  0.960846151257

-------------------------------------------
C parameter:  0.1
-------------------------------------------

Iteration  1 : recall score =  0.835616438356
Iteration  2 : recall score =  0.86301369863
Iteration  3 : recall score =  0.915254237288
Iteration  4 : recall score =  0.932432432432
Iteration  5 : recall score =  0.878787878788

Mean recall score  0.885020937099

-------------------------------------------
C parameter:  1
-------------------------------------------

Iteration  1 : recall score =  0.835616438356
Iteration  2 : recall score =  0.86301369863
Iteration  3 : recall score =  0.966101694915
Iteration  4 : recall score =  0.945945945946
Iteration  5 : recall score =  0.893939393939

Mean recall score  0.900923434357

-------------------------------------------
C parameter:  10
-------------------------------------------

Iteration  1 : recall score =  0.849315068493
Iteration  2 : recall score =  0.86301369863
Iteration  3 : recall score =  0.966101694915
Iteration  4 : recall score =  0.959459459459
Iteration  5 : recall score =  0.893939393939

Mean recall score  0.906365863087

-------------------------------------------
C parameter:  100
-------------------------------------------

Iteration  1 : recall score =  0.86301369863
Iteration  2 : recall score =  0.86301369863
Iteration  3 : recall score =  0.966101694915
Iteration  4 : recall score =  0.959459459459
Iteration  5 : recall score =  0.893939393939

Mean recall score  0.909105589115

*********************************************************************************
Best model to choose from cross validation is with C parameter =  0.01
*********************************************************************************

C parameter是惩罚力度参数,从这里可以看出哪些recall值比较低?哪些recall值比较高?希望找出较高模型的参数,这个数值是其中一个5倍交叉验证的结果值,具体如下:

Iteration  1 : recall score =  0.849315068493
Iteration  2 : recall score =  0.86301369863
Iteration  3 : recall score =  0.966101694915
Iteration  4 : recall score =  0.959459459459
Iteration  5 : recall score =  0.893939393939

通过结果可以看出,当惩罚参数是0.01,recall的值最高.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容