我正在尝试在pandas中读取一个大的csv文件(aprox.6 GB),我收到以下内存错误:
MemoryError Traceback (most recent call last)
<ipython-input-58-67a72687871b> in <module>()
----> 1 data=pd.read_csv('aphro.csv',sep=';')
C:\Python27\lib\site-packages\pandas\io\parsers.pyc in parser_f(filepath_or_buffer, sep, dialect, compression, doublequote, escapechar, quotechar, quoting, skipinitialspace, lineterminator, header, index_col, names, prefix, skiprows, skipfooter, skip_footer, na_values, na_fvalues, true_values, false_values, delimiter, converters, dtype, usecols, engine, delim_whitespace, as_recarray, na_filter, compact_ints, use_unsigned, low_memory, buffer_lines, warn_bad_lines, error_bad_lines, keep_default_na, thousands, comment, decimal, parse_dates, keep_date_col, dayfirst, date_parser, memory_map, nrows, iterator, chunksize, verbose, encoding, squeeze, mangle_dupe_cols, tupleize_cols, infer_datetime_format)
450 infer_datetime_format=infer_datetime_format)
451
--> 452 return _read(filepath_or_buffer, kwds)
453
454 parser_f.__name__ = name
C:\Python27\lib\site-packages\pandas\io\parsers.pyc in _read(filepath_or_buffer, kwds)
242 return parser
243
--> 244 return parser.read()
245
246 _parser_defaults = {
C:\Python27\lib\site-packages\pandas\io\parsers.pyc in read(self, nrows)
693 raise ValueError('skip_footer not supported for iteration')
694
--> 695 ret = self._engine.read(nrows)
696
697 if self.options.get('as_recarray'):
C:\Python27\lib\site-packages\pandas\io\parsers.pyc in read(self, nrows)
1137
1138 try:
-> 1139 data = self._reader.read(nrows)
1140 except StopIteration:
1141 if nrows is None:
C:\Python27\lib\site-packages\pandas\parser.pyd in pandas.parser.TextReader.read (pandas\parser.c:7145)()
C:\Python27\lib\site-packages\pandas\parser.pyd in pandas.parser.TextReader._read_low_memory (pandas\parser.c:7369)()
C:\Python27\lib\site-packages\pandas\parser.pyd in pandas.parser.TextReader._read_rows (pandas\parser.c:8194)()
C:\Python27\lib\site-packages\pandas\parser.pyd in pandas.parser.TextReader._convert_column_data (pandas\parser.c:9402)()
C:\Python27\lib\site-packages\pandas\parser.pyd in pandas.parser.TextReader._convert_tokens (pandas\parser.c:10057)()
C:\Python27\lib\site-packages\pandas\parser.pyd in pandas.parser.TextReader._convert_with_dtype (pandas\parser.c:10361)()
C:\Python27\lib\site-packages\pandas\parser.pyd in pandas.parser._try_int64 (pandas\parser.c:17806)()
MemoryError:
对此有何帮助?
答案 0 :(得分:183)
错误显示机器没有足够的内存来读取整个内存
CSV一次进入DataFrame。假设您不需要整个数据集
记忆一次,避免问题的一种方法是process the CSV in
chunks(通过指定chunksize
参数):
chunksize = 10 ** 6
for chunk in pd.read_csv(filename, chunksize=chunksize):
process(chunk)
chucksize
参数指定每个块的行数。
(当然,最后一个块可能包含少于chunksize
行。)
答案 1 :(得分:51)
Chunking不应该永远是这个问题的第一个停靠点。
<强> 1。由于重复的非数字数据或不需要的列,文件是否很大?
如果是这样,您有时可以通过reading in columns as categories看到大量内存节省,并通过pd.read_csv usecols
参数选择所需的列。
<强> 2。您的工作流程是否需要切片,操作,导出?
如果是这样,您可以使用dask.dataframe进行切片,执行计算并迭代导出。通过dask静默执行分块,它也支持pandas API的子集。
第3。如果所有其他方法都失败了,请通过块逐行读取。
Chunk via pandas或csv library作为最后的手段。
答案 2 :(得分:31)
我继续这样做:
chunks=pd.read_table('aphro.csv',chunksize=1000000,sep=';',\
names=['lat','long','rf','date','slno'],index_col='slno',\
header=None,parse_dates=['date'])
df=pd.DataFrame()
%time df=pd.concat(chunk.groupby(['lat','long',chunk['date'].map(lambda x: x.year)])['rf'].agg(['sum']) for chunk in chunks)
答案 3 :(得分:24)
对于大数据,我建议你使用“dask”库例如:
# Dataframes implement the Pandas API
import dask.dataframe as dd
df = dd.read_csv('s3://.../2018-*-*.csv')
答案 4 :(得分:9)
上述答案已经令人满意。无论如何,如果您需要内存中的所有数据 - 请查看bcolz。它压缩内存中的数据。我有很好的经验。但它遗漏了很多熊猫的特征
编辑:我认为压缩率约为1/10或原始尺寸,当然这取决于数据类型。缺少的重要功能是聚合。
答案 5 :(得分:4)
您可以将数据读取为大块,并将每个大块另存为泡菜。
import pandas as pd
import pickle
in_path = "" #Path where the large file is
out_path = "" #Path to save the pickle files to
chunk_size = 400000 #size of chunks relies on your available memory
separator = "~"
reader = pd.read_csv(in_path,sep=separator,chunksize=chunk_size,
low_memory=False)
i=1
for chunk in reader:
out_file = out_path + "/data_{}.pkl".format(i)
with open(out_file, "wb") as f:
pickle.dump(chunk,f,pickle.HIGHEST_PROTOCOL)
i+=1
在下一步中,读取泡菜并将每个泡菜附加到所需的数据框中。
import glob
pickle_path = "" #Same Path as out_path i.e. where the pickle files are
data_p_files=[]
for name in glob.glob(pickle_path + "/data_*.pkl"):
data_p_files.append(name)
df = pd.DataFrame([])
for i in range(len(data_p_files)):
df = df.append(pd.read_pickle(data_p_files[i]),ignore_index=True)
答案 6 :(得分:4)
解决方案1:
解决方案2:
TextFileReader = pd.read_csv(path, chunksize=1000) # the number of rows per chunk
dfList = []
for df in TextFileReader:
dfList.append(df)
df = pd.concat(dfList,sort=False)
答案 7 :(得分:4)
我想根据已经提供的大多数潜在解决方案做出更全面的回答。我还想指出一种可能有助于阅读过程的潜在帮助。
选项1:dtypes
“ dtypes”是一个非常强大的参数,可用于减少read
方法的内存压力。请参见this和this答案。熊猫默认情况下会尝试推断数据的dtypes。
参考数据结构,存储的每个数据都会进行一次内存分配。在基本级别上,请参考以下值(下表说明了C编程语言的值):
The maximum value of UNSIGNED CHAR = 255
The minimum value of SHORT INT = -32768
The maximum value of SHORT INT = 32767
The minimum value of INT = -2147483648
The maximum value of INT = 2147483647
The minimum value of CHAR = -128
The maximum value of CHAR = 127
The minimum value of LONG = -9223372036854775808
The maximum value of LONG = 9223372036854775807
请参阅this页,以查看NumPy和C类型之间的匹配。
假设您有一个数字的整数数组。您可以在理论上和实践上都进行分配,比如说16位整数类型的数组,但是您将分配比实际存储该数组更多的内存。为防止这种情况,您可以在dtype
上设置read_csv
选项。您不希望将数组项存储为长整数,实际上可以在其中将其与8位整数(np.int8
或np.uint8
)配合使用。
观察以下dtype映射。
来源:https://pbpython.com/pandas_dtypes.html
您可以将dtype
参数作为read
上的dict传递给pandas方法的参数,例如{column:type}。
import numpy as np
import pandas as pd
df_dtype = {
"column_1": int,
"column_2": str,
"column_3": np.int16,
"column_4": np.uint8,
...
"column_n": np.float32
}
df = pd.read_csv('path/to/file', dtype=df_dtype)
选项2:大块阅读
分块读取数据使您可以访问内存中的部分数据,并且可以对数据进行预处理,并保留处理后的数据而不是原始数据。如果将此选项与第一个 dtypes 结合使用,那就更好了。
我想指出该过程的“熊猫食谱”部分,您可以在其中找到here。注意那两个部分;
选项3:快速
Dask是在Dask's website中定义为的框架:
Dask为分析提供了高级并行性,可为您喜欢的工具提供大规模的性能
它的诞生是为了覆盖熊猫无法触及的必要部分。 Dask是一个功能强大的框架,通过以分布式方式处理它,可以使您访问更多数据。
您可以使用dask整体预处理数据,Dask负责分块部分,因此与熊猫不同,您可以定义处理步骤并让Dask完成工作。在由compute
和/或persist
明确推送计算之前,Dask不会应用这些计算(有关差异,请参见答案here)。
其他帮助(想法)
答案 8 :(得分:2)
您可以尝试使用与pandas具有相同语法的sframe,但允许您操作大于RAM的文件。
答案 9 :(得分:2)
函数read_csv和read_table几乎相同。但是,当您在程序中使用函数read_table时,必须指定分隔符“,”。
def get_from_action_data(fname, chunk_size=100000):
reader = pd.read_csv(fname, header=0, iterator=True)
chunks = []
loop = True
while loop:
try:
chunk = reader.get_chunk(chunk_size)[["user_id", "type"]]
chunks.append(chunk)
except StopIteration:
loop = False
print("Iteration is stopped")
df_ac = pd.concat(chunks, ignore_index=True)
答案 10 :(得分:1)
如果你使用pandas将大文件读入chunk然后逐行产生,这就是我所做的
import pandas as pd
def chunck_generator(filename, header=False,chunk_size = 10 ** 5):
for chunk in pd.read_csv(filename,delimiter=',', iterator=True, chunksize=chunk_size, parse_dates=[1] ):
yield (chunk)
def _generator( filename, header=False,chunk_size = 10 ** 5):
chunk = chunck_generator(filename, header=False,chunk_size = 10 ** 5)
for row in chunk:
yield row
if __name__ == "__main__":
filename = r'file.csv'
generator = generator(filename=filename)
while True:
print(next(generator))
答案 11 :(得分:1)
这里是一个例子:
chunkTemp = []
queryTemp = []
query = pd.DataFrame()
for chunk in pd.read_csv(file, header=0, chunksize=<your_chunksize>, iterator=True, low_memory=False):
#REPLACING BLANK SPACES AT COLUMNS' NAMES FOR SQL OPTIMIZATION
chunk = chunk.rename(columns = {c: c.replace(' ', '') for c in chunk.columns})
#YOU CAN EITHER:
#1)BUFFER THE CHUNKS IN ORDER TO LOAD YOUR WHOLE DATASET
chunkTemp.append(chunk)
#2)DO YOUR PROCESSING OVER A CHUNK AND STORE THE RESULT OF IT
query = chunk[chunk[<column_name>].str.startswith(<some_pattern>)]
#BUFFERING PROCESSED DATA
queryTemp.append(query)
#! NEVER DO pd.concat OR pd.DataFrame() INSIDE A LOOP
print("Database: CONCATENATING CHUNKS INTO A SINGLE DATAFRAME")
chunk = pd.concat(chunkTemp)
print("Database: LOADED")
#CONCATENATING PROCESSED DATA
query = pd.concat(queryTemp)
print(query)
答案 12 :(得分:1)
在使用chunksize选项之前,如果要确定要在@unutbu提到的chunking for循环中编写的过程函数,可以简单地使用nrows选项。
small_df = pd.read_csv(filename, nrows=100)
一旦确定过程块已准备就绪,就可以将其放入整个数据帧的分块for循环中。
答案 13 :(得分:0)
除了上述答案外,对于想要处理CSV然后导出到csv,镶木地板或SQL的用户,d6tstack是另一个不错的选择。您可以加载多个文件,它可以处理数据模式更改(添加/删除的列)。分块核心支持已内置。
def apply(dfg):
# do stuff
return dfg
c = d6tstack.combine_csv.CombinerCSV([bigfile.csv], apply_after_read=apply, sep=',', chunksize=1e6)
# or
c = d6tstack.combine_csv.CombinerCSV(glob.glob('*.csv'), apply_after_read=apply, chunksize=1e6)
# output to various formats, automatically chunked to reduce memory consumption
c.to_csv_combine(filename='out.csv')
c.to_parquet_combine(filename='out.pq')
c.to_psql_combine('postgresql+psycopg2://usr:pwd@localhost/db', 'tablename') # fast for postgres
c.to_mysql_combine('mysql+mysqlconnector://usr:pwd@localhost/db', 'tablename') # fast for mysql
c.to_sql_combine('postgresql+psycopg2://usr:pwd@localhost/db', 'tablename') # slow but flexible
答案 14 :(得分:0)
万一有人还在寻找类似的东西,我发现这个名为modin的新库可以提供帮助。它使用可以帮助读取的分布式计算。这是一个不错的article,将其功能与熊猫进行了比较。它基本上使用了与熊猫相同的功能。
import modin.pandas as pd
pd.read_csv(CSV_FILE_NAME)
答案 15 :(得分:0)
csv
数据条目的 millions
文件并且想要加载完整数据集,您应该使用 dask_cudf
,import dask_cudf as dc
df = dc.read_csv("large_data.csv")