文章原创,最近更新:2018-06-8
1.SMOTE样本生成策略
课程资料:这里所涉及到的练习资料creditcard.csv相关的链接以及密码如下:
链接: https://pan.baidu.com/s/1APgU4cTAaM9zb8_xAIc41Q 密码: xgg7
对于下采样操作而言,模型回归的评估以及参数的选择.那么这个就是下采样应该怎么样去做这个事情.不光有下采样的操作,还有过采样的操作.那么接下来讲的就是过采样的操作,是关于SMOTE的算法.
(1)对于少数类中每一个样本x,以欧氏距离为标准计算它到少数类样本集中所有样本的距离,得到其k近邻.
(2)根据样本不平衡比例设置一个采样比例以确定采样倍率N,对于每一个少数类样本,从其k近邻中随机选择若干个样本,假设选择的近邻为xn.
(3)对于每一个随机选出的近邻xn,分别与原样本按照如下的公式构建新的样本.
在过采样的时候要有数据的生成,现在有0和1两类的样本.0类样本很多,1类样本很少,现在希望1类的样本也很多进行生成的操作.
假设1类的样本有100个,想生成500个,那我们能不能做这个事呢?肯定是可以的.首先介绍一个算法,这个算法是在数据挖掘以及统计当中非常常用的,这个算法就叫SMOTE,给大家解释一下,流程是怎么完成这样的事的.
(1)对于少数类中每一个样本x,以欧氏距离为标准计算它到少数类样本集中所有样本的距离,得到其k近邻.
先将少数类的样本先拿出来,以欧氏距离为标准计算它到少数类样本集中所有样本的距离,得到其k近邻.具体案例如下:
假设有个三角形,比较稀缺的类别,写个for循环,这个for循环遍历每个三角形的样本,第一次遍历的样本是xi,计算xi样本到其他样本的距离.
比如d1,d2,d3,...dn.计算好之后,分别将d1,d2,d3,...dn进行排序的操作,那么将一个样本变成5个样本,就把排序好的样本每5个就切一刀分组,如果将一个样本变成10个样本,那么就将排序好的样本每10个就切一刀分组.具体案例如下:
假设是排序好的样本每5个就切一刀分组,那么接下来就按公式操作:
这个公式的x是表示刚才切下来的xi样本,xnew是新生成的样本.是不是有5个距离,其中如下的截图就是算出来的欧氏距离
比如d1乘以一个随机数,比如这个随机数是0.76,就会得到一个新值,再将新值加到原始的数据上,那么就会得到一个新的数据.接下来用d1,d2,d3,d4,d5按照以上的方法都得到新的值.这个就叫SMOTE算法.接下来就是按照SMOTE算法来进行一个数据生成的操作.
首先导入python相关的库以及模块.
import pandas as pd
from imblearn.over_sampling import SMOTE
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split
因为imblearn.over_sampling 这个库第一次使用,需要进行按照.
在,输入:pip install imblearn,即可以安装完毕.
over_sampling指的是过采样的操作.
因为以下代码,之前都有提到过,因此就不一一再次述说了.
credit_cards=pd.read_csv('creditcard.csv')
columns=credit_cards.columns
# The labels are in the last column ('Class'). Simply remove it to obtain features columns
features_columns=columns.delete(len(columns)-1)
features=credit_cards[features_columns]
labels=credit_cards['Class']
features_train, features_test, labels_train, labels_test = train_test_split(features,
labels,
test_size=0.2,
random_state=0)
我们来看看重点的代码,具体如下:
oversampler=SMOTE(random_state=0)
os_features,os_labels=oversampler.fit_sample(features_train,labels_train)
oversampler=SMOTE(random_state=0),用SMOTE进行数据生成,首先实例化一个对象,叫oversampler,SMOTE可以不使用参数,但是要使每次生成的数据都是一样的,可以random_state=0.
os_features,os_labels=oversampler.fit_sample(features_train,labels_train),用oversampler.fit_sample()将原始数据传进来,刚才有对原始数据进行切分,有切分成测试集以及训练集.需要想一个问题,切分完之后,需要哪哪一部分进行生成呢?肯定是拿训练集进行生成并建立一个模型.测试集是千万不可以动的.
fit_sample(features_train,labels_train)传进来的是训练集的x以及训练集的y,训练完之后,就会自动做一个平衡,就会知道0有多少个,1有多少个?
len(os_labels[os_labels==1])
这里是计算lable1的有多少个?共有227454个.lable0的也有20多万个,因此样本就均衡了.可以通过过采样的方式,查看recall有多少?
os_features = pd.DataFrame(os_features)
os_labels = pd.DataFrame(os_labels)
best_c = printing_Kfold_scores(os_features,os_labels)
输出结果如下:
-------------------------------------------
C parameter: 0.01
-------------------------------------------
Iteration 1 : recall score = 0.890322580645
Iteration 2 : recall score = 0.894736842105
Iteration 3 : recall score = 0.968861347792
Iteration 4 : recall score = 0.957595541926
Iteration 5 : recall score = 0.958430881173
Mean recall score 0.933989438728
-------------------------------------------
C parameter: 0.1
-------------------------------------------
Iteration 1 : recall score = 0.890322580645
Iteration 2 : recall score = 0.894736842105
Iteration 3 : recall score = 0.970410534469
Iteration 4 : recall score = 0.959980655302
Iteration 5 : recall score = 0.960178498807
Mean recall score 0.935125822266
-------------------------------------------
C parameter: 1
-------------------------------------------
Iteration 1 : recall score = 0.890322580645
Iteration 2 : recall score = 0.894736842105
Iteration 3 : recall score = 0.970454796946
Iteration 4 : recall score = 0.96014552489
Iteration 5 : recall score = 0.960596168431
Mean recall score 0.935251182603
-------------------------------------------
C parameter: 10
-------------------------------------------
Iteration 1 : recall score = 0.890322580645
Iteration 2 : recall score = 0.894736842105
Iteration 3 : recall score = 0.97065397809
Iteration 4 : recall score = 0.960343368396
Iteration 5 : recall score = 0.960530220596
Mean recall score 0.935317397966
-------------------------------------------
C parameter: 100
-------------------------------------------
Iteration 1 : recall score = 0.890322580645
Iteration 2 : recall score = 0.894736842105
Iteration 3 : recall score = 0.970543321899
Iteration 4 : recall score = 0.960211472725
Iteration 5 : recall score = 0.960903924995
Mean recall score 0.935343628474
*********************************************************************************
Best model to choose from cross validation is with C parameter = 100.0
*********************************************************************************
通过以上的结果可以知道recall值平均算下来大概是0.935.
我们在看一下混淆矩阵.
lr = LogisticRegression(C = best_c, penalty = 'l1')
lr.fit(os_features,os_labels.values.ravel())
y_pred = lr.predict(features_test.values)
# Compute confusion matrix
cnf_matrix = confusion_matrix(labels_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]))
# Plot non-normalized confusion matrix
class_names = [0,1]
plt.figure()
plot_confusion_matrix(cnf_matrix
, classes=class_names
, title='Confusion matrix')
plt.show()
输出结果如下:
Recall metric in the testing dataset: 0.90099009901
通过输出结果我们可以知道,测试集共有5万多个样本,recall值是等于90%.之前的recall值是约等于91%(这个数值是大概,有点忘记了).这个结果比之前的结果稍微低了一些,而现在的误杀值有517个.之前的误杀值有8000多个,是500多个的十几倍.通过过采样得到的误差是偏低一些的.
使用过采样recall值可能偏低一些,但是模型的优点是精度偏高.这就是与下采样的区别.
总结:
对于样本不均衡数据,要利用越多的数据越好,能利用一种生成方式,就不妨利用这种生成方式.下采样误杀率很高,这是模型本身自带的一个问题,因为0和1一样少,会存在潜在的意识是原始数据0和1的数据一样少,导致误杀率偏高.过采样的结果偏好一些,虽然recall偏低了一点,但是整体的效果还是不错的.
流程总结:
首先要观察数据,当前数据是否分布均衡,不均衡的情况下就要想一些方法.
(这节课的数据是比较纯净的,就不需要做其他一些预处理的操作,直接原封不动的拿出来就可以了.很多情况下,不见得可以直接拿到特征数据,
后面讲到特征工程的时候,会拿到比较难的数据,怎么去建立特征以及怎么样去寻求一些帮助呢?)
让数据进行标准化,让数据的浮动比较小一些,然后再进行数据的选择以及参数的选择.通过交叉验证的方式.
混淆矩阵以及模型的评估标准
通过阈值与预测值进行比较,然后得到最终的一个预测结果.不同的阈值会使结果发生很大的变化.
SMOTE算法.