本文已参与「新人创作礼」活动,一起开启掘金创作之路。
注意:所有函数仅针对西瓜数据集,如果需要对其他数据集进行分类,只需找到数据集中目标值(西瓜数据集中目标值为是否是好瓜的"是"和"否")所在的列(西瓜数据集中其在最后一列),然后将需要按照目标值进行运行的代码替换即可
留出法实现
实现思路:根据留出法的原理,需要将数据集分为互斥的两个集合,一个作为训练集,另一个作为测试集,在数据划分过程中需要分层采样,为了生成多组数据,需要每次随机划分。 首先统计一下数据集中的正例的个数:
# 计算数据集中的正例数
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
其它读取数据集文件,保存生成的训练集和测试集到文件等其他非主要函数不在此赘述