使用Dask读取块结构ASCII文件

时间:2018-08-06 19:59:17

标签: dask

我有一个按块构造的ASCII文件,如下所示(简化版本):

setContentView(mGameView);

我们可以忽略标题行,每个块都由定义时间步长的TS行开始,然后是一个长为ND的数据块。块中每个数据点的索引仅是值在块中的位置。数据块由“ TS”行分隔。

我想与Dask一起阅读,以便我可以处理非常大的文件。我想我需要使用dask.read_bytes,但是在这种情况下,我的分隔符是变量(即'TS 0 * \ n')加上每个块的时间步长值(即TS 0 180.00中的180)

关于这是否可能以及如何进行的一些指示将不胜感激。目标文件约为12GB。

1 个答案:

答案 0 :(得分:0)

对于给定的数据样本,您可以执行以下操作:

head, parts = dask.bytes.read_bytes(infile, delimiter=b'\nTS 0', blocksize=30)

此处,head包含文件的前导字节(对于这种情况,整个文件!通常由sample=控制)。如果您还没有正则表达式,则查找全局元数据可能是最好的选择。

re.search(b'ND (\d+)', head).groups()[0]
b'4'

对于数据,您将需要类似以下的功能。我在这里假设数据帧输出。另外,我猜每一行TS之后有一行数据,因为这就是样本所具有的。此功能可能不够美观或效率很高,但可以完成工作

import numpy as np
import pandas as pd
import dask

@dask.delayed
def proc(bytes, meta):
    if len(bytes) == 0:
        return meta
    parts = bytes.split(b'\nTS 0')
    out = []
    for part in parts:
        if len(part) == 0:
            continue
        lines = part.split(b'\n')
        timestep = float(lines[0].strip())
        values = np.fromstring(lines[1], dtype=float, sep=' ')
        out.append(pd.DataFrame({'timestep': timestep, 'values': values}))
    return pd.concat(out)


meta = pd.DataFrame([], dtype=float, columns=['timestep', 'values'])
dd.from_delayed([proc(p, meta) for p in parts[0][1:]], meta=meta)

注意:

  • 我们提供了meta,因为某些块可能是空的(对于本例中的小块而言)。我们还跳过每个字节块末尾的空块。

  • 第一个块包含标头,不应将其解析为数据(这是[1:]选择)。如果它还包含数据,则需要额外的代码来处理(也许只是try / except解析块)

  • parts是延迟字节列表的列表;理论上,一次调用中可能有多个输入文件。如何处理它们取决于每个文件是否都有标题,以及是否需要从每个文件中独立解析该信息。或者,可以将此处生成的数据帧连接起来。

计算这段代码,我得到

   timestep  values
0       0.0     1.0
1       0.0     2.0
2       0.0     3.0
3       0.0     4.0
0     180.0     1.1
1     180.0     2.1
2     180.0     3.1
3     180.0     4.1
0     360.0     1.2
1     360.0     2.2
2     360.0     3.2
3     360.0     4.2
0     540.0     1.3
1     540.0     2.3
2     540.0     3.3
3     540.0     4.3