python - 从 numpy.int32 数组的数据字节中有效地删除每 4 个字节

标签 python arrays string numpy 24-bit

我有一个大numpy.int32阵列,可能需要 4GB 或更多。它实际上是一个 24 位整数数组 (在音频应用中很常见),但作为 numpy.int24不存在,我使用了 int32 .
我想将此数组的数据作为 24 位(即每个数字 3 个字节)输出到文件。

  • 这有效(我不久前在某处找到了这个“食谱”,但我再也找不到在哪里了):
      import numpy as np
      x = np.array([[-33772,-2193],[13313,-1314],[20965,-1540],[10706,-5995],[-37719,-5871]], dtype=np.int32)
      data = ((x.reshape(x.shape + (1,)) >> np.array([0, 8, 16])) & 255).astype(np.uint8)
      print(data.tostring())
    
      # b'\x14|\xffo\xf7\xff\x014\x00\xde\xfa\xff\xe5Q\x00\xfc\xf9\xff\xd2)\x00\x95\xe8\xff\xa9l\xff\x11\xe9\xff'
    
    但是很多reshapex 时效率低下有几 GB 大:它需要大量不需要的 RAM。
  • 另一种解决方案是删除每 4 个字节:
    s = bytes([c for i, c in enumerate(x.tostring()) if i % 4 != 3])
    
    # b'\x14|\xffo\xf7\xff\x014\x00\xde\xfa\xff\xe5Q\x00\xfc\xf9\xff\xd2)\x00\x95\xe8\xff\xa9l\xff\x11\xe9\xff'
    
    它有效,但我怀疑如果 x假设需要 4 GB 的 RAM,这条线将至少消耗 8 GB 的 RAM,对于 sx (也许还有 x.tostring() ?)

  • TL;博士:如何通过删除每 4 个字节来有效地(不使用两倍于实际数据大小的 RAM)将一个 int32 数组作为 24 位数组写入磁盘?
    注意:这是可能的,因为整数实际上是 24 位的,即每个值的绝对值 < 2^23-1

    最佳答案

    经过更多的摆弄,我发现这是有效的:

    import numpy as np
    x = np.array([[-33772,-2193],[13313,-1314],[20965,-1540],[10706,-5995],[-37719,-5871]], dtype=np.int32)
    x2 = x.view(np.uint8).reshape(-1,4)[:,:3]
    print(x2.tostring())
    # b'\x14|\xffo\xf7\xff\x014\x00\xde\xfa\xff\xe5Q\x00\xfc\xf9\xff\xd2)\x00\x95\xe8\xff\xa9l\xff\x11\xe9\xff'
    
    这是一个时间+内存基准:
    import numpy as np, time
    t0 = time.time()
    x = np.random.randint(10000, size=(125_000_000, 2), dtype=np.int32)  # 125M * 2 * 4 bytes ~ 1GB of RAM
    print('Random array generated in %.1f sec.' % (time.time() - t0))
    time.sleep(5)  
    # you can check the RAM usage in the task manager in the meantime...
    t0 = time.time()
    x2 = x.view(np.uint8).reshape(-1,4)[:,:3]
    x2.tofile('test')
    print('24-bit output file written in %.1f sec.' % (time.time() - t0))
    
    结果:

    Random array generated in 4.6 sec.
    24-bit output file written in 35.9 sec.


    此外,在整个处理过程中仅使用了约 1GB(使用 Windows 任务管理器进行监控)

    @jdehesa 的方法给出了类似的结果,即如果我们改用这一行:
    x2 = np.ndarray(shape=x.shape + (3,), dtype=np.uint8, buffer=x, offset=0, strides=x.strides + (1,))
    
    该进程的 RAM 使用量也达到了 1GB 的峰值,并且花费的时间在 x2.tofile(...) 上。是 ~37 秒。

    关于python - 从 numpy.int32 数组的数据字节中有效地删除每 4 个字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63156701/

    相关文章:

    c - 理解 char *、char[] 和 strcpy()

    C++ cin空格问题

    python - 在 python 中记录异常过滤器

    python - 连续红色后获取 pandas 值

    python - 使用 lambda 的 relu 激活函数

    Java CharAt() 和 deleteCharAt() 性能

    python - 在 Pandas 中将字符串转换为小写

    python - 在每个数据点处带有对齐注释的散点图

    python - 如何将值作为索引的函数赋值给 numpy 数组?

    javascript - 从本地数据库加载所有数据