pandas 中的大而持久的 DataFrame
Posted
技术标签:
【中文标题】pandas 中的大而持久的 DataFrame【英文标题】:Large, persistent DataFrame in pandas 【发布时间】:2012-07-22 06:52:13 【问题描述】:作为长期 SAS 用户,我正在探索切换到 python 和 pandas。
但是,今天在运行一些测试时,我很惊讶 python 在尝试 pandas.read_csv()
一个 128mb 的 csv 文件时内存不足。它有大约 200,000 行和 200 列主要是数字数据。
使用 SAS,我可以将 csv 文件导入 SAS 数据集,它可以和我的硬盘一样大。
pandas
中有类似的东西吗?
我经常处理大文件,但无法访问分布式计算网络。
【问题讨论】:
我对 pandas 不熟悉,但您可能想通过遍历文件来查看。 pandas.pydata.org/pandas-docs/stable/… 【参考方案1】:原则上它不应该用完内存,但是由于一些复杂的Python内部问题导致read_csv
在大文件上存在内存问题(这个是模糊的,但它已经知道很长时间了:http://github.com/pydata/pandas/issues/407 )。
目前还没有完美的解决方案(这是一个乏味的解决方案:您可以将文件逐行转录为预先分配的 NumPy 数组或内存映射文件--np.mmap
),但它是一个我将在不久的将来工作。另一种解决方案是读取较小的文件(使用iterator=True, chunksize=1000
),然后与pd.concat
连接。当您一口气将整个文本文件拉入内存时,问题就出现了。
【讨论】:
假设我可以读取文件并将它们全部连接到一个 DataFrame 中。 DataFrame 是否必须驻留在内存中?有了 SAS,只要我有硬盘空间,我就可以处理任何大小的数据集。 DataFrames也一样吗?我得到的印象是它们受到 RAM 而不是硬盘空间的限制。抱歉这个菜鸟问题,感谢您的帮助。我很喜欢你的书。 对,你受到 RAM 的限制。 SAS 确实对“核外”大数据处理有更好的支持。 @WesMcKinney 这些变通办法应该不再需要了,因为您在 0.10 中使用了新的 csv 加载器,对吧?【参考方案2】:韦斯当然是对的!我只是想提供一些更完整的示例代码。我对一个 129 Mb 的文件也有同样的问题,解决方法是:
import pandas as pd
tp = pd.read_csv('large_dataset.csv', iterator=True, chunksize=1000) # gives TextFileReader, which is iterable with chunks of 1000 rows.
df = pd.concat(tp, ignore_index=True) # df is DataFrame. If errors, do `list(tp)` instead of `tp`
【讨论】:
我想你可以做df = concate(tp, ignore_index=True)
?
@smci 使用重复 x4 (550 Mb) 或 x8 (1.1Gb) 的相同数据快速尝试。有趣的是,无论有没有 [x for x in tp],x4 都能正常运行,而 x8 在 MemoryError 中崩溃。
我在使用它时收到此错误:AssertionError: first argument must be a list-like of pandas objects, you passed an object of type "TextFileReader"
。知道这里发生了什么吗?
这个bug将在0.14(即将发布)中修复,github.com/pydata/pandas/pull/6941; pd.concat(list(tp), ignore_index=True)
如果值是字符串或分类怎么办 - 我收到错误:分类 concat 中的不兼容类别【参考方案3】:
这是一个较旧的线程,但我只是想在这里转储我的解决方法。我最初尝试了chunksize
参数(即使是非常小的值,例如 10000),但它并没有太大帮助;内存大小仍然存在技术问题(我的 CSV 约为 7.5 Gb)。
现在,我只是以 for 循环的方式读取 CSV 文件的块,然后逐步将它们添加到 SQLite 数据库中:
import pandas as pd
import sqlite3
from pandas.io import sql
import subprocess
# In and output file paths
in_csv = '../data/my_large.csv'
out_sqlite = '../data/my.sqlite'
table_name = 'my_table' # name for the SQLite database table
chunksize = 100000 # number of lines to process at each iteration
# columns that should be read from the CSV file
columns = ['molecule_id','charge','db','drugsnow','hba','hbd','loc','nrb','smiles']
# Get number of lines in the CSV file
nlines = subprocess.check_output('wc -l %s' % in_csv, shell=True)
nlines = int(nlines.split()[0])
# connect to database
cnx = sqlite3.connect(out_sqlite)
# Iteratively read CSV and dump lines into the SQLite table
for i in range(0, nlines, chunksize):
df = pd.read_csv(in_csv,
header=None, # no header, define column header manually later
nrows=chunksize, # number of rows to read at each iteration
skiprows=i) # skip rows that were already read
# columns to read
df.columns = columns
sql.to_sql(df,
name=table_name,
con=cnx,
index=False, # don't use CSV file index
index_label='molecule_id', # use a unique column from DataFrame as index
if_exists='append')
cnx.close()
【讨论】:
查看分块阅读功能的真实用例非常有用。谢谢。 对这个老话题说一句:pandas.read_csv
如果您只提供iterator=True
和chunksize=chunksize
,则直接返回(至少在我当前使用的版本上)一个迭代器。因此,您只需对 pd.read_csv
调用执行 for
循环,而不是每次都重新实例化它。但是,这仅花费了调用开销,可能不会产生重大影响。
嗨,乔尔。感谢您的注意!如果我没记错的话,iterator=True
和 chunksize
参数当时已经存在。也许旧版本中存在导致内存爆炸的错误 - 下次我在 Pandas 中读取大型 DataFrame 时我会再试一次(我现在主要使用 Blaze 执行此类任务)【参考方案4】:
您可以使用 Pytable 而不是 pandas df。 它专为大型数据集而设计,文件格式为 hdf5。 所以处理时间比较快。
【讨论】:
【参考方案5】:以下是我的工作流程。
import sqlalchemy as sa
import pandas as pd
import psycopg2
count = 0
con = sa.create_engine('postgresql://postgres:pwd@localhost:00001/r')
#con = sa.create_engine('sqlite:///XXXXX.db') SQLite
chunks = pd.read_csv('..file', chunksize=10000, encoding="ISO-8859-1",
sep=',', error_bad_lines=False, index_col=False, dtype='unicode')
根据您的文件大小,您最好优化块大小。
for chunk in chunks:
chunk.to_sql(name='Table', if_exists='append', con=con)
count += 1
print(count)
在数据库中获得所有数据后,您可以从数据库中查询出您需要的那些。
【讨论】:
【参考方案6】:如果您想加载巨大的 csv 文件,dask 可能是一个不错的选择。它模仿了pandas api,所以感觉很像pandas
link to dask on github
【讨论】:
谢谢,自从我发布这篇文章以来,我一直在使用 dask 和 parquet 格式。以上是关于pandas 中的大而持久的 DataFrame的主要内容,如果未能解决你的问题,请参考以下文章
Pandas学习笔记,如何删除DataFrame中的一列(行)
pandas 中的大数据,基于另一张表匹配和回填/转发一张表