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

3
我正在尝试构建一个分类模型。本地文件夹中有1000个文本文档。我想将它们分成训练集和测试集,比例为70:30(70 -> 训练集和30 -> 测试集)。有什么更好的方法吗?我正在使用Python。
我希望以编程方式划分训练集和测试集。首先读取本地目录中的文件。其次,构建这些文件的列表,并对它们进行随机洗牌。第三,在训练集和测试集之间进行划分。
我已经尝试了几种仅使用内置Python关键字和函数的方法,但都失败了。最后我得到了一个解决方案。另外,交叉验证是构建通用分类模型的好选择。

Scikit-learn提供了许多可用的函数来实现你想要的功能,并附有示例。如果在应用这些函数时遇到任何困难,请在网上搜索并在此处发布。 - undefined
这个问题有什么问题?为什么会有成员给这个问题投反对票? - undefined
1
Stackoverflow不是用来征求意见的地方,它是专门用于编程的。你只是简单地提问而没有展示任何努力。 - undefined
@VivekKumar 我已经为这些文档准备好了tf-idf。我提出的问题只是我在这个小项目中的一个步骤。我明白这是编程方面的问题,我已经完成了。我在其他问题上也看到过类似下面回答的描述。我只是想知道在拆分文档时的最佳实践。顺便说一句,我在提问之前已经写好了代码。 - undefined
下面的答案帮助我优化了它。我对此非常感激。 :) - undefined
4个回答

19

不确定你需要什么,我尽量详细解释一下。以下是几个步骤:

  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中等效于全局通配符 /ml/data/*.data )。

2. 随机化文件

我们不希望抽样是可预测的,因为这被认为是训练ML分类器的一种较差的方式。

from random import shuffle

def randomize_files(file_list):
    shuffle(file_list)

注意,random.shuffle是一种就地(shuffle in-place)打乱列表的方法,因此它会修改现有列表。(当然,这个函数相当愚蠢,因为你可以直接调用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. 做这个事情

这一步是打开每个文件并进行训练和测试的步骤。我会留给你来完成!


交叉验证

出于好奇,你考虑过使用 交叉验证 吗?这是一种将数据分割成训练和测试集的方法,使每个文档都用于训练和测试。您可以自定义每个“折叠”中用于训练的文档数量。如果您想了解更多信息,我可以深入介绍一下,但如果您不想做这样的话,我就不会。

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

我们有一个由1000个文档组成的数据集。交叉验证的想法是,您可以将其全部用于训练和测试-只是不能同时进行。我们将数据集分成所谓的“折叠”。折叠的数量确定了训练和测试集在任何时候的大小。

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

如果我们使用40折交叉验证系统,第一折将在文档1-25上进行训练,并在26-1000上进行测试,第二折将在26-40上进行训练,并在1-25和51-1000上进行测试,以此类推。

要实现这样的系统,我们仍然需要执行以上步骤中的步骤(1)和(2),但步骤(3)会有所不同。我们可以将函数转换为一个生成器-一个可以像列表一样迭代的函数。

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)

关于你的机器学习系统的实际功能,这由你自己来实现。

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


我想将1000个文本文件(.txt)分割成训练集和测试集,以实现tf-idf,并应用算法来构建一个分类模型。这个模型将根据我的目标将文档分类为两个不同的类别。 - undefined
是的,我考虑过交叉验证。但作为一个初学者,我觉得不需要使用它。我请求你也解释一下交叉验证。拜托了。 - undefined
2
就这个问题而言,使用dir作为你的get_file_list_from_dir函数的参数并不是一个好的做法,因为dir是Python内置函数的名称。或许可以尝试使用directory这样的变量名代替。 - undefined
1
@not_a_robot 是的,你说得对!我通常对此要求更加严格,但之前着急了一下,哈哈。现在已经更新了,谢谢! :) - undefined
1
k折交叉验证实际上是以相反的顺序进行解释的。每次,其中一个k个子集被用作测试集,而其他k-1个子集则组合在一起形成训练集。 - undefined
显示剩余2条评论

4

如果您使用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']

2

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


1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接