在Python和R中:使用交叉验证提高模型性能

关于黑客马拉松最有趣和最具挑战性的事情之一是在公共和私人排行榜上获得高分。 我密切关注了Data Hackathons系列,并发现了一个有趣的趋势。 这一趋势是基于参与者在公共和私人排行榜上的排名。

有一点非常突出,那就是在排行榜在私人排行榜上得到验证后,在排行榜上排名较高的参与者就会失去自己的位置。 有些人甚至未能在私人排行榜前20名中获得排名(图片见下图)。

最终,我发现这种现象在排行榜上带来了这样的涟漪。

rank

 1、为什么模型会失去稳定性?

让我们使用下面的快照来了解这一点,说明各种型号的适用性:

1

在这里,我们试图找到尺寸和价格之间的关系。为了达到这个目的,我们采取了以下步骤:

我们已经使用线性方程建立了关系,图中显示了这个关系。从训练数据点来看,第一个曲线有很高的误差。因此,这在公共或私人排行榜上都不会表现出色。这是“Underfit”的一个例子。在这种情况下,我们的模型未能捕捉到数据的基本趋势

在第二个情节中,我们找到了价格和规模之间的正确关系,即低的训练错误和关系的普遍化

在第三个情节中,我们发现了一个几乎没有训练错误的关系。这是因为通过考虑数据点(包括噪声)中的每个偏差来开发关系,即,模型过于敏感并且捕获仅存在于当前数据集中的随机模式。这是“过度配合”的一个例子。在这种关系中,公共和私人排行榜之间的偏差可能会很大

数据科学竞赛中的一种常见做法是迭代各种模型以找到更好的表现模型。然而,由于我们更好地捕捉了关系,或者我们只是过度拟合了数据,所以很难区分这种分数的提高是否会到来。为了找到这个问题的正确答案,我们使用验证技术。这种方法有助于我们实现更普遍的关系。

2、什么是交叉验证

交叉验证是一种技术,它涉及到预留一个数据集的特定样本,在该样本上不训练模型。 稍后,您在完成该测试之前测试您的模型。

以下是交叉验证所涉及的步骤:

您保留一个样本数据集

使用数据集的其余部分训练模型

使用测试(验证)集的备用样本。 这将有助于您衡量模型性能的有效性。 如果您的模型对验证数据提供了正面结果,请继续使用当前模型。 它岩石!

一些常用的方法用于交叉验证

有多种方法可用于执行交叉验证。 我在本节中讨论了其中的一些。

验证集方法

在这种方法中,我们保留50%的数据集用于验证,其余50%用于模型训练。 然而,这种方法的一个主要缺点是,由于我们只对50%的数据集进行模型训练,所以我们很可能会错过一些有关数据的有趣信息,这会导致更高的偏差。

Python 代码:

train, validation = train_test_split(data, test_size=0.50, random_state = 5)

R 代码:

set.seed(101) # Set Seed so that same sample can be reproduced in future also

# Now Selecting 50% of data as sample from total ‘n’ rows of the data
sample <- sample.int(n = nrow(data), size = floor(.50*nrow(data)), replace = F)
train <- data[sample, ]
test <- data[-sample, ]

3、留下一个交叉验证(LOOCV)

在这种方法中,我们只从可用数据集中预留一个数据点,并在其余数据上训练模型。 该过程针对每个数据点进行迭代。 这也有其自身的优点和缺点。 让我们看看他们:

我们利用所有的数据点,因此偏见会很低

我们重复交叉验证过程n次(其中n是数据点的数量),这会导致更高的执行时间

这种方法导致测试模型有效性的变化更大,因为我们针对一个数据点进行测试。 所以,我们的估计会受到数据点的高度影响。 如果数据点变成异常值,则可能导致更高的变化

Python 代码:

from sklearn.model_selection import LeaveOneOut
X = np.array([[1, 2], [3, 4]])
y = np.array([1, 2])
loo = LeaveOneOut()
loo.get_n_splits(X)

for train_index, test_index in loo.split(X):
print(“train:”, train_index, “validation:”, test_index)
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]

R 代码:

score = list()

LOOCV_function = function(x,label){
for(i in 1:nrow(x)){
training = x[-i,]
model = #… train model on training
validation = x[i,]
pred = predict(model, validation[,setdiff(names(validation),label)])
score[[i]] = rmse(pred, validation[[label]]) # score/error of ith fold
}
return(unlist(score)) # returns a vector
}

LOOCV留下一个数据点。 同样,您可以将p个训练样例留给每个迭代具有大小p的验证集。 这称为LPOCV(保留P Out交叉验证)

k-fold交叉验证

从以上两种验证方法中,我们了解到:

我们应该在大部分数据集上训练模型。否则,我们将无法阅读并识别数据中的潜在趋势。这最终会导致更高的偏见

我们还需要很好的测试数据点比例。正如我们上面所看到的,在测试模型的有效性时,少量的数据点可能会导致方差错误

