Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何提高该计数程序的性能?_Python_Performance_Bitarray - Fatal编程技术网

Python 如何提高该计数程序的性能?

Python 如何提高该计数程序的性能?,python,performance,bitarray,Python,Performance,Bitarray,给定的文件如下所示: 1440927 1 1727557 3 1440927 2 9917156 4 第一个字段是一个ID,其范围为(02000000)。第二个字段表示一个类型,该类型在范围(1,5)内。类型1和类型2属于一个共同的类别S1,而类型3和类型4属于S2。一个ID可能有多个不同类型的记录。该文件的大小约为200MB 问题是要计算记录类型为1或2的ID的数量,以及 具有类型为3或4的记录的ID 我的代码: def gen(path): line_count = 0 f

给定的文件如下所示:

1440927 1
1727557 3
1440927 2
9917156 4
第一个字段是一个ID,其
范围为(02000000)
。第二个字段表示一个类型,该类型在范围(1,5)内。类型1和类型2属于一个共同的类别
S1
,而类型3和类型4属于
S2
。一个ID可能有多个不同类型的记录。该文件的大小约为200MB

问题是要计算记录类型为1或2的ID的数量,以及 具有类型为3或4的记录的ID

我的代码:

def gen(path):
    line_count = 0
    for line in open(path):
        tmp = line.split()
        id = int(tmp[0])
        yield id, int(tmp[1])

max_id = 200000000
S1 = bitarray.bitarray(max_id)
S2 = bitarray.bitarray(max_id)
for id, type in gen(path):
    if type != 3 and type != 4:
        S1[id] = True
    else:
        S2[id] = True

print S1.count(), S2.count()
虽然它给出了答案,但我认为它运行得有点慢。我应该怎么做才能让它跑得更快

编辑:
文件中有重复的记录。我只需要区分S1(类型1和类型2)和S2(类型3和类型4)。例如,
1440927 1
1440927 2
仅计数一次,而不是两次,因为它们属于S1。所以我必须存储ID。

您是否与Python绑定

egrep -e "[12]$" filename.txt | cut -d " " -f 1 | sort -u | wc -l

egrep -e "[34]$" filename.txt | cut -d " " -f 1 | sort -u | wc -l
这两个命令计算filename.txt中每行末尾出现(“1”或“2”)和(“3”或“4”)的次数,同时忽略重复的第一个字段


可能比Python更快…

您在文件上使用迭代器,这意味着您一次只缓冲几行。每次缓冲区为空时,磁盘需要查找,程序必须等待

200MB的内存很容易存储,因此获取所有线路将加快速度:

def gen(path):
    # load all the lines, 
    lines = open(path).readlines() 
    split = (line.split() for line in lines)
    return ((int(x), int(y)) for x,y in split)

如果内存足够,可以使用
dict
而不是
bitarray.bitarray
。它可以更快:

S1, S2 = {}, {} # dicts are slightly faster than `set()`
with open(path) as f:
     for i, line in enumerate(f, 1):
         id, sep, type = line.partition(" ")
         if type == "1" or type == "2":
            S1[id] = True
         elif type == "3" or type == "4":
            S2[id] = True
         else:
            print "WARNING: unknown type: %r in line %d: %r" % (type, i, line)
print len(S1), len(S2)
或者您可以尝试先对行进行排序:

def gettype(line):
    return line[-1]

S1, S2 = 0, 0
with open(path) as f:
     lines = f.read().splitlines()

lines.sort(key=gettype)
for type, group in itertools.groupby(lines, gettype):
    ids = (line.partition(" ")[0] for line in group)
    if type == "1" or type == "2":
       S1 += len(set(ids))
    elif type == "3" or type == "4":
       S2 += len(set(ids))
    else:
       assert 0, (type, list(ids))

print S1, S2
第二种方法的渐近复杂性更差


您可以使用它来找出瓶颈所在。

您可以使用探查器。您可以删除
id=int(…
并改用
yield int(tmp[0],…
)。如果使用位数组标记索引有任何原因,您可以使用
。否则,您可以简单地增加计数器,而不是将条目设置为“True”这会给你一个性能提升。+ 1使用探查器。瓶颈在哪里?是S1和S2的分配吗?同样,考虑这些问题:(几乎)所有的数字都在0到200亿之间吗?如果没有,可以考虑另一个数据类型。每个ID可以多次出现吗?如果不是,考虑完全抛弃数组,只使用一个计数器。或者这是一个你已经有一个最佳解决方案的问题。对于真正的大文件,你的瓶颈可能是磁盘I/O,这将需要你购买BETT。er磁盘需要优化。@Boris我必须存储ID,因为有重复的记录。例如,在文件中,样本1440927应该只计数一次,而不是两次。因为类型1和类型2都属于S1。
uniq
需要排序输入,而OP没有。您可以在管道中添加一个
sort
,您是否绑定到Python?vs.您与Linux有关联吗?:)@warvariuc:我的windows桌面在命令行上有一个
grep-E
。你的观点是什么?@MattH,我的观点是:什么更好-绑定到一个单独的程序,还是用Python做所有事情?@warvariuc:我倾向于说,适合于正确工作的正确工具是最好的方法。看起来你在解决方案中使用的是600MBon.@hochl:好的,我将listcomprehension更改为一个生成器表达式。现在它应该使用200MB来存储
。对于f中的行,您无法确定什么更快。readlines()或
对于f中的行
,除非探查器这样说。文件迭代器使用
READAHEAD\u BUFSIZE
8192
)在这种情况下,它意味着一次有数百行。