【问题标题】:Python particles simulator: out-of-core processingPython粒子模拟器:核外处理
【发布时间】:2014-01-23 07:35:13
【问题描述】:

问题描述

在 python/numpy 中编写蒙特卡洛粒子模拟器(布朗运动和光子发射)。我需要将模拟输出 (>>10GB) 保存到文件中并在第二步中处理数据。与 Windows 和 Linux 的兼容性很重要。

粒子数(n_particles)为 10-100。时间步数 (time_size) 约为 10^9。

模拟有 3 个步骤(以下代码适用于全 RAM 版本):

  1. 模拟(并存储)一个 emission 速率数组(包含许多几乎为 0 的元素):

    • 形状(n_particles x time_size),float32,大小80GB
  2. 计算 counts 数组,(来自 Poisson 过程的随机值,具有先前计算的速率):

    • 形状 (n_particles x time_size),uint8,大小 20GB

      counts = np.random.poisson(lam=emission).astype(np.uint8)
      
  3. 查找计数的时间戳(或索引)。计数几乎总是 0,因此时间戳数组将适合 RAM。

    # Loop across the particles
    timestamps = [np.nonzero(c) for c in counts]
    

我执行第 1 步一次,然后重复第 2-3 步多次(约 100 次)。将来我可能需要在计算counts之前预处理emission(应用cumsum或其他函数)。

问题

我有一个有效的内存实现,我正在尝试了解实现可以扩展到(更多)更长模拟的核外版本的最佳方法。

我希望它存在

我需要将数组保存到文件中,并且我想使用单个文件进行模拟。我还需要一种“简单”的方式来存储和调用模拟参数(标量)字典。

理想情况下,我想要一个文件支持的 numpy 数组,我可以预先分配和填充块。然后,我希望 numpy 数组方法(maxcumsum、...)透明地工作,只需要一个 chunksize 关键字来指定每次迭代时要加载多少数组。

更好的是,我想要一个不在缓存和 RAM 之间而是在 RAM 和硬盘驱动器之间运行的 Numexpr

有哪些实用的选项

作为首选 我开始尝试使用 pyTables,但我对它的复杂性和抽象性(与 numpy 如此不同)并不满意。此外,我目前的解决方案(见下文)是丑陋的,效率不高。

所以我寻求答案的选择是

  1. 实现一个具有所需功能的 numpy 数组(如何实现?)

  2. 以更智能的方式使用 pytable(不同的数据结构/方法)

  3. 使用另一个库:h5py、blaze、pandas...(目前我还没有尝试过)。

暂定解决方案(pyTables)

我将模拟参数保存在'/parameters'组中:每个参数都转换为一个numpy数组标量。详细的解决方案,但它有效。

我将 emission 保存为可扩展数组 (EArray),因为我以块的形式生成数据,并且需要附加每个新块(尽管我知道最终大小)。保存counts 问题更大。如果将其保存为 pytable 数组,则很难执行“counts >= 2”之类的查询。因此,我将计数保存为多个表(每个粒子一个)[UGLY],并使用.get_where_list('counts >= 2') 进行查询。我不确定这是否节省空间,并且 生成所有这些表而不是使用单个数组,会显着破坏 HDF5 文件。此外,奇怪的是,创建这些表需要创建自定义 dtype(即使对于标准 numpy dtypes):

    dt = np.dtype([('counts', 'u1')])        
    for ip in xrange(n_particles):
        name = "particle_%d" % ip
        data_file.create_table(
                    group, name, description=dt, chunkshape=chunksize,
                    expectedrows=time_size,
                    title='Binned timetrace of emitted ph (bin = t_step)'
                        ' - particle_%d' % particle)

每个粒子计数“表”都有不同的名称 (name = "particle_%d" % ip),我需要将它们放在 python 列表中以便于迭代。

编辑:这个问题的结果是一个名为PyBroMo的布朗运动模拟器。

