如何阅读带有pandas的6 GB csv文件

Raj*_*wat 166 python memory csv chunks pandas

我试图在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: 
Run Code Online (Sandbox Code Playgroud)

对此有何帮助??

unu*_*tbu 216

该错误表明机器没有足够的内存来将整个CSV一次读入DataFrame.假设您一次不需要内存中的整个数据集,避免此问题的一种方法是以块的形式处理CSV(通过指定chunksize参数):

chunksize = 10 ** 6
for chunk in pd.read_csv(filename, chunksize=chunksize):
    process(chunk)
Run Code Online (Sandbox Code Playgroud)

chucksize参数指定每个块的行数.(当然,最后一个块可能包含少于chunksize行.)

  • @altabq:这里的问题是我们没有足够的内存来构建一个包含所有数据的DataFrame.上面的解决方案试图通过一次减少一个块(例如通过聚合或仅提取所需信息)来处理这种情况 - 从而节省了内存.无论你做什么,都不要在循环中调用`DF.append(chunk)`.那将使用'O(N ^ 2)`复制操作.最好将聚合数据*附加到列表*,然后使用*一次调用*从*列表构建DataFrame到`pd.DataFrame`或`pd.concat`(取决于聚合数据的类型). (17认同)
  • 你通常需要2倍的最终内存来读取某些内容(来自csv,尽管其他格式的内存要求更低).仅供参考,尝试同时做几乎任何事情都是如此.更好的块(它具有恒定的内存使用). (13认同)
  • @altabq:在循环中调用`DF.append(chunk)`需要`O(N ^ 2)`复制操作,其中`N`是块的大小,因为每次调用`DF.append`都会返回一个新的DataFrame .在循环外部调用`pd.DataFrame`或`pd.concat`****会将复制量减少到'O(N)`. (10认同)
  • @Pyderman:是的; 在循环之后调用`pd.concat([list_of_dfs])`***比在循环中多次调用`pd.concat`或`df.append`要快得多.当然,你需要相当多的内存才能将整个6GB的csv作为一个DataFrame. (6认同)
  • @Pyderman:是的,`chunksize`参数指的是每个块的行数.当然,最后一个块可能包含少于`chunksize`行. (5认同)
  • @Pyderman:您可能想测试使用迭代器所需的时间:`for pdf中的df.read_csv(...,chunksize = 10**5):传递`而不进行任何处理.如果这很快成功,那么你知道它是循环中的其他东西需要花费很多时间.(例如,从不在循环中调用`result_df = result_df.append(df)`,因为[需要二次复制](http://stackoverflow.com/a/36489724/190597).) (2认同)
  • 从Jeff的评论中可以得出以下结论:就我而言,我需要的内存大约是3倍以上:我正在64位OS上加载19gb的csv,并具有64gb的ram,其中绝大多数是免费的。使用read_csv,我很快耗尽了内存,并且开始使用我的M2 SSD磁盘交换文件。大约10到15分钟后,我的屏幕变黑,必须重新启动。我绝对不会过热。我认为内存开销是由于panda的列类型检测引起的,并且我的文件有〜100 +列。 (2认同)

jpp*_*jpp 63

分块不应该总是这个问题的第一个停靠点.

1.由于重复的非数字数据或不需要的列,文件是否很大?

如果是这样,您有时可以通过读取列作为类别并通过pd.read_csv usecols参数选择所需列来节省大量内存.

2.您的工作流程是否需要切片,操作,导出?

如果是这样,您可以使用dask.dataframe进行切片,执行计算并迭代导出.通过dask静默执行分块,它也支持pandas API的子集.

3.如果所有其他方法都失败了,请通过块逐行读取.

通过大熊猫或通过CSV库作为最后的手段.


Raj*_*wat 33

我继续这样做:

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)
Run Code Online (Sandbox Code Playgroud)

  • 你有没有理由从`read_csv`切换到`read_table`? (16认同)

Sim*_*tsi 27

对于大数据,我建议您使用库"dask",
例如:

# Dataframes implement the Pandas API
import dask.dataframe as dd
df = dd.read_csv('s3://.../2018-*-*.csv')
Run Code Online (Sandbox Code Playgroud)

  • 任何超过熊猫的好处,可能会增加一些指针 (8认同)
  • 欢迎使用,它可以作为Numpy,Pandas和Scikit-Learn的包装。 (3认同)
  • 我没有使用Dask很长时间了,但是在我的用例中,主要的优点是Dask可以在多台机器上并行运行,也可以将数据作为切片放入内存中。 (2认同)
  • 谢谢!是熊猫的替代品,还是作为熊猫工作在熊猫之上 (2认同)
  • 我尝试过使用 Dask 来解决几个问题,但总是抛出错误。即使有块它也会引发内存错误。请参阅/sf/ask/4190590071/?noredirect=1#comment105870267_59865572 (2认同)

Pla*_*Tag 10

上面的答案已经令人满意了.无论如何,如果你需要内存中的所有数据 - 看看bcolz.它压缩内存中的数据.我有很好的经验.但它缺少了很多熊猫的功能

编辑:我认为压缩率约为1/10或原始尺寸,当然这取决于数据类型.缺少的重要功能是聚合.

  • 请通过告诉我们a)你得到的压缩率和b)它丢失的熊猫的主要特征来改进这个答案?可以处理NAs吗?字符串?categoricals?日期? (2认同)
  • 好的,它无法处理NAs,字符串或日期.我怀疑它也可以处理漂浮物. (2认同)

