在Python中对序列进行排序的最佳方法是什么?

时间:2013-07-09 20:29:47

标签: python csv conditional

我正在尝试根据需要连续发生的某些条件对表进行排序。 表的简化版本:

Number  Time
   1    23
   2    45
   3    67
   4    23
   5    11
   6    45
   7    123
   8    34

...

我需要检查时间是否连续40次<40次。就像我需要检查1-5行,然后2-6等...然后打印并保存到文件的第一次和最后一次。比如,如果第2-6行符合条件,我将需要打印第2号和第6号的时间。检查应在条件满足后停止。无需检查其他行。我实现了一个带有两个临时变量的计数器来检查到目前为止连续3个项目。它工作正常。但是,如果我想检查连续30次发生的情况,我不能手动创建30个临时变量。实现这一目标的最佳方法是什么?我想我只需要某种循环。谢谢!

以下是我的代码的一部分:

reader = csv.reader(open(filename))
counter, temp1, temp2, numrow = 0, 0, 0, 0

for row in reader:
    numrow+=1
    if numrow <5:
        col0, col1, col4, col5, col6, col23, col24, col25 = float(row[0]),
            float(row[1]), float(row[4]), float(row[5]),float(row[6]), 
            float(row[23]), float(row[24]), float(row[25])
        if col1 <= 40:
            list1=(col1, col3, col4, col5, col6, col23, col24, col25)
            counter += 1
            if counter == 3:
                print("Cell# %s" %filename[-10:-5])
                print LAYOUT.format(*headers_short)
                print LAYOUT.format(*temp1)
                print LAYOUT.format(*temp2)
                print LAYOUT.format(*list1)
                print ""

            elif counter == 1:
                temp1=list1

            elif counter == 2:
                temp2=list1

        else:
            counter = 0

我实施了Bakuriu建议的解决方案,它似乎正在运作。但是,结合众多测试的最佳方法是什么?就像我需要检查几个条件。让我们说: v

  • 连续10个周期内效率低于40,
  • 行中5个周期内容量小于40
  • 连续25个循环的时间少于40
  • 和其他一些......

现在我只需为每次测试打开csv.reader并运行该功能。我想这不是最有效的方式,虽然它有效。对不起,我只是一个完整的菜鸟。

csvfiles = glob.glob('processed_data/*.stat')
for filename in csvfiles: 

    flag=[]
    flag.append(filename[-12:-5])
    reader = csv.reader(open(filename))
    for a, row_group in enumerate(row_grouper(reader,10)):
        if all(float(row[1]) < 40 for row in row_group):         
            str1= "Efficiency is less than 40 in cycles "+ str(a+1)+'-'+str(a+10)  #i is the index of the first row in the group.
            flag.append(str1)
            break #stop processing other rows.

    reader = csv.reader(open(filename))    
    for b, row_group in enumerate(row_grouper(reader,5)):
        if all(float(row[3]) < 40 for row in row_group):
            str1= "Capacity is less than 40 minutes in cycles "+ str(a+1)+'-'+str(a+5)
            flag.append(str1)
            break #stop processing other rows.

    reader = csv.reader(open(filename))    
    for b, row_group in enumerate(row_grouper(reader,25)):
        if all(float(row[3]) < 40 for row in row_group):
            str1= "Time is less than < 40 in cycles "+ str(a+1)+'-'+str(a+25)
            flag.append(str1)
            break #stop processing other rows.

   if len(flag)>1:

       for i in flag:
            print i
        print '\n'

2 个答案:

答案 0 :(得分:2)

您根本不必对数据进行排序。一个简单的解决方案可能是:

def row_grouper(reader):
    iterrows = iter(reader)
    current = [next(iterrows) for _ in range(5)]
    for next_row in iterrows:
        yield current
        current.pop(0)
        current.append(next_row)


reader = csv.reader(open(filename))

for i, row_group in enumerate(row_grouper(reader)):
    if all(float(row[1]) < 40 for row in row_group):
        print i, i+5  #i is the index of the first row in the group.
        break #stop processing other rows.

row_grouper函数是一个生成连续行的5个元素列表的生成器。每次删除组的第一行并在最后添加新行。


