在dask和pandas数据框中嵌套Numpy数组

Sta*_*tav 10 python numpy pandas dask

适用于图像和音频的机器/深度学习代码的常见用例是加载和操纵图像或音频片段的大型数据集。这些数据集中的条目几乎总是由图像/音频段和元数据(例如,班级标签,培训/测试实例等)表示。

例如,在我的语音识别的特定用例中,数据集几乎总是由具有以下属性的条目组成:

  • 演讲者ID(字符串)
  • 成绩单(字符串)
  • 测试数据(布尔)
  • WAV数据(numpy数组)
  • 数据集名称(字符串)
  • ...

建议以大熊猫和/或dask表示这种数据集的推荐方法是-强调wav数据(在图像数据集中,这就是图像数据本身)?

在熊猫中,有一些技巧,可以将一列numpy数组嵌套在一个列中,但这不能很好地序列化,也不能使用dask。似乎这是一个非常普通的用例,但我找不到任何相关建议。

人们还可以将这些数组序列化/反序列化为二进制格式(Uber的petastorm做类似的事情),但这似乎错过了dask和pandas这样的库的要点,在库中自动幻化是核心优点之一。

我们欢迎任何实用的评论或对不同方法的建议。

Sta*_*tav 1

一种(可能是丑陋的)方法是修补 pandas 和 dask parquet API 以支持多维数组:

# these monkey-patches into the pandas and dask I/O API allow us to save multi-dimensional numpy
# arrays# in parquet format by serializing them into byte arrays

from dask import dataframe as dd
import pandas as pd
from io import BytesIO

def _patched_pd_read_parquet(*args, **kwargs):
    return _orig_pd_read_parquet(*args, **kwargs).applymap(
        lambda val: np.load(BytesIO(val)) if isinstance(val, bytes) else val)
_orig_pd_read_parquet = pd.io.parquet.PyArrowImpl.read
pd.io.parquet.PyArrowImpl.read = _patched_pd_read_parquet

def _serialize_ndarray(arr: np.ndarray) -> bytes:
    if isinstance(arr, np.ndarray):
        with BytesIO() as buf:
            np.save(buf, arr)
            return buf.getvalue()
    return arr

def _deserialize_ndarray(val: bytes) -> np.ndarray:
    return np.load(BytesIO(val)) if isinstance(val, bytes) else val

def _patched_pd_write_parquet(self, df: pd.DataFrame, *args, **kwargs):
    return _orig_pd_write_parquet(self, df.applymap(_serialize_ndarray), *args, **kwargs)
_orig_pd_write_parquet = pd.io.parquet.PyArrowImpl.write
pd.io.parquet.PyArrowImpl.write = _patched_pd_write_parquet

def _patched_dask_read_pyarrow_parquet_piece(*args, **kwargs):
    return _orig_dask_read_pyarrow_parquet_piece(*args, **kwargs).applymap(_deserialize_ndarray)
_orig_dask_read_pyarrow_parquet_piece = dd.io.parquet._read_pyarrow_parquet_piece
dd.io.parquet._read_pyarrow_parquet_piece = _patched_dask_read_pyarrow_parquet_piece

def _patched_dd_write_partition_pyarrow(df: pd.DataFrame, *args, **kwargs):
    return _orig_dd_write_partition_pyarrow(df.applymap(_serialize_ndarray), *args, **kwargs)
_orig_dd_write_partition_pyarrow = dd.io.parquet._write_partition_pyarrow
dd.io.parquet._write_partition_pyarrow = _patched_dd_write_partition_pyarrow
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用问题中指定的技巧来获取 pandas 单元格(内存中)中的嵌套数组,上面的内容将充当“穷人”编解码器,将数组序列化为字节流(不同的序列化方案,例如 parquet可以处理)