Dask read_csv:定期跳过划线

时间:2018-02-16 17:22:18

标签: python dask

我想使用Dask在多个时间步读取大型原子坐标文件。该格式称为XYZ文件,它看起来像这样:

3 timestep 1 C 9.5464696279 5.2523477968 4.4976072664 C 10.6455075132 6.0351186102 4.0196547961 C 10.2970471574 7.3880736108 3.6390228968 3 timestep 2 C 9.5464696279 5.2523477968 4.4976072664 C 10.6455075132 6.0351186102 4.0196547961 C 10.2970471574 7.3880736108 3.6390228968

第一行包含原子编号,第二行只是注释。 之后,列出原子的名称和位置。 列出所有原子后,下一个时间步重复相同。

我现在想通过dask.dataframe.read_csv加载这样的轨迹。 但是,我无法弄清楚如何跳过包含原子编号和注释的周期性划线。这实际上是可能的吗?

修改

可以通过以下方式将此格式读入Pandas Dataframe:

atom_nr = 3

def skip(line_nr):
    return line_nr % (atom_nr + 2) < 2


pd.read_csv(xyz_filename, skiprows=skip, delim_whitespace=True,
            header=None)

但看起来Dask数据帧不支持将函数传递给skiprows。

编辑2 : MRocklin的答案有效!为了完整起见,我写下了我用过的完整代码。

from io import BytesIO

import pandas as pd
import dask.bytes
import dask.dataframe
import dask.delayed


atom_nr = ...
filename = ...


def skip(line_nr):
    return line_nr % (atom_nr + 2) < 2


def pandaread(data_in_bytes):
    pseudo_file = BytesIO(data_in_bytes[0])
    return pd.read_csv(pseudo_file, skiprows=skip, delim_whitespace=True,
                       header=None)

bts = dask.bytes.read_bytes(filename, delimiter=f"{atom_nr}\ntimestep".encode())
dfs = dask.delayed(pandaread)(bts)

sol = dask.dataframe.from_delayed(dfs)
sol.compute()

唯一剩下的问题是:如何告诉dask只计算前n帧?目前似乎已经阅读了完整的轨迹。

1 个答案:

答案 0 :(得分:0)

简短回答

不,pandas.read_csv和dask.dataframe.read_csv都不提供这种功能(据我所知)

长答案

如果您可以编写代码将某些数据转换为pandas数据帧,那么您可以自己动手使用

一般来说,这可能类似于以下内容:

values = read_bytes('filenames.*.txt', delimiter='...', blocksize=2**27)
dfs = [dask.delayed(load_pandas_from_bytes)(v) for v in values]
df = dd.from_delayed(dfs)

每个dfs对应于数据的大约blocksize个字节(然后直到下一个分隔符)。您可以控制分区使用此块大小的程度。如果您愿意,您也可以只选择其中一些dfs个对象来获取较小部分的数据

dfs = dfs[:5]  # only the first five blocks of `blocksize` data