您可以使用list而不是简单deque,并使用pop(0)调用替换row_grouper中的popleft()更有效,尽管这样做如果列表只有5个元素,则无关紧要。

或者,您可以使用martineau建议并使用maxlen关键字参数并避免pop。这大约是使用deque的popleft的两倍,这大约是使用list的{​​{1}}的两倍。


修改:要检查多个条件,您可以修改使用多个pop(0)并使用row_grouper获取可迭代的副本。

例如:

itertools.tee

第一部分只是导入import itertools as it def check_condition(group, row_index, limit, found): if group is None or found: return False return all(float(row[row_index]) < limit for row in group) f_iter, s_iter, t_iter = it.tee(iter(reader), 3) groups = row_grouper(f_iter, 10), row_grouper(s_iter, 5), row_grouper(t_iter, 25) found_first = found_second = found_third = False for index, (first, second, third) in enumerate(it.izip_longest(*groups)): if check_condition(first, 1, 40, found_first): #stuff found_first = True if check_condition(second, 3, 40, found_second): #stuff found_second = True if check_condition(third, 3, 40, found_third): # stuff found_third = True if found_first and found_second and found_third: #stop the code if we matched all the conditions once. break (并指定“别名”itertools以避免每次都输入it

我已经定义了itertools函数,因为条件越来越复杂,你不想一遍又一遍地重复它们。正如您所看到的,check_condition的最后一行与之前的条件相同:它检查当前“行组”是否验证该属性。由于我们计划只迭代文件一次,并且当只满足一个条件时我们无法停止循环(因为我们错过了其他条件)我们必须使用一些标志告诉我们条件是否(例如)时间是以前见过或不见过面。正如您在check_condition循环中看到的那样,当满足所有条件时,我们for会退出循环。

现在,行:

break

f_iter, s_iter, t_iter = it.tee(iter(reader), 3) 行上创建一个迭代,并制作3份副本。 这意味着循环:

reader

将打印文件的所有行,就像执行for row in f_iter: print(row) 一样。 但请注意,for row in reader允许我们获取行的副本,而不会多次读取文件。

之后,我们必须将这些行传递给itertools.tee以验证条件:

row_grouper

最后,我们必须遍历“行组”。要同时执行此操作,我们在python3中使用groups = row_grouper(f_iter, 10), row_grouper(s_iter, 5), row_grouper(t_iter, 25) (重命名为itertools.izip_longest(不带itertools.zip_longest)。 它就像i一样,创建元素对(例如zip)。区别在于zip([1, 2, 3], ["a", "b", "c"]) -> [(1, "a"), (2, "b"), (3, "c")] pad izip_longest s的较短迭代。这可以确保我们检查所有可能组的条件(这也是None必须检查check_conditiongroup)的原因。

要获取当前行索引,我们将所有内容都包装在None中,就像之前一样。 在enumerate内部,代码非常简单:使用for检查条件,如果满足条件,则执行必须设置的条件该条件的标志(以便在以下循环中条件始终为check_condition)。

(注意:我必须说我没有测试代码。当我有一点时间时我会测试它,无论如何我希望我给你一些想法。并查看False的文档)

答案 1 :(得分:1)

您不需要对数据进行排序,只需跟踪您所查找的条件是否发生在最后 N 行的数据中。固定大小的collections.deque对这类事情有好处。

import csv
from collections import deque
filename = 'table.csv'
GROUP_SIZE = 5
THRESHOLD = 40
cond_deque = deque(maxlen=GROUP_SIZE)

with open(filename) as datafile:
    reader = csv.reader(datafile) # assume delimiter=','
    reader.next() # skip header row
    for linenum, row in enumerate(reader, start=1):  # process rows of file
        col0, col1, col4, col5, col6, col23, col24, col25 = (
            float(row[i]) for i in (0, 1, 4, 5, 6, 23, 24, 25))
        cond_deque.append(col1 < THRESHOLD)
        if cond_deque.count(True) == GROUP_SIZE:
            print 'lines {}-{} had {} consecutive rows with col1 < {}'.format(
                linenum-GROUP_SIZE+1, linenum, GROUP_SIZE, THRESHOLD)
            break  # found, so stop looking