使用 HDF5 或 Pickle 进行内存优化和 RAM 扩展

Memory optimization and RAM extend with HDF5 or Pickle

我加载了一个非常大的数据文件,它比我的 RAM 还大。我尝试同时使用 Pickle 和 HDF5 来做到这一点,但数据已加载到内存中。 有没有一种方法可以访问数据而不将它们加载到内存中,而是直接在磁盘上访问它们?

from memory_profiler import profile
import numpy as np
import pandas as pd
import cPickle
import gc
import time

basepath = '/Users/toto/Desktop/'

@profile
def test_write():
    dim = 10000000
    df = pd.DataFrame({'test':range(dim)}, index=range(dim))
    for i in range(30):
        df[str(i)]=df['test'] * np.random.normal(0,1)

    print 'df created'
    cPickle.dump(df, open(basepath + 'df_pickle', 'wb'))
    gc.collect()
    store = pd.HDFStore(basepath + 'df_HDFpd')
    store['df'] = df
    store.close()
    gc.collect()
    del df
    gc.collect()

@profile
def test_read(method):
    print method
    if method == 'pickle':
        df = cPickle.load(open(basepath + 'df_pickle', 'rb'))
    if method == 'HDF':
        store = pd.HDFStore(basepath + 'df_HDFpd')
        df = store['df']
    print df.head(5)

    try:
        store.close()
    except:
        pass


#test_write()

timer = time.time()
test_read('HDF')
print 'Execution time: 'time.time()-timer

test_write() 的结果:

Line #    Mem usage    Increment   Line Contents
================================================
    12     42.5 MiB      0.0 MiB   @profile
    13                             def test_write():
    14     42.5 MiB      0.0 MiB       dim = 10000000
    15    969.4 MiB    926.8 MiB       df = pd.DataFrame({'test':range(dim)}, index=range(dim))
    16   3029.7 MiB   2060.3 MiB       for i in range(30):
    17   3029.7 MiB      0.0 MiB           df[str(i)]=df['test'] * np.random.normal(0,1)
    18                             
    19   3029.7 MiB      0.0 MiB       print 'df created'
    20   3029.7 MiB      0.1 MiB       cPickle.dump(df, open(basepath + 'df_pickle', 'wb'))
    21   2616.7 MiB   -413.0 MiB       gc.collect()
    22   2619.7 MiB      3.0 MiB       store = pd.HDFStore(basepath + 'df_HDFpd')
    23   2695.3 MiB     75.5 MiB       store['df'] = df
    24   2695.4 MiB      0.1 MiB       store.close()
    25   2696.1 MiB      0.7 MiB       gc.collect()
    26   1319.8 MiB  -1376.3 MiB       del df
    27   1319.8 MiB      0.0 MiB       gc.collect()

test_load('HDF') 的结果:

Line #    Mem usage    Increment   Line Contents
================================================
    29     42.5 MiB      0.0 MiB   
    30                             @profile
    31     42.5 MiB      0.0 MiB   def test_read(method):
    32     42.5 MiB      0.0 MiB       print method
    33                                 if method == 'pickle':
    34     42.5 MiB      0.0 MiB           df = cPickle.load(open(basepath + 'df_pickle', 'rb'))
    35     46.7 MiB      4.2 MiB       if method == 'HDF':
    36   2488.7 MiB   2442.0 MiB           store = pd.HDFStore(basepath + 'df_HDFpd')
    37   2489.2 MiB      0.5 MiB           df = store['df']
    38                                 print df.head(5)
    39   2489.2 MiB      0.0 MiB   
    40   2489.2 MiB      0.0 MiB       try:
    41                                     store.close()
    42                                 except:
    43                                     pass

test_load('cPickle') 的结果:

几分钟后过来

如果您使用 h5py,当您索引到 H5File 时,它会为您提供一些不是 NumPy 数组但可以转换为数组的东西。所以你应该把它切片,或者直接以某种方式对其进行操作,这样可以避免一次将整个东西读入内存。

我还没有使用过 HDF,但看起来您可以使用 pandas.read_hdf() 增量读取 HDF,或者使用 start/stop 参数或将其获取到 return一个迭代器。