阅读巨大的 .csv 文件。

11 浏览
0 Comments

阅读巨大的 .csv 文件。

我目前正在尝试在Python 2.7中读取带有多达1百万行和200列的csv文件(文件范围从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文件中一起列出,因此当我超过它们时,我会离开循环以节省时间。

我的问题是:

  1. 如何使它能够处理更大的文件?
  2. 有什么方法可以使它更快?

我的计算机具有8GB RAM,运行64位Windows 7,处理器为3.40 GHz(我不确定您需要什么信息)。

admin 更改状态以发布 2023年5月21日
0
0 Comments

虽然Martijin的答案可能是最好的。但对于初学者来说,这里有一种更直观的方法来处理大型csv文件。这允许您一次处理一组行或块。

import pandas as pd
chunksize = 10 ** 8
for chunk in pd.read_csv(filename, chunksize=chunksize):
    process(chunk)

0
0 Comments

你正在将所有行读入列表中,然后处理该列表。 不要这样做

在生成行时处理它们。如果需要先过滤数据,请使用生成器函数:

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() 中也是同样的处理:

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 使函数成为生成器函数,这意味着在您开始循环遍历之前它不会执行任何操作。

0