28

例如,通过使用字段名称列表进行索引,我可以fields在结构化数组中一次看到几列 ( )numpy

import numpy as np

a = np.array([(1.5, 2.5, (1.0,2.0)), (3.,4.,(4.,5.)), (1.,3.,(2.,6.))],
        dtype=[('x',float), ('y',float), ('value',float,(2,2))])

print a[['x','y']]
#[(1.5, 2.5) (3.0, 4.0) (1.0, 3.0)]

print a[['x','y']].dtype
#[('x', '<f4') ('y', '<f4')])

但问题是它似乎是一个副本而不是一个视图:

b = a[['x','y']]
b[0] = (9.,9.)

print b
#[(9.0, 9.0) (3.0, 4.0) (1.0, 3.0)]

print a[['x','y']]
#[(1.5, 2.5) (3.0, 4.0) (1.0, 3.0)]

如果我只选择一列,它是一个视图:

c = x['y']
c[0] = 99.

print c
#[ 99.  4.   3. ]

print a['y']
#[ 99.  4.   3. ]

有什么方法可以一次获得多个列的视图行为?

我有两种解决方法,一种是循环遍历列,另一种是创建一个分层的dtype,以便一列实际上返回一个结构化数组,其中包含我想要的两个(或更多)字段。不幸的是,zip还返回一个副本,所以我不能这样做:

x = a['x']; y = a['y']
z = zip(x,y)
z[0] = (9.,9.)
4

5 回答 5

35

您可以创建一个仅包含所需字段的 dtype 对象,并用于numpy.ndarray()创建原始数组的视图:

import numpy as np
strc = np.zeros(3, dtype=[('x', int), ('y', float), ('z', int), ('t', "i8")])

def fields_view(arr, fields):
    dtype2 = np.dtype({name:arr.dtype.fields[name] for name in fields})
    return np.ndarray(arr.shape, dtype2, arr, 0, arr.strides)

v1 = fields_view(strc, ["x", "z"])
v1[0] = 10, 100

v2 = fields_view(strc, ["y", "z"])
v2[1:] = [(3.14, 7)]

v3 = fields_view(strc, ["x", "t"])

v3[1:] = [(1000, 2**16)]

print(strc)

这是输出:

[(10, 0.0, 100, 0L) (1000, 3.14, 7, 65536L) (1000, 3.14, 7, 65536L)]
于 2014-02-17T01:36:26.867 回答
11

基于@HYRY 的回答,您也可以使用ndarray's 方法getfield

def fields_view(array, fields):
    return array.getfield(numpy.dtype(
        {name: array.dtype.fields[name] for name in fields}
    ))
于 2016-08-26T04:32:06.197 回答
7

从 Numpy 1.16 版开始,您建议的代码返回一个视图。请参阅此页面上的“NumPy 1.16.0 发行说明->未来更改->多字段视图返回视图而不是副本”:

https://numpy.org/doc/stable/release/1.16.0-notes.html#multi-field-views-return-a-view-instead-of-a-copy

于 2017-03-20T09:35:26.307 回答
4

我认为没有一种简单的方法可以实现您想要的。通常,您不能将任意视图放入数组中。尝试以下操作:

>>> a
array([(1.5, 2.5, [[1.0, 2.0], [1.0, 2.0]]),
       (3.0, 4.0, [[4.0, 5.0], [4.0, 5.0]]),
       (1.0, 3.0, [[2.0, 6.0], [2.0, 6.0]])], 
      dtype=[('x', '<f8'), ('y', '<f8'), ('value', '<f8', (2, 2))])
>>> a.view(float)
array([ 1.5,  2.5,  1. ,  2. ,  1. ,  2. ,  3. ,  4. ,  4. ,  5. ,  4. ,
        5. ,  1. ,  3. ,  2. ,  6. ,  2. ,  6. ])

记录数组的浮动视图显示了实际数据是如何存储在内存中的。对此数据的视图必须可以表达为上述数据的形状、步幅和偏移量的组合。因此,如果您想要,例如,只有一个视图'x''y'您可以执行以下操作:

>>> from numpy.lib.stride_tricks import as_strided
>>> b = as_strided(a.view(float), shape=a.shape + (2,),
                   strides=a.strides + a.view(float).strides)
>>> b
array([[ 1.5,  2.5],
       [ 3. ,  4. ],
       [ 1. ,  3. ]])

as_strided与可能更容易理解的相同:

>>> bb = a.view(float).reshape(a.shape + (-1,))[:, :2]
>>> bb
array([[ 1.5,  2.5],
       [ 3. ,  4. ],
       [ 1. ,  3. ]])

这其中的任何一个都是对以下内容的看法 a

>>> b[0,0] =0
>>> a
array([(0.0, 2.5, [[0.0, 2.0], [1.0, 2.0]]),
       (3.0, 4.0, [[4.0, 5.0], [4.0, 5.0]]),
       (1.0, 3.0, [[2.0, 6.0], [2.0, 6.0]])], 
      dtype=[('x', '<f8'), ('y', '<f8'), ('value', '<f8', (2, 2))])
>>> bb[2, 1] = 0
>>> a
array([(0.0, 2.5, [[0.0, 2.0], [1.0, 2.0]]),
       (3.0, 4.0, [[4.0, 5.0], [4.0, 5.0]]),
       (1.0, 0.0, [[2.0, 6.0], [2.0, 6.0]])], 
      dtype=[('x', '<f8'), ('y', '<f8'), ('value', '<f8', (2, 2))])

如果可以将其中任何一个转换为记录数组,那就太好了,但是 numpy 拒绝这样做,原因对我来说不是那么清楚:

>>> b.view([('x',float), ('y',float)])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: new type not compatible with array.

当然,什么对(某种)有效,什么对'x'无效'y',例如,对于'x'and 'value',所以一般来说答案是:它做不到。

于 2013-03-03T07:47:06.250 回答
0

在我的情况下,“几列”恰好等于相同数据类型的两列,我可以使用以下函数来创建视图:

def make_view(arr, fields, dtype):
    offsets = [arr.dtype.fields[f][1] for f in fields]
    offset = min(offsets)
    stride = max(offsets)
    return np.ndarray((len(arr), 2), buffer=arr, offset=offset, strides=(arr.strides[0], stride-offset), dtype=dtype)

我认为这归结为@Jamie 所说的同样的事情,一般情况下不能这样做,但对于相同 dtype 的两列它可以。这个函数的结果不是字典,而是一个很好的老式 numpy 数组。

于 2020-05-06T16:55:58.057 回答