我们应该多次迭代训练和测试过程。我们应该改变火车和测试数据集的分布。这有助于正确验证模型的有效性

我们是否有一种方法来处理所有这3项要求?

是!该方法被称为“k倍交叉验证”。这很容易遵循和实施。下面是它的步骤:

将整个数据集随机分成k个“折叠”

对于数据集中的每个k-fold,在k-1折叠的数据集上构建模型。然后,测试模型以检查第k次折叠的有效性

记录您在每个预测中看到的错误

重复此操作,直到每个k-折叠都充当测试集

记录的k个错误的平均值称为交叉验证错误,并将作为模型的性能指标

以下是当k = 10时的k倍验证的可视化。

2

现在,最常见的问题之一是,“如何选择正确的k值?”。

请记住,k值越低越有偏见,因此是不可取的。 另一方面,较高的K值偏差较小,但可能会有较大的变化。 重要的是要知道,较小的kalways值将我们带向验证集方法,而较高的k值导致LOOCV方法。

准确地说,LOOCV相当于n倍交叉验证,其中n是训练样本的数量。

Python 代码:

from sklearn.model_selection import KFold
kf = RepeatedKFold(n_splits=5, n_repeats=10, random_state=None)

for train_index, test_index in kf.split(X):
print(“Train:”, train_index, “Validation:”,test_index)
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]

R 代码:

library(caret)
data(iris)

# Define train control for k fold cross validation
train_control <- trainControl(method="cv", number=10)
# Fit Naive Bayes Model
model <- train(Species~., data=iris, trControl=train_control, method="nb")
# Summarise Results
print(model)

4、分层k折交叉验证

分层是重新整理数据的过程,以确保每一次折叠都是整体的良好代表。 例如,在二元分类问题中,每个类别包含50%的数据,最好安排数据,以便在每一个类别中,每个类别包含大约一半的实例。

在Python和R中:使用交叉验证提高模型性能

处理偏差和方差时通常是更好的方法。 随机选择的折叠可能不足以代表小类,尤其是在类别失衡严重的情况下。

用于分层k折交叉验证的Python代码片段:

from sklearn.model_selection import StratifiedKFold
skf = StratifiedKFold(n_splits=5, random_state=None)
# X is the feature set and y is the target
for train_index, test_index in skf.split(X,y):
print(“Train:”, train_index, “Validation:”, val_index)
X_train, X_test = X[train_index], X[val_index]
y_train, y_test = y[train_index], y[val_index]

R 代码:

library(caret)
# Folds are created on the basis of target variable
folds <- createFolds(factor(data$target), k = 10, list = FALSE)

话虽如此,如果火车集没有充分代表整个人口,那么使用分层k倍可能不是最好的主意。 在这种情况下,应该使用简单的k-fold交叉验证和重复。

在重复交叉验证中,交叉验证程序重复n次,得到原始样本的n个随机分区。 n次结果再次被平均(或以其他方式组合)以产生单一估计。

用于重复k-fold交叉验证的Python代码:

from sklearn.model_selection import RepeatedKFold
rkf = RepeatedKFold(n_splits=5, n_repeats=10, random_state=None)
# X is the feature set and y is the target
for train_index, test_index in rkf.split(X):
print(“Train:”, train_index, “Validation:”, val_index)
X_train, X_test = X[train_index], X[val_index]
y_train, y_test = y[train_index], y[val_index]

5、敌对验证

在处理真实的数据集时,经常会遇到测试和训练集非常不同的情况。 因此,内部交叉验证技术可能给出的分数甚至不在测试分数的大部分范围内。 在这种情况下,对抗性验证提供了一个有趣的解决方案。

总体思路是根据特征分布检查训练和测试之间的相似程度。 如果似乎并非如此,我们可以怀疑它们是完全不同的。 这种直觉可以通过组合训练和测试集,分配0/1标签(0训练,1测试)和评估二元分类任务来量化。

让我们了解一下,如何在以下步骤中实现这一点:

1、从火车组中移除目标变量

train.drop([‘target’], axis = 1, inplace = True)

2、为列组中的每一行创建一个新的目标变量,对于测试集中的每一行创建一个新的目标变量

train[‘is_train’] = 1 test[‘is_train’] = 0

3、组合火车和测试数据集

df = pd.concat([train, test], axis = 0)

4、使用上面新创建的目标变量,拟合一个分类模型并预测测试集中每行的概率

y = df[‘is_train’]; df.drop(‘is_train’, axis = 1, inplace = True)
# Xgboost parameters
xgb_params = {‘learning_rate’: 0.05,
‘max_depth’: 4,
‘subsample’: 0.9,
‘colsample_bytree’: 0.9,
‘objective’: ‘binary:logistic’,
‘silent’: 1,
‘n_estimators’:100,
‘gamma’:1,
‘min_child_weight’:4}
clf = xgb.XGBClassifier(**xgb_params, seed = 10)

5、在步骤4中使用计算的概率对列车组进行排序,并将n%样本/行作为验证集(n%是要保留在验证集中的列车组的一部分)

