[英]Reading a huge .csv file
我目前正在尝试从 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 内存,运行 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()
做同样的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
使函数成为生成器函数,这意味着在您开始循环之前它不会做任何工作。
尽管 Martijin 的回答是最好的。 这里有一种更直观的方法来处理初学者的大型 csv 文件。 这允许您一次处理多组行或块。
import pandas as pd
chunksize = 10 ** 8
for chunk in pd.read_csv(filename, chunksize=chunksize):
process(chunk)
我做了大量的振动分析并查看大型数据集(数千万个点)。 我的测试表明pandas.read_csv()函数比 numpy.genfromtxt() 快20倍。 并且 genfromtxt() 函数比 numpy.loadtxt() 快 3 倍。 看来你需要大数据集的熊猫。
我在讨论MATLAB 与 Python 进行振动分析的博客上发布了我在此测试中使用的代码和数据集。
对我有用的是并且超快的是
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
对于遇到这个问题的人。 利用大熊猫与“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)
这是 Python3 的另一个解决方案:
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
是一个生成器函数。
如果使用的是熊猫,并有大量的RAM(足以读取整个文件到内存)尝试使用pd.read_csv
与low_memory=False
,例如:
import pandas as pd
data = pd.read_csv('file.csv', low_memory=False)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.