【问题标题】:Reading binary data into pandas将二进制数据读入熊猫
【发布时间】:2021-07-28 20:15:07
【问题描述】:

我有一些二进制数据,我想知道如何将其加载到 pandas 中。

我能否以某种方式加载它并指定它的格式以及各个列的名称?

编辑:
格式是

int, int, int, float, int, int[256]

每个逗号分隔代表数据中的一列,即最后 256 个整数为一列。

【问题讨论】:

  • 你需要把它放到一个numpy数组(或python dict/list)中。它是自定义格式吗?或类似stata的东西?
  • 这是一种自定义格式。一些整数,一些浮点数。
  • 你最好的选择是使用 python 读取并创建一个 numpy 数组;如果速度有问题,那么你可以用 cython 阅读,或者如果你已经在 c 中有一个阅读器,那么你可以用 cython 换行
  • 能提供你二进制文件的格式吗?
  • 当然。将格式添加到原始帖子中。

标签: python pandas numpy


【解决方案1】:

这里有一些东西可以帮助您入门。

from struct import unpack, calcsize
from pandas import DataFrame

entry_format = 'iiifi256i' #int, int, int, float, int, int[256]
field_names = ['a', 'b', 'c', 'd', 'e', 'f', ]
entry_size = calcsize(entry_format)

with open(input_filename, mode='rb') as f:
    entry_count = os.fstat(f.fileno()).st_size / entry_size
    for i in range(entry_count):
        record = f.read(entry_size)
        entry = unpack(entry_format, record)
        entry_frame = dict( (n[0], n[1]) for n in zip(field_names, entry) )
        DataFrame(entry_frame)

【讨论】:

  • 对您的 sn-p 稍作修改(如 open(.., mode='rb')os.fstat(input_filename))我收到以下错误,DataFrame constructor not properly called!
  • 真的不需要在这里算数......for record in iter(lambda: f.read(entry_size), ''): # ... 会做的
  • 这给出了一个错误:ValueError: If use all scalar values, must pass index,看起来 'f' 是 0 而不是数组。
  • 酷,struct 模块看起来很有用。我只需将 entry_frame 字典附加到列表中,然后在读取整个文件后从字典列表中创建一个 DataFrame。
【解决方案2】:

即使这是一个老问题,我也想知道同样的事情,但我没有看到我喜欢的解决方案。

使用 Python 读取二进制数据时,我发现 numpy.fromfilenumpy.fromstring 比使用 Python struct 模块快得多。混合类型的二进制数据可以通过上述方法高效地读入 numpy 数组,只要数据格式不变并且可以用 numpy 数据类型对象 (numpy.dtype) 来描述。

import numpy as np
import pandas as pd

# Create a dtype with the binary data format and the desired column names
dt = np.dtype([('a', 'i4'), ('b', 'i4'), ('c', 'i4'), ('d', 'f4'), ('e', 'i4'),
               ('f', 'i4', (256,))])
data = np.fromfile(file, dtype=dt)
df = pd.DataFrame(data)

# Or if you want to explicitly set the column names
df = pd.DataFrame(data, columns=data.dtype.names)

编辑:

  • 删除了data.to_list() 的不必要转换。谢谢fxx
  • 添加了省略 columns 参数的示例

【讨论】:

  • 一个很大的改进。感谢您发布此解决方案。
  • 不需要列表转换,直接使用数据作为 Pandas 数据帧的驱动程序可以加快速度:df = pd.DataFrame(data, columns=data.dtype.names)
  • 可以在不提供格式的情况下做些什么吗?也就是说,如果我有超过一千列,这将需要一段时间和不必要的努力。
【解决方案3】:

下面使用编译的结构体,比普通结构体快很多。 另一种方法是使用 np.fromstring 或 np.fromfile,如上所述。

import struct, ctypes, os
import numpy as np, pandas as pd 

mystruct = struct.Struct('iiifi256i')
buff = ctypes.create_string_buffer(mystruct.size)
with open(input_filename, mode='rb') as f:
    nrows = os.fstat(f.fileno()).st_size / entry_size
    dtype = 'i,i,i,d,i,i8'
    array = np.empty((nrows,), dtype=dtype)
    for row in xrange(row):
        buff.raw = f.read(s.size)
        record = mystruct.unpack_from(buff, 0)
        #record = np.fromstring(buff, dtype=dtype)
        array[row] = record
 df = pd.DataFrame(array)

另见http://pymotw.com/2/struct/

【讨论】:

    【解决方案4】:

    最近我遇到了一个类似的问题,不过结构要大得多。我想我发现使用实用方法 DataFrame.from_records 改进了 mowen 的答案。在上面的示例中,这将给出:

    import numpy as np
    import pandas as pd
    
    # Create a dtype with the binary data format and the desired column names
    dt = np.dtype([('a', 'i4'), ('b', 'i4'), ('c', 'i4'), ('d', 'f4'), ('e', 'i4'), ('f', 'i4', (256,))])
    data = np.fromfile(file, dtype=dt)
    df = pd.DataFrame.from_records(data)
    

    就我而言,它显着加快了进程。我认为改进来自不必创建中间 Python 列表,而是直接从 Numpy 结构化数组创建 DataFrame。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-12
      • 2018-09-07
      • 2012-09-28
      • 1970-01-01
      • 2019-04-20
      • 1970-01-01
      • 2021-11-11
      相关资源
      最近更新 更多