nul*_*ull 7

我想根据已经提供的大多数潜在解决方案做出更全面的答案。我还想指出另一种可能有助于阅读过程的潜在帮助。

选项 1:dtypes

“dtypes”是一个非常强大的参数,您可以使用它来减少read方法的内存压力。看到这个这个答案。默认情况下,熊猫会尝试推断数据的 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
Run Code Online (Sandbox Code Playgroud)

请参阅页面以查看 NumPy 和 C 类型之间的匹配。

假设您有一个由数字组成的整数数组。您可以在理论上和实际上分配,例如 16 位整数类型的数组,但是您将分配比实际需要存储该数组更多的内存。为了防止这种情况,您可以dtype在 上设置选项read_csv。您不想将数组项存储为长整数,而实际上您可以用 8 位整数(np.int8np.uint8)来拟合它们。

观察以下 dtype 映射。

来源:https : //pbpython.com/pandas_dtypes.html

您可以将dtype参数作为 Pandas 方法的参数作为 dict传递给read{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)
Run Code Online (Sandbox Code Playgroud)

选项 2:按块读取

以块的形式读取数据允许您访问内存中的部分数据,并且您可以对数据应用预处理并保留处理后的数据而不是原始数据。如果将此选项与第一个选项dtypes结合使用会更好。

我想指出该过程的熊猫食谱部分,您可以在此处找到它。注意那里的那两个部分;

选项 3:Dask

Dask 是一个框架,在Dask 的网站上定义为:

Dask 为分析提供高级并行性,为您喜爱的工具提供大规模性能

它的诞生是为了覆盖熊猫无法到达的必要部分。Dask 是一个强大的框架,它允许您通过以分布式方式处理数据来访问更多数据。

您可以使用 dask 对整个数据进行预处理,Dask 负责分块部分,因此与 Pandas 不同,您只需定义处理步骤并让 Dask 完成工作。Dask 在被compute和/或明确推送之前不会应用计算persist(有关差异,请参阅此处的答案)。

其他帮助(想法)

  • 为数据设计的 ETL 流程。仅保留原始数据中需要的内容。
    • 首先,使用 Dask 或 PySpark 等框架将 ETL 应用于整个数据,并将处理后的数据导出。
    • 然后看处理后的数据是否可以整体放入内存中。
  • 考虑增加内存。
  • 考虑在云平台上处理这些数据。


sam*_*sam 7

在使用 chunksize 选项之前,如果您想确定要在分块 for 循环内编写的处理函数(如 @unutbu 提到的),您可以简单地使用 nrows 选项。

small_df = pd.read_csv(filename, nrows=100)
Run Code Online (Sandbox Code Playgroud)

一旦确定流程块已准备好,您就可以将其放入整个数据帧的分块 for 循环中。


小智 6

read_csv 和 read_table 函数几乎相同。但在程序中使用 read_table 函数时,必须指定分隔符 \xe2\x80\x9c\xef\xbc\x8c\xe2\x80\x9d。

\n\n
def get_from_action_data(fname, chunk_size=100000):\n    reader = pd.read_csv(fname, header=0, iterator=True)\n    chunks = []\n    loop = True\n    while loop:\n        try:\n            chunk = reader.get_chunk(chunk_size)[["user_id", "type"]]\n            chunks.append(chunk)\n        except StopIteration:\n            loop = False\n            print("Iteration is stopped")\n\n    df_ac = pd.concat(chunks, ignore_index=True)\n
Run Code Online (Sandbox Code Playgroud)\n


小智 6

您可以将数据读取为大块,并将每个大块另存为泡菜。

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)    


for i, chunk in enumerate(reader):
    out_file = out_path + "/data_{}.pkl".format(i+1)
    with open(out_file, "wb") as f:
        pickle.dump(chunk,f,pickle.HIGHEST_PROTOCOL)
Run Code Online (Sandbox Code Playgroud)

在下一步中,您将读取泡菜并将每个泡菜附加到所需的数据框中。

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)
Run Code Online (Sandbox Code Playgroud)

  • 如果您的最终 `df` 完全适合内存(如暗示的那样)并且包含与您的输入相同数量的数据,那么您肯定根本不需要分块吗? (4认同)

bla*_*eep 5

解决方案一:

使用 pandas 处理大数据

解决方案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)
Run Code Online (Sandbox Code Playgroud)

  • 只是不要执行“dfList.append”,只需单独处理每个块(“df”) (6认同)
  • 这里我们再次将 6 GB 文件完全加载到内存中,是否有任何选项,我们可以处理当前块,然后读取下一个块 (3认同)

归档时间:

查看次数:

181444 次

最近记录:

5 年,9 月 前