数据分析与预处理
当我们拿到一堆数据的时候,首先应该做的是对其进行分析与处理。
import pandas as pd
data = pd.read_csv("creditcard.csv")#读取数据
print(data.head())#显示数据,默认前五行
这里不建议使用excel开打数据,因为数据一般而言都是成千上万条,打开所需的时间太久了,我们直接使用pandas库来进行读取和显示前五条数据进行一个简单的分析。

这里我们可以看到这个数据的大概模样,可以得知此数据集一共有31列,其中有30列是特征列,Amount为贷款的金额,Class为分类结果,0为交易正常,1为异常。
接下来我们要检查一下这里面所存在多少异常值。
import matplotlib.pyplot as plt
#异常值的找寻
count_classes = pd.value_counts(data['Class'], sort = True).sort_index()
count_classes.plot(kind = 'bar')
plt.title("Fraud class histogram")
plt.xlabel('Class')
plt.ylabel('Frequency')
plt.show()
由于数据太多,这里我们使用画图进行数据统计与分析。
value_counts()是一个计数函数,统计数据的数量。
参数data['Class']指的是统计Class这一列以下的数据。
参数sort是是否进行排序处理。
sort_index()为引索排序,这里是按照行引索升序排列,使得他们还是从上向下进行排序(0,1,2....),而非乱序(2,1,0.....)
count_classes.plot()是画图函数,传入的kind是所需绘图的类型,这里的‘bar’是指绘制条形图
plt.title()绘制图的标题。
plt.xlabel()为x轴坐标的标签,同理ylable即为y轴的标签。
plt.show()将所绘制的图在屏幕上展示出来。

于是乎得到了这一张图,看起来好像没有异常值,其实是有的,只是太少了。
特征标准化

这里我们能看到v1-v28列的数值都是较小的,而amount列的数据相比之下就大的太多了,这样的话,会使得amount在模型中所占的权重过大,但我们并不希望这样,所以我们进行一下数据标准化操作,使模型对他们一视同仁。

from sklearn.preprocessing import StandardScaler
data['normAmount'] = StandardScaler().fit_transform(data["Amount"].values.reshape(-1,1))
data = data.drop(['Time','Amount'],axis=1)
print(data.head())
首先导入标准化库,然后使用标准化库中的fit_transform()函数来进行处理(这个函数先会寻找数据的均值等特征值,然后再进行标准化处理)。
data['Amount']参数指的是我们对Amount这列数据进行处理,后面跟的.values.reshape(-1,1)指的是将Amount列的数据转换成一列数据。
data.drop()函数用处删除数据,这里我们删除time和amount列,axis=1代表删除的是列

这下我们变化后的normAmount就和前面的数据相差无几了。
样本不平均的处理方法
这里可以看到我们class为0和为1的数量相差太大,这里有两种解决办法,一为下采样,一为过采样。
下采样
假设我们的class为0的样本只有1000个,为1的样本有10000个,那么我们取样的时候,为0的样本取1000个,为1的样本也只取其中的1000。这样就保证了两类数据的比例平均。
过采样
这时候我们就增加一些class为0的样本,使其和为1的样本数一样多,怎么增加呢?捏造数据。
下采样方案
X = data.loc[:, data.columns != 'Class']#读取除Class列之外的所有列
y = data.loc[:, data.columns == "Class"]#读取Class列
number_records_fraud = len(data[data.Class == 1])#统计异常数据数量
fraud_indices = np.array(data[data.Class == 1].index)#将异常值放入数组
normal_indices = data[data.Class == 0].index#储存正常值的索引
random_normal_indices = np.random.choice(normal_indices, number_records_fraud, replace = False)#从正常值引索数组中抽取异常值个数的数为一个新列表,replac = false为不取相同数据
random_normal_indices = np.array(random_normal_indices)#转换为np中的数组
under_sample_indices = np.concatenate([fraud_indices,random_normal_indices])#拼接两个数组
under_sample_data = data.iloc[under_sample_indices,:]#读取这些行的数据
X_undersample = under_sample_data.loc[:, under_sample_data.columns != 'Class']
y_undersample = under_sample_data.loc[:, under_sample_data.columns == "Class"]
print("正常样本所占整体比例:", len(under_sample_data[under_sample_data.Class==0])/len(under_sample_data))
print("异常样本所占整体比例:",len(under_sample_data[under_sample_data.Class == 1])/len(under_sample_data))
print("下采样策略总体样本数量:",len(under_sample_data))
data.loc()函数是读取列表中的数据,参数中第一个:指的是读取全部行。
这里我们将除class列之外的所有数据作为特征值,class列的值作为预测值。
np.random.choice()函数的第一个参数为从哪一个数组里抽取,第二个为抽取的数量,第三个为是否取相同的数据。

