使用Python对csv中的列子集求和

时间:2013-09-13 14:45:07

标签: python csv sum

我正在尝试优化某些代码以更快地运行。对于此文本文件矩阵:

TAG, DESC, ID1, ID2, ID3, ID4, 
1, "details", 0, 1, NA, 1, 2
2, "details", 2, 1, NA, 0, 1
3, "details", 1, NA, NA, 0, 2
...

这是一个包含~10,000列和~2M行的大文件。我想要做的是计算所有ID的总和(TAG = 1时为4)和给定最大值为2(因此4/8 = 0.5)的频率,然后将这些值附加到新列。 NA缺少数据并且有效地为零。这段代码有效,但速度很慢:

tab_dict =csv.DictReader(open(path), delimiter=",") 
tab_reader = [row for row in tab_dict]

for t in tab_reader:
    idlist = [i for i in t.keys()] 
    idlist.remove('TAG')  #exclude columns that do not contain numbers for summing
    idlist.remove('DESC')
    rowsum = 0
    for i in idlist:
        try: rowsum+= int(t[i]) #try/except to handle "NA"s
        except: TypeError
    t["ROWSUM"] = rowsum  # create the new columns
    t["ROWFREQ"] = float(rowsum)/ float(2*len(idlist))

有关如何加快速度的任何建议?感谢

2 个答案:

答案 0 :(得分:2)

是否将整个文件读入tab_reader列表,以便您可以随时修改它?如果可能的话,这是你应该避免的。由于读者是一个迭代器,如果你以后的处理不需要整个文件在内存中,那么逐行编写修改后的输出会更好。

这个版本仍然使用dictreader,但更多的内置工具应该更快:

ignored_keys = frozenset(('TAG', 'DESC'))   
desired_keys = [key for key in tab_dict.fieldnames if key not in ignored_keys]
frequency_divisor = float(2*len(desired_keys))
for t in tab_reader:
    rowsum = sum((int(t[key]) for key in desired_keys if t[key] != 'NA'))
    rowfreq = float(rowsum) / frequency_divisor
    t["ROWSUM"] = rowsum
    t["ROWFREQ"] = rowfreq

我认为你会看到使用csv.reader实例而不是DictReader并预先计算所需索引列表而不是键的额外改进。或者,当然,如果'TAG'和'DESC'总是前两个:

   rowsum = sum((int(x) for x in t[2:] if x != 'NA'))

答案 1 :(得分:2)

首先,你循环数据两次,一次创建tab_reader,一次加总和所有值。其次,你可能想放弃你的DictReader并简单地循环遍历文件。此外,使用内置函数会加快。

from __future__ import division # to use float division

for line in open(path):
    ids = line.split(',')[2:]
    ids = [int(id) if id != 'NA' else 0 for id in ids]
    rowsum = sum(ids)
    rowfreq = rowsum / 2 * len(ids)