查看数据样本
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
data = pd.read_csv("./data/creditcard.csv")
data.head()
这个数据,并不是最原始数据,而是通过降维操作把数据进行特征压缩。我们可以根据这些特征进行建模。
这些数据有一列class,用来标注是否正常,0
表示正常,1
表示异常。
这是经典的二分类问题。
首先查看当前数据的正负样本的比例:
count_classes = pd.value_counts(data['Class'], sort=True).sort_index()
count_classes.plot(kind='bar') # 用pandas也可以花一些简单的图
plt.title("Fraud class histogram")
plt.xlabel("Class")
plt.ylabel("Frequency")
可以看出0
样本占了大多数, 1
样本占了很少的数量。
因此两个数据量并不均衡,如何进行调整?
1. 下采样
例如0
样本数据量大约28万,1
样本数据量大约几百个。可以让0
样本采集几百个,跟1
样本的数量同样少。
2. 上采样
生成1
样本数据,与0
样本的数据量一样。
3. 特征分布
从数据中可以看到,Amount列的数据与其他特征的数据值差异较大,一些算法会误以为数据大则重要程度高,所以为了使得每个特征的重要程度是相当的,需要对Amount的数据进行归一化。
可以通过sklearn
进行处理:
from sklearn.preprocessing import StandardScaler
data['normAmount'] = StandardScaler().fit_transform(data['Amount'].values.reshape(-1, 1)) # 对数据进行标准化,reshape相当于对矩阵进行行列的变换,成为新的特征['normAmount'],加到原始数据
data = data.drop(['Time', 'Amount'], axis=1) # 将Time和Amount列删掉
data.head()
reshape相当于对矩阵进行行列的变换,例如矩阵
A
3
×
6
A_{3\times6}
A3×6经过A.reshape(-1, 2)
就会自动变成
B
9
×
2
B_{9\times2}
B9×2,数据总量不变。调整后的数据如下:
使用下采样进行调整
X = data.loc[:, data.columns.values != ["Class"]] # 获取特征数据
y = data.loc[:, data.columns.values == ["Class"]] # 获取标签
#print(X.head())
#print(y.head())
number_records_fraud = len(y[y["Class"]==1])# 标签为1的样本数量,异常样本的数量
print(len(y[y["Class"]==1]))
print(len(y[y["Class"]==0])) # 标签为0的样本数量,正常样本的数量
fraud_indices = y[y.Class==1].index # 获取标签为1的样本的索引
normal_indices = y[y.Class==0].index # 获取标签为0的样本的索引
# print(normal_indices)
random_normal_indices = np.random.choice(normal_indices, number_records_fraud, replace=False) # 随机从class=0的样本中拿number_records_fraud个数据
random_normal_indices = np.array(random_normal_indices)
# 将两种index合并到一起,下采样
under_sample_indices = np.concatenate([fraud_indices, random_normal_indices])
under_sample_data = data.iloc[under_sample_indices, :]
print(len(under_sample_data[under_sample_data.Class==0])) # 492
print(len(under_sample_data[under_sample_data.Class==1])) # 492
这样就通过下采样的方式将数据分布均衡,代价就是很多数据没有利用。
交叉验证
一般情况下,当我们达到数据时,会将数据80%分割为训练集,数据20%分割为测试集。还可以将训练集继续平均分割成3份,分别是训练集、验证集,这里用A、B、C表示。我们可以通过交叉验证的方式来调整参数,通过验证集当前模型参数是好还是不好。第一次可以用A+B进行训练,用C进行验证;第二次用A+C进行训练,用B进行验证;第三次用B+C进行训练,用A进行验证。
这么做主要是为了防止某一部分的数据比较简单,导致模型效果比较高。
模型的评估标准
假设有1000个人,其中990个人正常,有10个人患有癌症,模型旨在预测哪些人是患有癌症的。
如果模型预测1000个人中都是正常的,没有癌症患者,那么可以说模型的精度是
990
1000
=
0.99
\frac{990}{1000}=0.99
1000990=0.99。虽然精度很高,但是都是正样本,没有负样本,模型是无用的,因为一个患者都没有找到。因此无法用精度来评估模型,而是使用recall
召回率来评估。
上采样SMOTE算法
- 对于少数类中每一个样本x,以欧氏距离为标准计算它到少数类样本集中所有样本的距离,得到其k近邻
- 根据样本不平衡比例设置一个采样比例以确定采样倍率N,对于每一个少数类样本x,从其k近邻中随机选择若干个样本,假设选择的近邻为xn
- 对于每一个随机选出的近邻xn,分别与原样本按照如下的公式构建新的样本。
x n e w = x + r a n d ( 0 , 1 ) × ( x ~ − x ) x_{new}=x+ rand(0,1)\times(\tilde{x} -x) xnew=x+rand(0,1)×(x~−x)
import pandas as pd
from imblearn.over_sampling import SMOTE
features_train, feature_test, labels_train, labels_test = train_test_split(X, y, test_size=0.2, random_state = 0) # test_size表示切分比例,20%的数据作为测试集;random_state表示让每一次随机出的样本都一致
oversampler = SMOTE(random_state=0)
os_features,os_labels=oversampler.fit_sample(features_train, labels_train)
len(os_labels[os_labels==1])
这样就生成了很多数据。