生成训练集和测试集的方法实现

623 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

注意:所有函数仅针对西瓜数据集,如果需要对其他数据集进行分类,只需找到数据集中目标值(西瓜数据集中目标值为是否是好瓜的"是"和"否")所在的列(西瓜数据集中其在最后一列),然后将需要按照目标值进行运行的代码替换即可

留出法实现

实现思路:根据留出法的原理,需要将数据集分为互斥的两个集合,一个作为训练集,另一个作为测试集,在数据划分过程中需要分层采样,为了生成多组数据,需要每次随机划分。 首先统计一下数据集中的正例的个数:

# 计算数据集中的正例数
    for data in data_set:
        if data[-1] == "是":
            positive_size += 1

然后计算一下需要的训练集的大小:

# 计算训练集大小
    train_set_size = int(percent / 100 * len(data_set)+0.5)

其中,percent是训练集占数据集的百分比,需要人为输入。 再然后计算一下训练集中需要的正例个数:

# 计算训练集中需要的正例大小
    positive_train_data_size = int(
        train_set_size / len(data_set) * positive_size + 0.5)

为了每次划分都随机且训练集和测试集互斥,使用sample生成随机数作为即将采集训练的下标:

# 每组训练集和数据集保证随机划分
        index_list = random.sample(range(0, len(data_set)), len(data_set))

使用for循环分层训练集和测试集:

# 划分训练集、数据集
        for j in index_list:
            if data_set[j][-1] == "是":
                if positive_count < positive_train_data_size:
                    train_set.append(data_set[j])
                    positive_count += 1
                else:
                    test_set.append(data_set[j])
            else:
                if negative_count < train_set_size - positive_train_data_size:
                    train_set.append(data_set[j])
                    negative_count += 1
                else:
                    test_set.append(data_set[j])

每生成完一组训练集和测试集就将其存起来

k_train_set.append(train_set)
k_test_set.append(test_set)

总的程序如下:


def setAside(data_set):
    '''使用留出法生成数据集'''
    positive_size = 0
    # 计算数据集中的正例数
    for data in data_set:
        if data[-1] == "是" or data[-1] == "1":
            positive_size += 1
    percent = int(input("训练集占总数据集百分比(1~99):"))
    # 计算训练集大小
    train_set_size = int(percent / 100 * len(data_set)+0.5)
    # 计算训练集中需要的正例大小
    positive_train_data_size = int(
        train_set_size / len(data_set) * positive_size + 0.5)
    group_num = int(input("需要多少组? "))
    k_train_set, k_test_set = [], []
    # 生成训练集、测试集
    for i in range(group_num):
        # 每组训练集和数据集保证随机划分
        index_list = random.sample(range(0, len(data_set)), len(data_set))
        # 存放一组数据集和训练集
        train_set, test_set = [], []
        # 训练集中正反例计数,为了确定正反例已存够
        positive_count, negative_count = 0, 0
        # 划分训练集、数据集
        for j in index_list:
            if data_set[j][-1] == "是" or data[-1] == "1":
                if positive_count < positive_train_data_size:
                    train_set.append(data_set[j])
                    positive_count += 1
                else:
                    test_set.append(data_set[j])
            else:
                if negative_count < train_set_size - positive_train_data_size:
                    train_set.append(data_set[j])
                    negative_count += 1
                else:
                    test_set.append(data_set[j])
        k_train_set.append(train_set)
        k_test_set.append(test_set)
    # 返回训练集、数据集组,组数
    return k_train_set, k_test_set, group_num

k折交叉验证法实现

实现思路:K折交叉验证法是将数据集划分为k个互斥子集,取出一个作为测试集,其余作为训练集,且要分层采样,如果像留出法那样计算各个子集需要的各种数据,会导致程序太复杂,所以采用另外一种思路,就是将其按照是否是好瓜进行排序,然后依次存入各个列表。 首先,将数据集排序

# 按照表中最后一个元素来排序,便于分层
    data_set.sort(key=lambda k: k[-1])

然后将排好序的数据集依次存入大小为k的list

# 分层划分数据集为k份
    for i in range(len(data_set)):
        k_list[i % k].append(data_set[i])

这样,数据就被分层分为了互斥的k份 然后将k份数据中的一份作为测试集,其他作为训练集来分类,每划分一次就将其结果存下来

# 生成k个数据集和k个训练集
    for i in range(k):
        temp_set = []
        for j in range(k):
            if j != i:
                temp_set.extend(k_list[j])
            else:
                k_test_set.append(k_list[j])
        k_train_set.append(temp_set)

总的程序如下:

def crossValidate(data_set):
    '''使用k折交叉验证法生成数据集'''
    # 按照表中最后一个元素来排序,便于分层
    data_set.sort(key=lambda k: k[-1])
    k = int(input("输入折数k(k>1):"))
    # 生成k个列表放在一个列表中
    k_list = list([] for i in range(k))
    k_train_set = list([])
    k_test_set = list([])
    # 分层划分数据集为k份
    for i in range(len(data_set)):
        k_list[i % k].append(data_set[i])
    # 生成k个数据集和k个训练集
    for i in range(k):
        temp_set = []
        for j in range(k):
            if j != i:
                temp_set.extend(k_list[j])
            else:
                k_test_set.append(k_list[j])
        k_train_set.append(temp_set)
    # 返回训练集、数据集组,组数
    return k_train_set, k_test_set, k

自助法实现

实现思路:自助法就是从大小的m数据集中随机采样(本随机采样类似于放回抽样)m次数据,作为训练集,其余的作为测试集。 首先得到m的大小

m = len(data_set)

为了可以生成多组训练集和测试集,所以生成需要的组数组随机数,每组随机数的范围为0~m-1,因为数据集的下标范围是从0开始到m-1结束

# 生成group组随机数,每组有m个,随机数的范围为0~m-1
ran_lis = list([[random.randint(0, m-1)for i in range(m)] for j in range(group)])

然后分出训练集和测试集

# 生成训练集,测试集
    for i in range(group):
        train_set = []
        test_set = []
        # 随机采样m个数据放在训练集中
        for j in ran_lis[i]:
            train_set.append(data_set[j])
        # 余下的数据放在测试集中
        for data in data_set:
            if data not in train_set:
                test_set.append(data)
        k_train_set.append(train_set)
        k_test_set.append(test_set)
总的程序如下:
def bootstrap(data_set):
    m = len(data_set)
    group = int(input("需要多少组? "))
    # 生成group组随机数,每组有m个,随机数的范围为0~m-1
    ran_lis = list([[random.randint(0, m-1)
                     for i in range(m)] for j in range(group)])
    k_train_set = []
    k_test_set = []
    # 生成训练集,测试集
    for i in range(group):
        train_set = []
        test_set = []
        # 随机采样m个数据放在训练集中
        for j in ran_lis[i]:
            train_set.append(data_set[j])
        # 余下的数据放在测试集中
        for data in data_set:
            if data not in train_set:
                test_set.append(data)
        k_train_set.append(train_set)
        k_test_set.append(test_set)
    # 返回训练集、数据集组,组数
    return k_train_set, k_test_set, group

其它读取数据集文件,保存生成的训练集和测试集到文件等其他非主要函数不在此赘述