【问题标题】:numpy: fromfile for gzipped filenumpy: 用于 gzip 压缩文件的 fromfile
【发布时间】:2016-06-27 18:07:46
【问题描述】:

我正在使用numpy.fromfile 构造一个数组,我可以将它传递给pandas.DataFrame 构造函数

import numpy as np
import pandas as pd

def read_best_file(file, **kwargs):
    '''
    Loads best price data into a dataframe
    '''
    names   = [ 'time', 'bid_size', 'bid_price', 'ask_size', 'ask_price' ]
    formats = [ 'u8',   'i4',       'f8',        'i4',       'f8'        ]
    offsets = [  0,      8,          12,          20,         24         ]

    dt = np.dtype({
            'names': names, 
            'formats': formats,
            'offsets': offsets 
        })
    return pd.DataFrame(np.fromfile(file, dt))

我想扩展此方法以处理压缩文件。

根据numpy.fromfile文档,第一个参数是file:

file : file or str
Open file object or filename

因此,我添加了以下内容来检查 gzip 文件路径:

if isinstance(file, str) and file.endswith(".gz"):
    file = gzip.open(file, "r")

但是,当我尝试通过 fromfile 构造函数传递它时,我得到一个 IOError

IOError: first argument must be an open file

问题:

如何使用 gzip 压缩文件调用 numpy.fromfile

编辑:

根据 cmets 中的请求,显示检查 gzip 文件的实现:

def read_best_file(file, **kwargs):
    '''
    Loads best price data into a dataframe
    '''
    names   = [ 'time', 'bid_size', 'bid_price', 'ask_size', 'ask_price' ]
    formats = [ 'u8',   'i4',       'f8',        'i4',       'f8'        ]
    offsets = [  0,      8,          12,          20,         24         ]

    dt = np.dtype({
            'names': names, 
            'formats': formats,
            'offsets': offsets 
        })

    if isinstance(file, str) and file.endswith(".gz"):
        file = gzip.open(file, "r")

    return pd.DataFrame(np.fromfile(file, dt))

【问题讨论】:

  • 我们需要确切了解检查是如何实施的。
  • @TheBlackCat 在返回语句之前插入这两行。
  • 您能否显示完整的代码,并带有正确的缩进?
  • @TheBlackCat 正确缩进是什么意思 - 缩进是正确的
  • 您能否编辑您的问题以显示您所做更改的完整代码。

标签: python numpy


【解决方案1】:

open.gzip() 不会返回真正的 file 对象。这是一只鸭子.. 它像鸭子一样走路,听起来像鸭子,但根据numpy,它并不完全是鸭子。所以numpy 是严格的(因为很多都是用较低级别的 C 代码编写的,它可能需要一个实际的文件描述符。)

您可以从gzip.open() 调用中获取底层file,但这只会为您获取压缩流。

这就是我要做的:我会使用subprocess.Popen() 调用zcat 将文件解压缩为流。

>>> import subprocess
>>> p = subprocess.Popen(["/usr/bin/zcat", "foo.txt.gz"], stdout=subprocess.PIPE)
>>> type(p.stdout)
<type 'file'>
>>> p.stdout.read()
'hello world\n'

现在您可以将p.stdout 作为file 对象传递给numpy

np.fromfile(p.stdout, ...)

【讨论】:

  • fromfile 正在用 c 代码读取自己的文件。它不导入或使用gzip 模块。
  • 这不起作用(对我来说),因为 zcat 的标准输出写入的管道不可查找。因此, np.fromfile 引发 IOError: could not seek in file
  • 啊,如果你的文件适合内存,那么你将不得不使用临时文件或 python 的 stringio。更多关于 gzip 缺乏随机访问的讨论在这里讨论:stackoverflow.com/questions/25985645/…
  • BytesIO 给了我和open.gzip同样的问题
【解决方案2】:

通过 numpy.frombuffer() 提供 read() 结果,我已经成功地从 gzip 文件中读取原始二进制数据数组。此代码适用于 Python 3.7.3,或许也适用于早期版本。

# Example: read short integers (signed) from gzipped raw binary file

import gzip
import numpy as np

fname_gzipped = 'my_binary_data.dat.gz'
raw_dtype = np.int16
with gzip.open(fname_gzipped, 'rb') as f:
    from_gzipped = np.frombuffer(f.read(), dtype=raw_dtype)

# Demonstrate equivalence with direct np.fromfile()
fname_raw = 'my_binary_data.dat'
from_raw = np.fromfile(fname_raw, dtype=raw_dtype)

# True
print('raw binary and gunzipped are the same: {}'.format(
    np.array_equiv(from_gzipped, from_raw)))

# False
wrong_dtype = np.uint8
binary_as_wrong_dtype = np.fromfile(fname_raw, dtype=wrong_dtype)
print('wrong dtype and gunzipped are the same: {}'.format(
    np.array_equiv(from_gzipped, binary_as_wrong_dtype)))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-11
    • 1970-01-01
    • 2015-07-14
    • 1970-01-01
    相关资源
    最近更新 更多