阅读一个巨大的.csv文件

2cmtqfgy  于 2023-11-14  发布在  其他
关注(0)|答案(8)|浏览(156)

我目前正在尝试从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文件中一起列出,所以当我跳过它们时,我离开循环以节省保存时间。
我的问题是:
1.我怎样才能让它与更大的文件一起工作?
1.有什么方法可以让它更快吗?
我的电脑有8GB RAM,运行64位Windows 7,处理器是3. 40 GHz(不确定你需要什么信息)。

yx2lnoni

yx2lnoni1#

您正在将所有行阅读到一个列表中,然后处理该列表。不要这样做
在生成行时处理它们。如果需要先过滤数据,请使用生成器函数:

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使函数成为生成器函数,这意味着它不会做任何工作,直到你开始循环它。

6l7fqoea

6l7fqoea2#

虽然Martijin的答案是最好的,但这里有一个更直观的方法来处理初学者的大csv文件。这允许你一次处理多组行或块。

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

字符串

7xzttuei

7xzttuei3#

我做了大量的振动分析,并查看了大型数据集(数千万和数亿个点)。我的测试显示pandas.read_csv()函数比numpy.genfromtxt()快 20 倍。genfromtxt()函数比numpy.loadtxt()快3倍。看起来你需要 * pandas来处理大型数据集。
我在一个讨论MATLAB vs Python for vibration analysis的博客上发布了我在这个测试中使用的代码和数据集。

tzdcorbm

tzdcorbm4#

如果有人问这个问题,使用pandas和'chunksize'和'usecols'可以帮助我比其他建议的选项更快地读取一个巨大的zip文件。

import pandas as pd

sample_cols_to_keep =['col_1', 'col_2', 'col_3', 'col_4','col_5']

# First setup dataframe iterator, ‘usecols’ parameter filters the columns, and 'chunksize' sets the number of rows per chunk in the csv. (you can change these parameters as you wish)
df_iter = pd.read_csv('../data/huge_csv_file.csv.gz', compression='gzip', chunksize=20000, usecols=sample_cols_to_keep) 

# this list will store the filtered dataframes for later concatenation 
df_lst = [] 

# Iterate over the file based on the criteria and append to the list
for df_ in df_iter: 
        tmp_df = (df_.rename(columns={col: col.lower() for col in df_.columns}) # filter eg. rows where 'col_1' value grater than one
                                  .pipe(lambda x:  x[x.col_1 > 0] ))
        df_lst += [tmp_df.copy()] 

# And finally combine filtered df_lst into the final lareger output say 'df_final' dataframe 
df_final = pd.concat(df_lst)

字符串

sg3maiej

sg3maiej5#

对我有用的是,

import pandas as pd
import dask.dataframe as dd
import time
t=time.clock()
df_train = dd.read_csv('../data/train.csv', usecols=[col1, col2])
df_train=df_train.compute()
print("load train: " , time.clock()-t)

字符串
另一个可行的解决方案是:

import pandas as pd 
from tqdm import tqdm

PATH = '../data/train.csv'
chunksize = 500000 
traintypes = {
'col1':'category',
'col2':'str'}

cols = list(traintypes.keys())

df_list = [] # list to hold the batch dataframe

for df_chunk in tqdm(pd.read_csv(PATH, usecols=cols, dtype=traintypes, chunksize=chunksize)):
    # Can process each chunk of dataframe here
    # clean_data(), feature_engineer(),fit()

    # Alternatively, append the chunk to list and merge all
    df_list.append(df_chunk) 

# Merge all dataframes into one dataframe
X = pd.concat(df_list)

# Delete the dataframe list to release memory
del df_list
del df_chunk

g52tjvyc

g52tjvyc6#

下面是Python 3另一个解决方案:

import csv
with open(filename, "r") as csvfile:
    datareader = csv.reader(csvfile)
    count = 0
    for row in datareader:
        if row[3] in ("column header", criterion):
            doSomething(row)
            count += 1
        elif count > 2:
            break

字符串
这里datareader是生成器函数。

kx7yvsdv

kx7yvsdv7#

如果你使用pandas并且有足够的RAM(足以将整个文件读入内存),请尝试将pd.read_csvlow_memory=False一起使用,例如:

import pandas as pd
data = pd.read_csv('file.csv', low_memory=False)

字符串

goucqfw6

goucqfw68#

所有这些答案都在最后使用了一个pd.concat(),它假设过滤后的嵌套框架适合内存,但是如果嵌套框架真的很大,你可以采用这种方法来读取块并在你去的时候附加到文件中。你可以将多处理融入这种方法,并在文件写入上放置一个Lock:

input_filename= 'input.csv'
out_filename = 'output.csv'

chunks= pd.read_csv(input_filename, chunksize=80000)
for i,chunk in enumerate(chunks):
    chunk = chunk[chunk.Availability != "Out of Stock"]
    chunk.to_csv(out_filename, header=(i==0), mode='a', index=False)

字符串

相关问题