我目前正在尝试从Python 2.7中的.csv文件中读取数据,该文件最多包含100万行和200列(文件范围从100mb到1.6gb)。对于少于300,000行的文件,我可以(非常缓慢地)执行此操作,但是一旦超过该行,就会出现内存错误。我的代码如下所示:
def getdata(filename, criteria): data=[] for criterion in criteria: data.append(getstuff(filename, criteron)) return data def getstuff(filename, criterion): import csv data=[] with open(filename, "rb") as csvfile: datareader=csv.reader(csvfile) for row in datareader: if row[3]=="column header": data.append(row) elif len(data)<2 and row[3]!=criterion: pass elif row[3]==criterion: data.append(row) else: return data
在getstuff函数中使用else子句的原因是,所有符合条件的元素都将一起列在csv文件中,因此当我经过它们时,为了节省时间,我离开了循环。
我的问题是:
我如何设法使其与较大的文件一起使用?
有什么办法可以使它更快?
我的计算机具有8gb RAM,运行64位Windows 7,处理器为3.40 GHz(不确定您需要什么信息)。
您正在将所有行读入列表,然后处理该列表。 不要那样做 。
在生成行时对其进行处理。如果需要先过滤数据,请使用生成器函数:
import csv def getstuff(filename, criterion): with open(filename, "rb") as csvfile: datareader = csv.reader(csvfile) yield next(datareader) # yield the header row count = 0 for row in datareader: if row[3] == criterion: yield row count += 1 elif count: # done when having read a consecutive series of rows return
我还简化了您的过滤器测试;逻辑相同但更简洁。
因为只匹配与条件匹配的单个行序列,所以还可以使用:
import csv from itertools import dropwhile, takewhile def getstuff(filename, criterion): with open(filename, "rb") as csvfile: datareader = csv.reader(csvfile) yield next(datareader) # yield the header row # first row, plus any subsequent rows that match, then stop # reading altogether # Python 2: use `for row in takewhile(...): yield row` instead # instead of `yield from takewhile(...)`. yield from takewhile( lambda r: r[3] == criterion, dropwhile(lambda r: r[3] != criterion, datareader)) return
您现在可以getstuff()直接循环。在getdata():
getstuff()
getdata()
def getdata(filename, criteria): for criterion in criteria: for row in getstuff(filename, criterion): yield row
现在直接getdata()在您的代码中循环:
for row in getdata(somefilename, sequence_of_criteria): # process row
现在,您只在内存中保留 一行 ,而不是每个条件存储数千行。
yield使函数成为生成器函数,这意味着直到开始循环它之前,它不会做任何工作。
yield