NumPy"记录数组"或"结构化数组"或"重新排列"

xnx*_*xnx 19 python numpy data-structures

如果有的话,NumPy"结构化数组","记录数组"和"重新排列"之间的区别是什么?

NumPy的文档 暗示,前两个是相同的:如果是这样,这是该对象的首选术语?

同样的文件说,(在页面的底部):你可以找到关于recarrays和结构化阵列(包括两者之间的区别)一些更多的信息在这里.这种差异有一个简单的解释吗?

hpa*_*ulj 11

记录/重新排列在实施中

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

此文件中的一些相关引用

记录数组记录数组将结构化数组的字段显示为属性.重新排列几乎与标准数组(它已经支持命名字段)相同.最大的区别是它可以使用属性查找来查找字段,并使用记录构建它.

recarray是的子类ndarray(以同样的方式,matrixmasked 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.
Run Code Online (Sandbox Code Playgroud)

将唯一字段实现为属性行为的关键功能是__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)
Run Code Online (Sandbox Code Playgroud)

它首先它会尝试获取常规属性-比如.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)
Run Code Online (Sandbox Code Playgroud)

您可以将recarray视图作为视图返回的事实显示该层的"薄"程度.

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


Joh*_*hnE 8

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

有关更详细的解释,请参见@jakevdp的书摘录。特别是,他指出,简单地访问结构化数组的列可能比访问recarray的列快20到30倍。但是,他的示例使用的是只有4行的非常小的数据框,并且不执行任何标准操作。

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

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)))
Run Code Online (Sandbox Code Playgroud)

如果我们执行标准操作(例如将一列乘以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)
Run Code Online (Sandbox Code Playgroud)