【问题讨论】:

  • pandas 为 PyTables 提供了一个不错的接口,请参见此处:pandas.pydata.org/pandas-docs/dev/io.html#hdf5-pytables。如果您不打算一起查询它们,您应该将单独的数据放在单独的 HDF5 文件中。表是一个很好的简单结构,可以执行您所描述的操作,可以附加和压缩。
  • 我明白了。从逻辑上讲,我会将粒子计数存储在一个表中,每个粒子一列(和 10^9 行)。然后我会查询每列的计数> x。那效率低吗?为什么你建议单独的文件?此外,一维表与一维数组中是否存在空间开销(由于索引)?
  • 它非常节省空间。您可以使用压缩。您可以单独查询每一列。如果数据是“单独的”,则单独的文件很有用。例如我经常在不同的过程中附加数据,您只能在单独的文件中执行此操作。 (虽然在多进程上阅读是可以的)。 1 gigarow 和 80GB 一样大,但说它大 20%,这真的重要吗?记住压缩在这里有很大帮助。见pytables.github.io/usersguide/optimization.html
  • 只是一个想法,当您说:“模拟(并存储)一个发射率数组(包含许多 0 或几乎为 0 的元素)”时,是否有必要将其存储为 float32?如果大多数事情是零或几乎为零,那么只存储不为零的索引及其值是否更好,知道其余部分为零? (我猜是稀疏的东西?) - 另一个问题: num_particles 和 n_particles 是一样的吗?我认为第一个只是一个错字,应该到处都是 n_particles?
  • emission 是对粒子轨迹(3D 布朗运动)进行评估的函数的结果。轨迹是“完整阵列”,但在发射计算后被丢弃。大多数时候,排放量很小(但不是 0)。这导致counts 在大多数情况下为 0。我原则上只能存储timestamps,这是counts > 0 的“索引”。但是counts 不适合 ram,因此必须逐块找到索引(这需要一些索引算法)。但是,如果事实证明存储 counts 过于昂贵,这是一种可能的方法。

标签: numpy pandas pytables h5py blaze


【解决方案1】:

Dask.array 可以在 PyTables 或 h5py 等磁盘阵列上执行 maxcumsum 等分块操作。

import h5py
d = h5py.File('myfile.hdf5')['/data']
import dask.array as da
x = da.from_array(d, chunks=(1000, 1000))

X 看起来和感觉上都像一个 numpy 数组,并复制了大部分 API。 x 上的操作将创建一个内存中操作的 DAG,这些操作将根据需要使用来自磁盘的多个内核流来有效地执行

da.exp(x).mean(axis=0).compute()

http://dask.pydata.org/en/latest/

conda install dask
or 
pip install dask

