【问题标题】:NumPy "record array" or "structured array" or "recarray"NumPy“记录数组”或“结构化数组”或“recarray”
【发布时间】:2015-03-15 17:11:09
【问题描述】:

NumPy“结构化数组”、“记录数组”和“recarray”之间有什么区别(如果有的话)?

NumPy docs 暗示前两个是相同的:如果是,那么这个对象的首选术语是什么?

相同的文档说(在页面底部): 你可以找到更多关于recarrays 和结构化数组的信息(包括两者的区别)here。对这种差异有简单的解释吗?

【问题讨论】:

  • 我已经澄清了这个问题,@Ashwini Chaudhary - 谢谢。
  • 对文档差异的解释有什么不清楚的地方? recarray 支持以arr.foo 格式访问字段,而普通结构化数组仅支持通过arr['foo'] 格式访问,但查找速度更快。我永远不会将“结构化数组”称为“记录数组”,正是因为它会导致与“recarrays”的潜在混淆。
  • 比如这两种记录数组的历史是怎样的?它们是完全不同的实现还是共享底层代码?为什么给定属性访问开销,我要使用recarray吗?
  • Noob here.... 对我来说,当您希望从具有许多字段/列的数组中访问数据时,recarrays 可以提供更高级别的灵活性。可以通过 my_array['DataField'] 或数组点域表示法 my_array.DataField 进行访问。我发现这是一个额外的好处,并且比你必须依赖使用数字按字段位置切片的数组更上一层楼,因为我永远不记得它们在哪一列。

标签: python numpy data-structures


【解决方案1】:

简而言之,你应该使用结构化数组而不是recarrays,因为结构化数组更快,recarrays的唯一优点是允许你写arr.x而不是arr['x'],这是一个方便的快捷方式,但如果您的列名与 numpy 方法/属性冲突,也容易出错。

查看@jakevdp 书中的excerpt 以获得更详细的解释。他特别指出,简单地访问结构化数组的列可以比访问重新数组的列快 20 到 30 倍左右。但是,他的示例使用了一个只有 4 行的非常小的数据框,并且不执行任何标准操作。

对于较大数据帧的简单操作,尽管结构化数组仍然更快,但差异可能要小得多。例如,这是一个结构化的记录数组,每个数组有 10,000 行(代码从借用自 @jpp 答案 here 的数据帧创建数组)。

n = 10_000
df = pd.DataFrame({ 'x':np.random.randn(n) })
df['y'] = df.x.astype(int)

rec_array = df.to_records(index=False)

s = df.dtypes
struct_array = np.array([tuple(x) for x in df.values], dtype=list(zip(s.index, s)))

如果我们执行标准操作,例如将列乘以 2,结构化数组的速度大约快 50%:

%timeit struct_array['x'] * 2
9.18 µs ± 88.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit rec_array.x * 2
14.2 µs ± 314 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

【讨论】:

  • 美女。关于性能差距问题的可靠陈述。也就是说,它确实存在,您可能应该担心。
  • 当我使用 dtype=list(zip(s.index, s)) 我得到所有列的 dtype 对象的 np 数组。有没有办法从 pd.DataFrame 进行转换,以便 np.array 保留原始列的 dtypes(例如字符串、整数和浮点数?)而不是将它们全部设置为对象?
  • @Spcoggthesecond 我不确定我是否遵循...使用上面的代码,对于struct_arr 和rec_array,我得到x 作为float 和y 作为int。如果你不是,我不知道为什么,但常规 numpy 数组有一个用于 dtype 转换的 astype 方法,你也可以在此处查看 rec 数组的类型转换:stackoverflow.com/questions/9949427/…
【解决方案2】:

记录/记录数组在

中实现

https://github.com/numpy/numpy/blob/master/numpy/core/records.py

此文件中的一些相关引述

记录数组 记录数组将结构化数组的字段公开为属性。 recarray 几乎与标准数组相同(它支持 已命名字段)最大的区别是它可以使用 属性查找来查找字段,它是使用构造的 记录。

recarray 是ndarray 的子类(与matrix 和masked arrays 相同)。但请注意,它的构造函数与np.array 不同。它更像np.empty(size, dtype)。

class recarray(ndarray):
    """Construct an ndarray that allows field access using attributes.
    This constructor can be compared to ``empty``: it creates a new record
       array but does not fill it with data.

实现唯一字段作为属性行为的关键函数是__getattribute__(__getitem__实现索引):

def __getattribute__(self, attr):
    # See if ndarray has this attr, and return it if so. (note that this
    # means a field with the same name as an ndarray attr cannot be
    # accessed by attribute).
    try:
        return object.__getattribute__(self, attr)
    except AttributeError:  # attr must be a fieldname
        pass

    # look for a field with this name
    fielddict = ndarray.__getattribute__(self, 'dtype').fields
    try:
        res = fielddict[attr][:2]
    except (TypeError, KeyError):
        raise AttributeError("recarray has no attribute %s" % attr)
    obj = self.getfield(*res)

    # At this point obj will always be a recarray, since (see
    # PyArray_GetField) the type of obj is inherited. Next, if obj.dtype is
    # non-structured, convert it to an ndarray. If obj is structured leave
    # it as a recarray, but make sure to convert to the same dtype.type (eg
    # to preserve numpy.record type if present), since nested structured
    # fields do not inherit type.
    if obj.dtype.fields:
        return obj.view(dtype=(self.dtype.type, obj.dtype.fields))
    else:
        return obj.view(ndarray)

它首先尝试获取一个常规属性——例如.shape、.strides、.data,以及所有方法(.sum、.reshape 等)。如果失败,它会在 dtype 字段名称中查找名称。所以它实际上只是一个结构化数组,带有一些重新定义的访问方法。

据我所知,record array 和 recarray 是相同的。

另一个文件显示了一些历史记录

https://github.com/numpy/numpy/blob/master/numpy/lib/recfunctions.py

用于操作结构化数组的实用程序集合。 其中大部分功能最初是由 John Hunter 实现的 matplotlib。为方便起见,它们已被重写和扩展。

此文件中的许多函数都以​​:

    if asrecarray:
        output = output.view(recarray)

您可以将数组返回为recarray 视图这一事实表明该层有多“薄”。

numpy 历史悠久,合并了几个独立的项目。我的印象是recarray 是一个较老的想法,而结构化数组是当前基于广义dtype 的实现。与任何新开发相比,recarrays 似乎是为了方便和向后兼容而保留的。但我必须研究github 文件历史记录,以及任何最近的问题/拉取请求以确定。

【讨论】:

    猜你喜欢
    • 2016-10-10
    • 2011-03-04
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 2019-05-08
    • 2016-03-29
    相关资源
    最近更新 更多