交叉验证

将训练集划分为多份,每次取其中一份作为验证集,如此下来,对所有的结果取平均,就是模型的评估值。建模的时候有训练集,验证集,测试集。训练集就是用来训练模型的,验证用于验证模型的,测试集用于检测模型成效的。交叉验证就是用于评估检测模型的。
#导入数据集切分模块
from sklearn.model_selection import train_test_split
#对于特征值与预测值划分训练集与测试集
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size = 0.3, random_state = 0)
print("\n原始训练集包括样本数量:",len(X_train))
print("原始测试集包含样本数量:", len(X_test))
print("原始样本总数:", len(X_train)+len(X_test))
#下采样数据集进行划分
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("\n下采样训练集包含样本数量:", len(X_train_undersample))
print("下采样训练测试集包含样本数量:",len(X_test_undersample))
print("下采样样本总数:", len(X_train_undersample)+len(X_test_undersample))
train_test_split()函数用于划分训练与测试集,参数为特征值数组,预测值数组,test_size测试集划分比例,random_state随机种子。

模型评估方法


正则化惩罚
简单而言就是在模型迭代的过程中,不断调整模型的不同参数的占比,以防止出现过拟合现象,使模型的预测效果更好。

a系数是惩罚力度,a越大,惩罚力度越大。
逻辑回归模型
#逻辑回归模型
from sklearn.model_selection import KFold
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import recall_score
def printing_Kfold_scores(X_train_date, y_train_data):
fold = KFold(5,shuffle=False)
#定义不同的正则化惩罚力度
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
# k-fold 表示K折的交叉验证,这里会得到两个索引集合:训练集 = indices[0], 验证集 = indices[1]
j = 0
#循环遍历不同的参数
for c_param in c_param_range:
print('\n---------------------')
print('正则化惩罚力度:', c_param)
print('---------------------')
recall_accs = []
#一步步分解来执行交叉验证
for iteration, indices in enumerate(fold.split(y_train_data),start=1):
#指定算法模型,并且给定参数
Ir = LogisticRegression(C = c_param, penalty = 'l1',solver='liblinear')
#训练模型,注意不要给错索引,训练的时候传入的一定是训练集,所以X和Y的索引都是0
Ir.fit(X_train_date.iloc[indices[0],:],y_train_data.iloc[indices[0],:].values.ravel())
#建立好模型后,预测模型结果,这里用的就是验证集,索引为1
y_pred_undersample = Ir.predict(X_train_date.iloc[indices[1],:].values)
#预测结果明确后,就可以进行评估,这里recall_score需要传入预测值和真实值
recall_acc = recall_score(y_train_data.iloc[indices[1],:].values,y_pred_undersample)
#一会还要计算平均,所以吧每一步的结果都先保存起来
recall_accs.append(recall_acc)
print('Iteration',iteration,"召回率 = ",recall_acc)
#当执行完所有的交叉验证之后,计算平均结果
results_table.loc[j,'Mean recall score'] = np.mean(recall_accs)
j += 1
print('')
print('平均召回率',np.mean(recall_accs))
print('')
#找到最好的参数,哪一个Recall高,自然就是最好的
best_c = results_table.loc[results_table["Mean recall score"].astype('float32').idxmax()]['C_parameter']
#打印最好的结果
print("*************************")
print("效果最好的模型所选参数 = ",best_c)
print("*************************")
return best_c
best_c = printing_Kfold_scores(X_train_undersample,y_train_undersample)
最后将结果

类似于这样,警告自动忽视一下
Comments NOTHING