【讨论】:

    【解决方案2】:

    请参阅here,了解如何将参数存储在 HDF5 文件中(它是 pickle,因此您可以按照自己的方式存储它们;它们是 pickle 大小的 64kb 限制)。

    import pandas as pd                                                                                                                                                                                                                                                                                               
    import numpy as np                                                                                                                                                                                                                                                                                                
    
    n_particles = 10                                                                                                                                                                                                                                                                                                  
    chunk_size = 1000                                                                                                                                                                                                                                                                                                 
    
    # 1) create a new emission file, compressing as we go                                                                                                                                                                                                                                                             
    emission = pd.HDFStore('emission.hdf',mode='w',complib='blosc')                                                                                                                                                                                                                                                   
    
    # generate simulated data                                                                                                                                                                                                                                                                                         
    for i in range(10):                                                                                                                                                                                                                                                                                               
    
        df = pd.DataFrame(np.abs(np.random.randn(chunk_size,n_particles)),dtype='float32')                                                                                                                                                                                                                            
    
        # create a globally unique index (time)                                                                                                                                                                                                                                                                       
        # http://stackoverflow.com/questions/16997048/how-does-one-append-large-amounts-of-
    
        data-to-a-pandas-hdfstore-and-get-a-natural/16999397#16999397                                                                                                                                                              
            try:                                                                                                                                                                                                                                                                                                          
                nrows = emission.get_storer('df').nrows                                                                                                                                                                                                                                                                   
            except:                                                                                                                                                                                                                                                                                                       
                nrows = 0                                                                                                                                                                                                                                                                                                 
    
            df.index = pd.Series(df.index) + nrows                                                                                                                                                                                                                                                                        
            emission.append('df',df)                                                                                                                                                                                                                                                                                      
    
        emission.close()                                                                                                                                                                                                                                                                                                  
    
        # 2) create counts                                                                                                                                                                                                                                                                                                
        cs = pd.HDFStore('counts.hdf',mode='w',complib='blosc')                                                                                                                                                                                                                                                           
    
        # this is an iterator, can be any size                                                                                                                                                                                                                                                                            
        for df in pd.read_hdf('emission.hdf','df',chunksize=200):                                                                                                                                                                                                                                                         
    
            counts = pd.DataFrame(np.random.poisson(lam=df).astype(np.uint8))                                                                                                                                                                                                                                             
    
            # set the index as the same                                                                                                                                                                                                                                                                                   
            counts.index = df.index                                                                                                                                                                                                                                                                                       
    
            # store the sum across all particles (as most are zero this will be a 
            # nice sub-selector                                                                                                                                                                                                                       
            # better maybe to have multiple of these sums that divide the particle space                                                                                                                                                                                                                                  
            # you don't have to do this but prob more efficient                                                                                                                                                                                                                                                           
            # you can do this in another file if you want/need                                                                                                                                                                                                                                                               
            counts['particles_0_4'] = counts.iloc[:,0:4].sum(1)                                                                                                                                                                                                                                                           
            counts['particles_5_9'] = counts.iloc[:,5:9].sum(1)                                                                                                                                                                                                                                                           
    
            # make the non_zero column indexable                                                                                                                                                                                                                                                                          
            cs.append('df',counts,data_columns=['particles_0_4','particles_5_9'])                                                                                                                                                                                                                                         
    
        cs.close()                                                                                                                                                                                                                                                                                                        
    
        # 3) find interesting counts                                                                                                                                                                                                                                                                                      
        print pd.read_hdf('counts.hdf','df',where='particles_0_4>0')                                                                                                                                                                                                                                                      
        print pd.read_hdf('counts.hdf','df',where='particles_5_9>0')         
    

    您也可以将每个粒子设为 data_column 并单独选择它们。

    还有一些输出(在这种情况下是非常活跃的发射:)

        0  1  2  3  4  5  6  7  8  9  particles_0_4  particles_5_9
    0   2  2  2  3  2  1  0  2  1  0              9              4
    1   1  0  0  0  1  0  1  0  3  0              1              4
    2   0  2  0  0  2  0  0  1  2  0              2              3
    3   0  0  0  1  1  0  0  2  0  3              1              2
    4   3  1  0  2  1  0  0  1  0  0              6              1
    5   1  0  0  1  0  0  0  3  0  0              2              3
    6   0  0  0  1  1  0  1  0  0  0              1              1
    7   0  2  0  2  0  0  0  0  2  0              4              2
    8   0  0  0  1  3  0  0  0  0  1              1              0
    10  1  0  0  0  0  0  0  0  0  1              1              0
    11  0  0  1  1  0  2  0  1  2  1              2              5
    12  0  2  2  4  0  0  1  1  0  1              8              2
    13  0  2  1  0  0  0  0  1  1  0              3              2
    14  1  0  0  0  0  3  0  0  0  0              1              3
    15  0  0  0  1  1  0  0  0  0  0              1              0
    16  0  0  0  4  3  0  3  0  1  0              4              4
    17  0  2  2  3  0  0  2  2  0  2              7              4
    18  0  1  2  1  0  0  3  2  1  2              4              6
    19  1  1  0  0  0  0  1  2  1  1              2              4
    20  0  0  2  1  2  2  1  0  0  1              3              3
    22  0  1  2  2  0  0  0  0  1  0              5              1
    23  0  2  4  1  0  1  2  0  0  2              7              3
    24  1  1  1  0  1  0  0  1  2  0              3              3
    26  1  3  0  4  1  0  0  0  2  1              8              2
    27  0  1  1  4  0  1  2  0  0  0              6              3
    28  0  1  0  0  0  0  0  0  0  0              1              0
    29  0  2  0  0  1  0  1  0  0  0              2              1
    30  0  1  0  2  1  2  0  2  1  1              3              5
    31  0  0  1  1  1  1  1  0  1  1              2              3
    32  3  0  2  1  0  0  1  0  1  0              6              2
    33  1  3  1  0  4  1  1  0  1  4              5              3
    34  1  1  0  0  0  0  0  3  0  1              2              3
    35  0  1  0  0  1  1  2  0  1  0              1              4
    36  1  0  1  0  1  2  1  2  0  1              2              5
    37  0  0  0  1  0  0  0  0  3  0              1              3
    38  2  5  0  0  0  3  0  1  0  0              7              4
    39  1  0  0  2  1  1  3  0  0  1              3              4
    40  0  1  0  0  1  0  0  4  2  2              1              6
    41  0  3  3  1  1  2  0  0  2  0              7              4
    42  0  1  0  2  0  0  0  0  0  1              3              0
    43  0  0  2  0  5  0  3  2  1  1              2              6
    44  0  2  0  1  0  0  1  0  0  0              3              1
    45  1  0  0  2  0  0  0  1  4  0              3              5
    46  0  2  0  0  0  0  0  1  1  0              2              2
    48  3  0  0  0  0  1  1  0  0  0              3              2
    50  0  1  0  1  0  1  0  0  2  1              2              3
    51  0  0  2  0  0  0  2  3  1  1              2              6
    52  0  0  2  3  2  3  1  0  1  5              5              5
    53  0  0  0  2  1  1  0  0  1  1              2              2
    54  0  1  2  2  2  0  1  0  2  0              5              3
    55  0  2  1  0  0  0  0  0  3  2              3              3
    56  0  1  0  0  0  2  2  0  1  1              1              5
    57  0  0  0  1  1  0  0  1  0  0              1              1
    58  6  1  2  0  2  2  0  0  0  0              9              2
    59  0  1  1  0  0  0  0  0  2  0              2              2
    60  2  0  0  0  1  0  0  1  0  1              2              1
    61  0  0  3  1  1  2  0  0  1  0              4              3
    62  2  0  1  0  0  0  0  1  2  1              3              3
    63  2  0  1  0  1  0  1  0  0  0              3              1
    65  0  0  1  0  0  0  1  5  0  1              1              6
       .. .. .. .. .. .. .. .. .. ..            ...            ...
    
    [9269 rows x 12 columns]
    

    【讨论】:

    • 感谢您的回答。我正在测试你的方法,很快就会报告。
    • 我无法运行代码的计数生成部分,它说:NotImplementedError: indexing 64-bit unsigned integer columns is not supported yet, sorry
    • 可以在这个notebook的最后看到错误:nbviewer.ipython.org/gist/tritemio/8293590
    • 你需要 pytables 3.0.0, pandas 0.12
    • 可能是 0.12 中类型转换的错误:尝试使用 int8 而不是 uint8;也可能是架构/操作系统问题 - 你是 64 位的? Linux? uint 有时很奇怪。鞋数.dtypes 前附加;你不想要 uint64
    【解决方案3】:

    PyTable 解决方案

    由于不需要 Pandas 提供的功能,而且处理速度要慢得多(见下面的笔记本),最好的方法是直接使用 PyTables 或 h5py。到目前为止,我只尝试了 pytables 方法。

    所有测试均在此笔记本中进行:

    pytables 数据结构简介

    参考:Official PyTables Docs

    Pytables 允许以 2 种格式将数据存储在 HDF5 文件中:数组和表格。

    数组

    数组有ArrayCArrayEArray三种类型。它们都允许使用类似于 numpy 切片的符号来存储和检索(多维)切片。

    # Write data to store (broadcasting works)
    array1[:]  = 3
    
    # Read data from store
    in_ram_array = array1[:]
    

    为了在某些用例中进行优化,CArray 保存在“块”中,可以在创建时使用chunk_shape 选择其大小。

    ArrayCArray 的大小在创建时是固定的。不过,您可以在创建后逐块填充/写入数组。反之,EArray 可以用.append() 方法扩展。

    表格

    table 是一个完全不同的野兽。它基本上是一个“表”。您只有一维索引,每个元素都是一行。在每一行内都有“列”数据类型,每一列可以有不同的类型。 numpy record-arrays你很熟悉,表基本上是一个一维记录数组,每个元素都有许多字段作为列。

    1D 或 2D numpy 数组可以存储在表中,但有点棘手:我们需要创建一个行数据类型。例如,要存储一个 1D uint8 numpy 数组,我们需要这样做:

    table_uint8 = np.dtype([('field1', 'u1')])
    table_1d = data_file.create_table('/', 'array_1d', description=table_uint8)
    

    那么为什么要使用表格呢?因为,与数组不同,可以有效地查询表。例如,如果我们想在一个巨大的基于磁盘的表中搜索大于 3 的元素,我们可以这样做:

    index = table_1d.get_where_list('field1 > 3')
    

    不仅简单(与数组相比,我们需要分块扫描整个文件并循环构建index),而且速度非常快。

    如何存储仿真参数

    存储模拟参数的最佳方法是使用一个组(即/parameters),将每个标量转换为numpy数组并将其存储为CArray

    emission”的数组

    emission 是按顺序生成和读取的最大数组。对于这种使用模式,一个好的数据结构是EArray。在具有约 50% 零元素的“模拟”数据上,blosc 压缩 (level=5) 可实现 2.2 倍的压缩率。我发现块大小为 2^18 (256k) 的处理时间最短。

    存储“counts

    同时存储“counts”将使文件大小增加 10%,计算时间戳的时间将增加 40%。存储counts 本身并不是一个优势,因为最终只需要时间戳。

    优点是重建索引(时间戳)更简单,因为我们在单个命令(.get_where_list('counts >= 1'))中查询完整时间轴。相反,对于分块处理,我们需要执行一些索引算法,这有点棘手,并且可能是维护的负担。

    但是,与这两种情况下所需的所有其他操作(排序和合并)相比,代码复杂度可能很小。

    存储“timestamps

    时间戳可以累积在 RAM 中。但是,在开始之前我们不知道数组的大小,并且需要最终的hstack() 调用来“合并”存储在列表中的不同块。这会使内存需求翻倍,因此 RAM 可能会不足。

    我们可以使用 .append() 将 as-we-go 时间戳存储到表中。最后,我们可以使用.read() 将表加载到内存中。这仅比全内存计算慢 10%,但避免了“双 RAM”要求。此外,我们可以避免最终的满载并使用最少的 RAM。

    H5Py

    H5py 是一个比 pytables 简单得多的库。对于这个(主要)顺序处理的用例,似乎比 pytables 更合适。唯一缺少的功能是缺少“blosc”压缩。这是否会导致很大的性能损失仍有待测试。

    【讨论】:

    • 这个测试完全是误导。在您的代码中,您的数据结构的列比行长得多,这对于 pytables 和 pandas 都不是最佳的。然后你忘了在flush()之后做fsync,这当然忽略了pytables的实际磁盘写入时间。您还忘记了在 HDFStore 中设置预期行。最后,您忘记在 store.append() 期间禁用动态索引机制。如果你解决了所有这些问题,pytables 和 pandas.HDFStore 实际上给出了相同的性能。
    【解决方案4】:

    使用 OpenMM 模拟粒子 (https://github.com/SimTk/openmm) 和 MDTraj (https://github.com/rmcgibbo/mdtraj) 处理轨迹 IO。

    【讨论】:

      【解决方案5】:

      接受答案中的pytables vs pandas.HDFStore 测试完全具有误导性:

      • 第一个严重错误是时间不适用os.fsync之后 冲洗,这使速度测试不稳定。所以有时候,pytables 函数意外地快得多。

      • 第二个问题是 pytables 和 pandas 版本已经完全 由于对pytables.EArray的误解造成的不同形状 形状 arg。作者尝试将列附加到 pytables 版本中,但是 将行追加到熊猫版本中。

      • 第三个问题是作者使用了不同的chunkshape 比较。

      • 作者还忘记在store.append()期间禁用表索引生成,这是一个耗时的过程。

      下表显示了他的版本和我的修复的性能结果。 tbold 是他的 pytables 版本,pdold 是他的 pandas 版本。 tbsyncpdsync 是他的版本,fsync()flush() 之后,并且还在追加期间禁用表索引生成。 tboptpdopt 是我的优化版本,blosc:lz4 和 complevel 9。

      | name   |   dt |   data size [MB] |   comp ratio % | chunkshape   | shape         | clib            | indexed   |
      |:-------|-----:|-----------------:|---------------:|:-------------|:--------------|:----------------|:----------|
      | tbold  | 5.11 |           300.00 |          84.63 | (15, 262144) | (15, 5242880) | blosc[5][1]     | False     |
      | pdold  | 8.39 |           340.00 |          39.26 | (1927,)      | (5242880,)    | blosc[5][1]     | True      |
      | tbsync | 7.47 |           300.00 |          84.63 | (15, 262144) | (15, 5242880) | blosc[5][1]     | False     |
      | pdsync | 6.97 |           340.00 |          39.27 | (1927,)      | (5242880,)    | blosc[5][1]     | False     |
      | tbopt  | 4.78 |           300.00 |          43.07 | (4369, 15)   | (5242880, 15) | blosc:lz4[9][1] | False     |
      | pdopt  | 5.73 |           340.00 |          38.53 | (3855,)      | (5242880,)    | blosc:lz4[9][1] | False     |
      

      pandas.HDFStore 在后台使用pytables。因此,如果我们正确使用它们,它们应该没有区别。

      我们可以看到 pandas 版本的数据量更大。这是因为 pandas 使用 pytables.Table 而不是 EArray。而且 pandas.DataFrame 总是有一个索引列。 Table 对象的第一列是这个 DataFrame 索引,它需要一些额外的空间来保存。这只会稍微影响 IO 性能,但会提供更多功能,例如核外查询。所以我还是在这里推荐pandas。 @MRocklin 还提到了一个更好的核心包 dask,如果您使用的大多数功能只是数组操作而不是类似表的查询。但 IO 性能不会有明显差异。

      h5f.root.emission._v_attrs
      Out[82]: 
      /emission._v_attrs (AttributeSet), 15 attributes:
         [CLASS := 'GROUP',
          TITLE := '',
          VERSION := '1.0',
          data_columns := [],
          encoding := 'UTF-8',
          index_cols := [(0, 'index')],
          info := {1: {'names': [None], 'type': 'RangeIndex'}, 'index': {}},
          levels := 1,
          metadata := [],
          nan_rep := 'nan',
          non_index_axes := [(1, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])],
          pandas_type := 'frame_table',
          pandas_version := '0.15.2',
          table_type := 'appendable_frame',
          values_cols := ['values_block_0']]
      

      这里是函数:

      def generate_emission(shape):
          """Generate fake emission."""
          emission = np.random.randn(*shape).astype('float32') - 1
          emission.clip(0, 1e6, out=emission)
          assert (emission >=0).all()
          return emission
      
      
      
      def test_puretb_earray(outpath,
                              n_particles = 15,
                              time_chunk_size = 2**18,
                              n_iter = 20,
                             sync = True,
                             clib = 'blosc',
                             clevel = 5,
                             ):
      
          time_size = n_iter * time_chunk_size
          data_file = pytb.open_file(outpath, mode="w")
          comp_filter = pytb.Filters(complib=clib, complevel=clevel)
          emission = data_file.create_earray('/', 'emission', atom=pytb.Float32Atom(),
                                             shape=(n_particles, 0),
                                             chunkshape=(n_particles, time_chunk_size),
                                             expectedrows=n_iter * time_chunk_size,
                                             filters=comp_filter)
      
          # generate simulated emission data
          t0 =time()
          for i in range(n_iter):
              emission_chunk = generate_emission((n_particles, time_chunk_size))
              emission.append(emission_chunk)
      
          emission.flush()
          if sync:
              os.fsync(data_file.fileno())
          data_file.close()
          t1 = time()
          return t1-t0
      
      
      def test_puretb_earray2(outpath,
                              n_particles = 15,
                              time_chunk_size = 2**18,
                              n_iter = 20,
                             sync = True,
                             clib = 'blosc',
                             clevel = 5,
                             ):
      
          time_size = n_iter * time_chunk_size
          data_file = pytb.open_file(outpath, mode="w")
          comp_filter = pytb.Filters(complib=clib, complevel=clevel)
          emission = data_file.create_earray('/', 'emission', atom=pytb.Float32Atom(),
                                             shape=(0, n_particles),
                                             expectedrows=time_size,
                                             filters=comp_filter)
      
          # generate simulated emission data
          t0 =time()
          for i in range(n_iter):
              emission_chunk = generate_emission((time_chunk_size, n_particles))
              emission.append(emission_chunk)
      
          emission.flush()
      
          if sync:
              os.fsync(data_file.fileno())
          data_file.close()
          t1 = time()
          return t1-t0
      
      
      def test_purepd_df(outpath,
                         n_particles = 15,
                         time_chunk_size = 2**18,
                         n_iter = 20,
                         sync = True,
                         clib='blosc',
                         clevel=5,
                         autocshape=False,
                         oldversion=False,
                         ):
          time_size = n_iter * time_chunk_size
          emission = pd.HDFStore(outpath, mode='w', complib=clib, complevel=clevel)
          # generate simulated data
          t0 =time()
          for i in range(n_iter):
      
              # Generate fake emission
              emission_chunk = generate_emission((time_chunk_size, n_particles))
      
              df = pd.DataFrame(emission_chunk, dtype='float32')
      
              # create a globally unique index (time)
              # http://stackoverflow.com/questions/16997048/how-does-one-append-large-
              # amounts-of-data-to-a-pandas-hdfstore-and-get-a-natural/16999397#16999397
              try:
                  nrows = emission.get_storer('emission').nrows
              except:
                  nrows = 0
      
              df.index = pd.Series(df.index) + nrows
      
              if autocshape:
                  emission.append('emission', df, index=False,
                                  expectedrows=time_size
                                  )
              else:
                  if oldversion:
                      emission.append('emission', df)
                  else:
                      emission.append('emission', df, index=False)
      
          emission.flush(fsync=sync)
          emission.close()
          t1 = time()
          return t1-t0
      
      
      def _test_puretb_earray_nosync(outpath):
          return test_puretb_earray(outpath, sync=False)
      
      
      def _test_purepd_df_nosync(outpath):
          return test_purepd_df(outpath, sync=False,
                                oldversion=True
                                )
      
      
      def _test_puretb_earray_opt(outpath):
          return test_puretb_earray2(outpath,
                                     sync=False,
                                     clib='blosc:lz4',
                                     clevel=9
                                     )
      
      
      def _test_purepd_df_opt(outpath):
          return test_purepd_df(outpath,
                                sync=False,
                                clib='blosc:lz4',
                                clevel=9,
                                autocshape=True
                                )
      
      
      testfns = {
          'tbold':_test_puretb_earray_nosync,
          'pdold':_test_purepd_df_nosync,
          'tbsync':test_puretb_earray,
          'pdsync':test_purepd_df,
          'tbopt': _test_puretb_earray_opt,
          'pdopt': _test_purepd_df_opt,
      }
      

      【讨论】:

        猜你喜欢
        • 2020-02-29
        • 2015-06-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-13
        • 1970-01-01
        相关资源
        最近更新 更多