Pandas:如何在不使用 scikit 的情况下进行交叉验证?

Posted

技术标签:

【中文标题】Pandas:如何在不使用 scikit 的情况下进行交叉验证?【英文标题】:Pandas: How can I do cross validation without using scikit? 【发布时间】:2017-09-12 12:22:55 【问题描述】:

我正在尝试实现自己的交叉验证功能。我在link 上阅读了有关交叉验证的信息,并且能够将我的数据集拆分为训练和测试。但是如何定义折叠? 例如我的数据框是这样的。

    Dataframe:
        MMC         MET_lep     MASS_Vis    Pt_H        Y
    0   138.70      51.65       97.82       0.91        0
    1   160.93      68.78       103.23      -999.00     0
    2   -999.00     162.17      125.95      -999.00     0
    3   143.90      81.41       80.94       -999.00     1
    4   175.86      16.91       134.80      -999.00     0
    5   -999.00     162.17      125.95      -999.00     0
    6   143.90      81.41       80.94       -999.00     1
    7   175.86      16.91       134.80      -999.00     0
    8   -999.00     162.17      125.95      -999.00     0
    9   143.90      81.41       80.94       -999.00     1

想要这样的输出:

For    K=3 (Folds)

When K=1
Training:
            MMC         MET_lep     MASS_Vis    Pt_H        Y
        0   138.70      51.65       97.82       0.91        0
        1   160.93      68.78       103.23      -999.00     0
        2   -999.00     162.17      125.95      -999.00     0
        3   143.90      81.41       80.94       -999.00     1
        4   175.86      16.91       134.80      -999.00     0
        5   -999.00     162.17      125.95      -999.00     0
        6   143.90      81.41       80.94       -999.00     1
Test:
        7   175.86      16.91       134.80      -999.00     0
        8   -999.00     162.17      125.95      -999.00     0
        9   143.90      81.41       80.94       -999.00     1

When K=2
Training:
            MMC         MET_lep     MASS_Vis    Pt_H        Y
        0   138.70      51.65       97.82       0.91        0
        1   160.93      68.78       103.23      -999.00     0
        2   -999.00     162.17      125.95      -999.00     0
        6   143.90      81.41       80.94       -999.00     1
        7   175.86      16.91       134.80      -999.00     0
        8   -999.00     162.17      125.95      -999.00     0
        9   143.90      81.41       80.94       -999.00     1

Test:
        3   143.90      81.41       80.94       -999.00     1
        4   175.86      16.91       134.80      -999.00     0
        5   -999.00     162.17      125.95      -999.00     0

When K=3
Training:
            MMC         MET_lep     MASS_Vis    Pt_H        Y
        0   138.70      51.65       97.82       0.91        0
        1   160.93      68.78       103.23      -999.00     0
        2   -999.00     162.17      125.95      -999.00     0
        3   143.90      81.41       80.94       -999.00     1
        7   175.86      16.91       134.80      -999.00     0
        8   -999.00     162.17      125.95      -999.00     0
        9   143.90      81.41       80.94       -999.00     1
Test:
        4   175.86      16.91       134.80      -999.00     0
        5   -999.00     162.17      125.95      -999.00     0
        6   143.90      81.41       80.94       -999.00     1

下面是我的代码,它完成了拆分但不折叠的工作:

 split = math.floor(dataset.shape[0]*0.8)
    data_train = dataset[:split]
    data_test = dataset[split:]

提前感谢您对此提供的帮助。

【问题讨论】:

【参考方案1】:

您是否打算将 K=2 折叠与 K=3 测试折叠 (3,4,5) 与 (4,5,6) 重叠?此外,在您的示例中,似乎 K 被重载以表示折叠数和当前折叠的索引。在我的回答中,我将 i 用于 k 总折叠中的第 i 折叠。

假设目标是创建不重叠的折叠,那么有一个函数可以在 0 到 len(dataset) - 1 的范围内产生大致均匀的范​​围就足够了。即使你的list 不能被在 floor((n*i)/k) 处的 k 分裂完全整除。在 python 中,你可以使用这样的函数:

def fold_i_of_k(dataset, i, k):
    n = len(dataset)
    return dataset[n*(i-1)//k:n*i//k]

这是一个关于一维数据集的示例(应该同样适用于 DataFrame):

>>> fold_i_of_k(list(range(0,11)),1,3)
[0, 1, 2]
>>> fold_i_of_k(list(range(0,11)),2,3)
[3, 4, 5, 6]
>>> fold_i_of_k(list(range(0,11)),3,3)
[7, 8, 9, 10]

【讨论】:

谢谢!很好的答案,请注意您在return 行上有一个额外的括号:它应该是n*(i-1)//k,而不是n*(i-1))//k。我确认它在 pandas.DataFrame 上效果很好:)【参考方案2】:

此解决方案基于 pandas 和 numpy 库:

import pandas as pd
import numpy as np

首先将数据集拆分为 k 个部分:

k = 10
folds = np.array_split(data, k)

然后你迭代你的折叠,使用一个作为测试集,另一个 k-1 作为训练,所以最后你执行了 k 次拟合:

for i in range(k):
    train = folds.copy() // you wanna work on a copy of your array
    test = folds[i]
    del train[i]
    train = pd.concat(train, sort=False)
    perform(clf, train.copy(), test.copy()) // do the fitting, here you also want to copy

在此函数中,您从集合中删除标签列并拟合 scikit 分类器 (clf),然后返回预测。

def perform(clf, train_set, test_set):
    # remove labels from data
    train_labels = train_set.pop('Y').values
    test_labels = test_set.pop('Y').values
    clf.fit(train_set, train_labels)
    return clf.score(test_set, test_labels)

【讨论】:

而不是拆分数组,如果您可以获取索引并使用这些索引迭代数组会更好

以上是关于Pandas:如何在不使用 scikit 的情况下进行交叉验证?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不拟合的情况下实例化具有已知系数的 Scikit-Learn 线性模型

如何在不使用外部库(例如 Numpy、Pandas)的情况下读取 CSV 文件?

如何在不使用 Pandas 的情况下创建等效于 numpy.nan 的日期时间对象?

Python Pandas:如何在不编写辅助函数的情况下使用 apply 广播操作

如何在不重复列的情况下合并 Pandas 数据框

如何在不丢失值的情况下将 json 解析为 pandas 数据框? [复制]