如何将文档拆分为训练集和测试集?

How to split documents into training set and test set?

我正在尝试构建分类模型。我在本地文件夹中有 1000 个文本文档。我想将它们分成训练集和测试集,分割比例为 70:30(70 -> Training and 30 -> Test) 这样做的更好方法是什么?我正在使用 python.


我想要一种以编程方式拆分训练集和测试集的方法。首先读取本地目录中的文件。其次,构建这些文件的列表并将它们打乱。第三,将它们分成训练集和测试集。

我尝试了几种使用内置 python 关键字和函数的方法,但都失败了。最后我有了接近它的想法。交叉验证也是构建通用分类模型的一个不错的选择。

只需使用 os.listdir() 列出文件名。使用 collections.shuffle() 打乱列表,然后 training_files = filenames[:700]testing_files = filenames[700:]

如果你使用numpy就很简单了,首先加载文档并把它们做成一个numpy数组,然后:

import numpy as np

docs = np.array([
    'one', 'two', 'three', 'four', 'five',
    'six', 'seven', 'eight', 'nine', 'ten',
    ])

idx = np.hstack((np.ones(7), np.zeros(3))) # generate indices
np.random.shuffle(idx) # shuffle to make training data and test data random

train = docs[idx == 1]
test = docs[idx == 0]

print(train)
print(test)

结果:

['one' 'two' 'three' 'six' 'eight' 'nine' 'ten']
['four' 'five' 'seven']

不确定确切地你想要什么,所以我会尽量全面。会有几个步骤:

  1. 获取文件列表
  2. 随机化文件
  3. 将文件拆分为训练集和测试集
  4. 做事

1。获取文件列表

假设您的文件都具有扩展名 .data,并且它们都在文件夹 /ml/data/ 中。我们要做的是获取所有这些文件的列表。这只需使用 os 模块即可完成。我假设你没有子目录;如果有的话,这会改变。

import os

def get_file_list_from_dir(datadir):
    all_files = os.listdir(os.path.abspath(datadir))
    data_files = list(filter(lambda file: file.endswith('.data'), all_files))
    return data_files

因此,如果我们调用 get_file_list_from_dir('/ml/data'),我们将返回该目录中所有 .data 文件的列表(在 shell 中相当于 glob /ml/data/*.data).

2。随机化文件

我们不希望采样是可预测的,因为这被认为是训练 ML 分类器的糟糕方法。

from random import shuffle

def randomize_files(file_list):
    shuffle(file_list)

请注意,random.shuffle 执行 就地 改组,因此它修改了现有列表。 (当然,这个函数相当愚蠢,因为你可以调用 shuffle 而不是 randomize_files;你可以将它写入另一个函数以使其更有意义。)

3。将文件拆分为训练集和测试集

我将假设 70:30 比率而不是任何特定数量的文档。所以:

from math import floor

def get_training_and_testing_sets(file_list):
    split = 0.7
    split_index = floor(len(file_list) * split)
    training = file_list[:split_index]
    testing = file_list[split_index:]
    return training, testing

4。做事

这是您打开每个文件并进行训练和测试的步骤。这个就交给你了!


交叉验证

出于好奇,您是否考虑过使用 cross-validation?这是一种拆分数据的方法,以便您使用每个文档进行训练和测试。您可以自定义每个 "fold" 中用于训练的文档数量。如果你愿意,我可以更深入地讨论这个问题,但如果你不想这样做,我不会。

编辑:好的,既然你要求我再解释一下。

所以我们有一个包含 1000 个文档的数据集。交叉验证的想法是,您可以使用 all 进行训练和测试——只是不能同时使用。我们将数据集拆分为我们所说的 "folds"。折叠的数量决定了任何给定时间点的训练集和测试集的大小。

假设我们想要一个 10 折交叉验证系统。这意味着训练和测试算法将 运行 十次。第一次将在文档 1-100 上训练并在 101-1000 上测试。第二折将在 101-200 上训练,在 1-100 和 201-1000 上测试。

如果我们做一个 40 折的 CV 系统,第一次折将在文档 1-25 上训练并在 26-1000 上测试,第二折将在 26-40 上训练并在 1-25 上测试和 51-1000,等等。

要实现这样一个系统,我们仍然需要执行上面的步骤 (1) 和 (2),但步骤 (3) 会有所不同。我们可以将函数转换为 generator——我们可以像列表一样遍历的函数,而不是只分成两组(一组用于训练,一组用于测试)。

def cross_validate(data_files, folds):
    if len(data_files) % folds != 0:
        raise ValueError(
            "invalid number of folds ({}) for the number of "
            "documents ({})".format(folds, len(data_files))
        )
    fold_size = len(data_files) // folds
    for split_index in range(0, len(data_files), fold_size):
        training = data_files[split_index:split_index + fold_size]
        testing = data_files[:split_index] + data_files[split_index + fold_size:]
        yield training, testing

最后的 yield 关键字使它成为一个生成器。要使用它,您可以像这样使用它:

def ml_function(datadir, num_folds):
    data_files = get_file_list_from_dir(datadir)
    randomize_files(data_files)
    for train_set, test_set in cross_validate(data_files, num_folds):
        do_ml_training(train_set)
        do_ml_testing(test_set)

同样,实现机器学习系统的实际功能取决于您。

声明一下,我不是专家,哈哈。但是,如果您对我在这里写的任何内容有任何疑问,请告诉我!

你可以使用sklearn提供的train_test_split方法。请参阅此处的文档:

http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html