主要内容数据向量化处理
特征放缩
上采样和下采样
重采样和交叉验证
模型验证
python 代码实现
1. 数据向量化处理
对于给定的m个样本,假设最终的拟合函数是
为拟合的权重系数,则有
损失函数改写为矩阵形式
由于
, 可以得出
有公式以得到损失函数的向量表达式
2. 特征放缩
在实际中,我们不同特征的尺度大小,取值范围可能可能相差很大
例如,我们有两个特征,分别是房子的面积以及房子的卧室数。房子的面积取值范围大约是0~300,而卧室数的取值范围在0~5。这样的话,如果我们把它们关于代价函数的等高线图绘制出来的话,形如狭长同心椭圆,一个狭长的椭圆在逼近收敛的时候就会产生震荡,因为横轴方向的参数只要略微变化等高线图中显示的损失函数就会剧烈变化,从而影响收敛准确性。我们的目标是我们特征放缩的目标是把所有的特征放到同一个数量级下面。
方法:均值标准化(Mean normalization)
使用特征值减去它的均值,然后再除以它们的最大值.
3. 过拟合和欠拟合
简单理解:过拟合是在训练数据上表现良好,在未知数据上表现差,欠拟合在训练数据和未知数据上表现都很差。
首先了解泛化概念
泛化:机器学习模型学习到的概念在它处于学习的过程中时模型没有遇见过的样本时候的表现。在机器学习领域中,当我们讨论一个机器学习模型学习和泛化的好坏时,我们通常使用术语,过拟合和欠拟合.
从训练数据中学习目标函数的过程中,我们必须考虑的问题是模型在预测新数据时的泛化性能。泛化好坏是很重要的,因为我们收集到的数据只是样本,其带有噪音并且是不完全的。
Note:如果我们已经知道了目标函数的形式,我们将可以直接用它来做预测,而不是从一堆有噪音的数据中把它费力的学习出来。
机器学习中的过拟合
当某个模型过度的学习训练数据中的细节和噪音,以至于模型在新的数据上表现很差。这意味着训练数据中的噪音或者随机波动也被当做概念被模型学习了。而问题就在于这些概念不适用于新的数据,从而导致模型泛化性能的变差。
过拟合更可能在无参数非线性模型中发生,因为学习目标函数的过程是易变的具有弹性的。同样的,许多的无参数机器学习算法也包括限制约束模型学习概念多少的参数或者技巧。例如,决策树就是一种无参数机器学习算法,非常有弹性并且容易受过拟合训练数据的影响。这种问题可以通过对学习过后的树进行剪枝来解决,这种方法就是为了移除一些其学习到的细节。
机器学习中的欠拟合
欠拟合指的是模型在训练和预测时表现都不好的情况。欠拟合通常不被讨论,因为给定一个评估模型表现的指标的情况下,欠拟合很容易被发现。矫正方法是继续学习并且试着更换机器学习算法。虽然如此,欠拟合与过拟合形成了鲜明的对照。
两种解决方式:重采样方法和验证集方法。
使用重采样来评价模型效能, 最流行的重采样技术是k折交叉验证。指的是在训练数据的子集上训练和测试模型k次,同时建立对于机器学习模型在未知数据上表现的评估。
验证集只是训练数据的子集,你把它保留到你进行机器学习算法的最后才使用。在训练数据上选择和调谐机器学习算法之后,我们在验证集上在对于模型进行评估,以便得到一些关于模型在未知数据上的表现的认知。
4. 重采样和交叉验证(Cross Validation)
重采样:
重采样基于实际数据生成一个独特的采样分布。它使用经验性方法,而不是分析方法,来生成该采样分布。重采样基于数据所有可能结果的无偏样本获取无偏估计
交叉验证:
在使用训练集对参数进行训练的时候,通常会将一整个训练集分为三个部分训练集(train_set),评估集(valid_set),测试集(test_set)这三个部分。这其实是为了保证训练效果而特意设置的。其中测试集很好理解,其实就是完全不参与训练的数据,仅仅用来观测测试效果的数据。在实际的训练中,训练的结果对于训练集的拟合程度通常还是挺好的(初始条件敏感),但是对于训练集之外的数据的拟合程度通常就不那么令人满意了。因此我们通常并不会把所有的数据集都拿来训练,而是分出一部分来(这一部分不参加训练)对训练集生成的参数进行测试,相对客观的判断这些参数对训练集之外的数据的符合程度。这种思想就称为交叉验证(Cross Validation)
常见的交叉验证方式:
1)k-folder cross-validation:
k个子集,每个子集均做一次测试集,其余的作为训练集。交叉验证重复k次,每次选择一个子集作为测试集,并将k次的平均交叉验证识别正确率作为结果。
优点:所有的样本都被作为了训练集和测试集,每个样本都被验证一次。10-folder通常被使用。
2)K * 2 folder cross-validation
是k-folder cross-validation的一个变体,对每一个folder,都平均分成两个集合s0,s1,我们先在集合s0训练用s1测试,然后用s1训练s0测试。
优点是:测试和训练集都足够大,每一个个样本都被作为训练集和测试集。一般使用k=10
3)least-one-out cross-validation(loocv)
假设dataset中有n个样本,那LOOCV也就是n-CV,意思是每个样本单独作为一次测试集,剩余n-1个样本则做为训练集。
优点:
1)每一回合中几乎所有的样本皆用于训练model,因此最接近母体样本的分布,估测所得的generalization error比较可靠。
2)实验过程中没有随机因素会影响实验数据,确保实验过程是可以被复制的。
但LOOCV的缺点则是计算成本高,为需要建立的models数量与总样本数量相同,当总样本数量相当多时,LOOCV在实作上便有困难,除非每次训练model的速度很快,或是可以用平行化计算减少计算所需的时间。
5. 模型的评估方法
上式的结果越接近于1 表明拟合的结果越好
6. Python 代码实现
下面以信用卡异常检测为案例,来巩固复习以上知识点。以下代码整理自屈大神视频。
导入三大件和数据
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
data = pd.read_csv("creditcard.csv")
data.head() # 查看数据头
X =data.loc[:,data.columns != 'Class'] # 特征列
Y =data.loc[:,data.columns == 'Class'] # 标签列
number_records_fraud = len(data[data.Class==1])# 计算失信人员个数
# 把索引取出,建立一个数据标签的一维数组
fraud_indices = np.array(data[data.Class == 1].index) # 异常索引
normal_indices = np.array(data[data.Class != 1].index) # 正常索引
下采样 Undersample
# 随机的在正常的数据中选择与异常数据个数相同的正常数据点,并建立数组
random_normal_indices = np.random.choice(normal_indices,
\number_records_fraud,replace=False)
random_normal_indices = np.array(random_normal_indices) # 建立一维数组
# under_sample
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 ('percent', len(under_sample_data[under_sample_data.Class==0] / len(under_sample_data)))
# 划分数据
from sklearn.model_selection 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)
# test_size 切分比例
# undersample
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)
导入sklearn 相关库
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import KFold, cross_val_score
from sklearn.metrics import confusion_matrix, recall_score, classification_report
交叉验证
def printing_Kfold_scores (x_train_data, y_train_data):
fold = KFold(5, shuffle=False)
#print (fold.get_n_splits()) #5
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 s'] )
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.split(y_train_data), start=1):
lr = LogisticRegression(C= c_param, penalty= 'l1')# C 惩罚力度
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)
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)
results_table.loc[j,'Mean recall score']= np.mean(recall_accs)
j+=1
print ('')
print ('Mean recall score', np.mean(recall_accs))
print ('')
best_c = results_table.loc[results_table['Mean recall score'].idxmax()]['C_parameter']
print('************************************************************************************')
print ('best model to choose from cross vaildation is with C parameter =', best_c)
print('************************************************************************************')
return best_c
best_c = printing_Kfold_scores(X_train_undersample, y_train_undersample)
#best_c_1 = printing_Kfold_scores(X_train,y_train) #原始数据集进行训练
lr = LogisticRegression (C=best_c, penalty = 'l1')
lr.fit(X_train, y_train.values.ravel)
y_pred_undersample = lr.predict(X_test.values)
cnf_matrix = confusion_matrix(y_test,y_pred_undersample)
np.set_printoptions(precision =2)
print ('Recall matric in the testing dataset', cnf_matrix[1,1]/(cnf_matrix[1,0] + cnf_matrix[1,1]))
class_names = [0,1]
plt.figure()
plot_confusion_matrix(cnf_matrix,
classes = class_names,
title='confusion matrix')
plt.show()