关于python:pandas中的大型持久性DataFrame

Large, persistent DataFrame in pandas

我正在探索作为一个长期的SAS用户切换到python和pandas。

然而,在今天运行一些测试时,我惊讶地发现当尝试pandas.read_csv()一个128MB的csv文件时,python内存不足。它有大约200000行和200列,其中大部分是数字数据。

使用SAS,我可以将一个csv文件导入到一个SAS数据集中,它可以和我的硬盘一样大。

pandas中有类似的东西吗?

我经常处理大文件,无法访问分布式计算网络。


原则上,它不应该耗尽内存,但是由于一些复杂的python内部问题(这是模糊的,但很长一段时间以来人们都知道它:http://github.com/pydata/pandas/issues/407),目前read_csv在大型文件上存在内存问题。

目前还没有一个完美的解决方案(这里有一个冗长的解决方案:您可以将文件逐行转录到一个预先分配的numpy数组或内存映射文件——np.mmap),但这是我在不久的将来要处理的一个解决方案。另一种解决方案是读取较小的文件(使用iterator=True, chunksize=1000),然后连接到pd.concat。当你把整个文本文件放在一个大的垃圾桶里,问题就出现了。


韦斯当然是对的!我只是想提供一个更完整的示例代码。我对一个129 MB的文件也有同样的问题,解决方法是:

1
2
3
4
from pandas import *

tp = read_csv('large_dataset.csv', iterator=True, chunksize=1000)  # gives TextFileReader, which is iterable with chunks of 1000 rows.
df = concat(tp, ignore_index=True)  # df is DataFrame. If errors, do `list(tp)` instead of `tp`


这是一个较旧的线程,但我只是想将我的解决方案转储到这里。我最初尝试过chunksize参数(即使有非常小的值,比如10000),但没有多大帮助;内存大小仍然存在技术问题(我的csv大约是7.5GB)。

现在,我只需使用for循环方法读取csv文件的块,然后逐步将它们添加到sqlite数据库中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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()


下面是我的工作流程。

1
2
3
4
5
6
7
8
9
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')

根据文件大小,最好优化chunksize。

1
2
3
4
 for chunk in chunks:
        chunk.to_sql(name='Table', if_exists='append', con=con)
        count += 1
        print(count)

在数据库中有了所有数据之后,您可以从数据库中查询出所需的数据。


如果您想加载巨大的csv文件,dask可能是一个不错的选择。它模仿熊猫API,所以感觉与熊猫非常相似

链接到Github上的DASK


您可以使用Pytable而不是Pandas DF。它是为大型数据集设计的,文件格式为HDF5。所以处理时间比较快。