probs = clf.predict_proba(x1)[:,1]
new_df = pd.DataFrame({‘id’:train.id, ‘probs’:probs})
new_df = new_df.sort_values(by = ‘probs’, ascending=False) # 30% validation set
val_set_ids = new_df.iloc[1:np.int(new_df.shape[0]*0.3),1]

val_set_ids将为您提供来自列车集的id,它们将构成与测试集最相似的验证集。 这将使您的验证策略在火车和测试集高度不相似的情况下更加稳健。

但是,使用这种类型的验证技术时必须小心。 一旦测试集的分布发生变化,验证集可能不再是评估模型的好子集。

6、时间序列的交叉验证

随机分割时间序列数据集不起作用,因为您的数据的时间部分将会混乱。 对于时间序列预测问题,我们按照以下方式进行交叉验证。

时间序列交叉倾斜的折叠以前向链式创建

假设我们有一个时间序列,用于n年期间产品的年度消费者需求。 折叠将创建如下:

fold 1: training [1], test [2]
fold 2: training [1 2], test [3]
fold 3: training [1 2 3], test [4]
fold 4: training [1 2 3 4], test [5]
fold 5: training [1 2 3 4 5], test [6]
.
.
.
fold n: training [1 2 3 ….. n-1], test [n]

在Python和R中:使用交叉验证提高模型性能

我们逐步选择一个新的火车和测试集。 我们从一个训练集开始,该训练集具有拟合模型所需的最少观察次数。 逐步地,我们每次都要更换我们的火车和测试台。 在大多数情况下,1步预测可能并不重要。 在这种情况下,可以将预测原点转换为允许使用多步错误。 例如,在回归问题中,以下代码可用于执行交叉验证。

Python 代码:

from sklearn.model_selection import TimeSeriesSplit
X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]])
y = np.array([1, 2, 3, 4])
tscv = TimeSeriesSplit(n_splits=3)
for train_index, test_index in tscv.split(X):
print(“Train:”, train_index, “Validation:”, val_index)
X_train, X_test = X[train_index], X[val_index]
y_train, y_test = y[train_index], y[val_index]

TRAIN: [0] TEST: [1]
TRAIN: [0 1] TEST: [2]
TRAIN: [0 1 2] TEST: [3]

R 代码:

library(fpp)
library(forecast)
e <- tsCV(ts, Arima(x, order=c(2,0,0), h=1) #CV for arima model
sqrt(mean(e^2, na.rm=TRUE)) # RMSE

h = 1意味着我们仅仅为了提前1步预测而采取错误。

(h = 4)前面的4步错误如下图所示。 如果您想评估您的模型以进行多步骤预测,可以使用此方法。

在Python和R中:使用交叉验证提高模型性能

7、自定义交叉验证技术

不幸的是,没有一种方法最适合于各种问题陈述。 通常,可以创建基于特征或特征组合的自定义交叉验证技术,如果该特征在用户在黑客马拉松中提交提交内容时给予用户稳定的交叉验证分数。

例如,在最近完成的由Analytics Vidhya完成的“机器之王”竞赛中,顶尖选手使用的最稳定的验证技术是使用campaign id变量。

请查看本主题参与者讨论的问题陈述和一些方法。

在Python和R中:使用交叉验证提高模型性能

如何衡量模型的偏差 – 方差?

k次交叉验证后,我们将得到k个不同的模型估计误差(e1,e2 … ..ek)。 在理想情况下,这些误差值应该总计为零。 要返回模型的偏差,我们取所有错误的平均值。 降低平均值,更好的模型。

类似地,为了计算模型方差,我们取所有错误的标准偏差。 标准偏差的较低值表明我们的模型在训练数据的不同子集上变化不大。

我们应该把重点放在实现偏差和方差之间的平衡上。 这可以通过在一定程度上减少方差和控制偏差来完成。 这将导致更好的预测模型。 这种折衷通常会导致构建不太复杂的预测模型。 为了更深入地理解偏差 – 方差权衡,请参阅本文的第9节。

结束笔记

在本文中,我们讨论了过度拟合和交叉验证等方法以避免过度拟合。 我们还研究了不同的交叉验证方法,如验证集方法,LOOCV,k-fold交叉验证,分层k-fold等等,然后是在Iris数据集上执行的每种方法在Python和R中的实现。

您是否觉得这篇文章有帮助? 请在下面的评论部分分享您的意见/想法。 不要忘了在AV黑客马拉松中测试这些技术。

英文作者:MUTHUPANDI

英文链接:https://www.analyticsvidhya.com/blog/2018/05/improve-model-performance-cross-validation-in-python-r/

本文由 翻译小组 翻译发布,英文链接:,转载或内容合作请联系我们,未经允许谢绝转载,本文链接:https://www.afenxi.com/55906.html 。

(2)
上一篇 2018-06-15 06:02
下一篇 2018-06-18 09:08

相关文章

关注我们
关注我们
分享本页
返回顶部