Python "输入数据

0 投票
5 回答
636 浏览
提问于 2025-04-16 17:40

我有一个以 *.data 结尾的文件,这个文件里的数据是按照特定顺序排列的:

2.5,10,U1
3,4.5,U1
3,9,U1
3.5,5.5,U1
3.5,8,U1
4,7.5,U1
4.5,3.5,U1
4.5,4.5,U1
4.5,6,U1
5,5,U1
5,7,U1
7,6.5,U1
3.5,9.5,U2
3.5,10.5,U2
4.5,8,U2
4.5,10.5,U2
5,9,U2
5.5,5.5,U2
5.5,7.5,U2

在这些数据中(我有不同类型的数据,这里只是举个例子,只有两个类别),有两个类别:U1 和 U2,每个类别都有两个值……我需要做的是读取这些数据,并把它们分成不同的类别,在这个例子中就是 U1 和 U2……然后,我需要从每个类别中取出 2/3 的数据放到一个新的值(学习集 learning_set)里,剩下的 1/3 放到另一个值(测试集 test_set)里。

我开始写了这个代码:

data = open('set.data', 'rt')                             
data_list=[]                                                   
border=2./3                                                  
data_list = [line.strip().split(',') for line in data]

learning_set=data_list[:int(round(len(data_list)*border))]
test_set=data_list[int(round(len(data_list)*border)):]

但是这样我取出的 2/3 和 1/3 是从所有数据中分的,而不是从每个类别中分的。

非常感谢大家的帮助!

5 个回答

2

我觉得这段内容还是有点用的(而且我已经打出来了),我会用类似下面的方式来实现...

from itertools import groupby
from operator import attrgetter
from collections import namedtuple

row_container = namedtuple('row', 'val1,val2,klass')

def process_row(row):
    """Return a named tuple"""
    return row_container(float(row[0]), float(row[1]), row[2])

def bisect_list(split_list, fraction):
    split_index = int(fraction * len(split_list))
    return split_list[:split_index], split_list[split_index:]


data = open('test.csv', 'rt')

## Parse & process each line
data = (row.strip().split(',') for row in data)
data = (process_row(row) for row in data)

## Sort & group the data by class
sorted_data = sorted(data, key=attrgetter('klass'))
grouped_data = groupby(sorted_data, attrgetter('klass'))

## For each class, create learning and test sets
final_data = {}
for klass, class_rows in grouped_data:
    learning_set, test_set = bisect_list(list(class_rows), 0.66)
    final_data[klass] = dict(learning=learning_set, test=test_set)

这个方法的操作方式和之前其他的回答差不多。它使用了命名元组。bisectlist() 是从 @senderle 那里借来的。

2

哦,你想要了解一下itertools.groupby这个东西:

import itertools
class_dict = dict(itertools.groupby(data_list, key=lambda x: x[-1]))
class_names = class_dict.keys()
class_lists = [list(group) for group in class_dict.values()]

然后只需要根据需要切分每个在class_lists里的列表,并用结果来扩展学习集和测试集。

这里有一个完整的解决方案:

data_list = [line.strip().split(',') for line in data]
data_list.sort(key=lambda x: x[-1])

def bisect_list(split_list, fraction):
    split_index = int(fraction * len(split_list))
    return split_list[:split_index], split_list[split_index:]

learning_set, test_set = [], []
for key, group in itertools.groupby(data_list, key=lambda x: x[-1]):
    l, t = bisect_list(list(group), 0.66)
    learning_set.extend(l)
    test_set.extend(t)
2

你可以在读取数据后,把你的列表分成两个不同的子集:

data_list_1 = [(x,y,c) for (x,y,c) in data_list if c=='U1']
data_list_2 = [(x,y,c) for (x,y,c) in data_list if c=='U2']

然后,你可以像之前一样,基于这些过滤后的列表,构建两个不同的学习集和测试集,比如:

learning_set = data_list_1[:int(round(len(data_list_1)*border))] + data_list_2[:int(round(len(data_list_2)*border))]

测试集也是同样的处理。

更新:如果你事先不知道有哪些类别,可以使用以下代码先检测所有的类别,然后再对它们进行循环处理。

classes = set([t[-1] for t in data_list])

learning_set = []
test_set = []

for cl in classes:
    data_list_filtered = [t for t in data_list if t[-1]==cl]

    learning_set += data_list_filtered[:int(round(len(data_list_filtered)*border))]
    test_set += data_list_filtered[int(round(len(data_list_filtered)*border)):]

撰写回答