Python 在NumPy 1.14中,将结构化数组的切片转换为常规NumPy数组

Python 在NumPy 1.14中,将结构化数组的切片转换为常规NumPy数组,python,numpy,structured-array,Python,Numpy,Structured Array,注1:在我的案例中,没有一个答案是有效的 注2:解决方案必须适用于NumPy 1.14 假设我有以下结构化数组: arr=np.array([(105.0,34.0,145.0,217.0)],dtype=[('a','f4'),('b','f4'),('c','f4'),('d','f4')]) 现在我将分为结构化数据类型,如下所示: arr2=arr['a','b']] 现在我尝试将该切片转换为常规数组: out=arr2[0]。视图((np.float32,2)) 导致 ValueErro

注1:在我的案例中,没有一个答案是有效的

注2:解决方案必须适用于NumPy 1.14

假设我有以下结构化数组:

arr=np.array([(105.0,34.0,145.0,217.0)],dtype=[('a','f4'),('b','f4'),('c','f4'),('d','f4')])

现在我将分为结构化数据类型,如下所示:

arr2=arr['a','b']]

现在我尝试将该切片转换为常规数组:

out=arr2[0]。视图((np.float32,2))

导致

ValueError:仅当itemsize保持不变时,才支持更改0d数组的数据类型

我想得到的只是一个规则数组,如下所示:

[105.0,34.0]

注意,为了最小化,这个例子被简化了。在我的实际用例中,我显然没有处理包含一个元素的数组

我知道这个解决方案是有效的:

out=np.asarray(列表(arr2[0]))


但我认为一定有比将NumPy数组中已有的数据复制到列表中然后再返回到数组中更有效的解决方案。我假设有一种方法可以留在NumPy中,但实际上可能根本不复制任何数据,我只是不知道如何进行。

1d数组会使用
视图进行转换:

In [270]: arr = np.array([(105.0, 34.0, 145.0, 217.0)], dtype=[('a', 'f4'), ('b','f4'), ('c', 'f4'), ('d', 'f4')])
In [271]: arr
Out[271]: 
array([(105., 34., 145., 217.)],
      dtype=[('a', '<f4'), ('b', '<f4'), ('c', '<f4'), ('d', '<f4')])
In [272]: arr.view('<f4')
Out[272]: array([105.,  34., 145., 217.], dtype=float32)
item
也是将元素从其numpy结构中拉出的好方法:

In [281]: arr[0].item()
Out[281]: (105.0, 34.0, 145.0, 217.0)
tolost
item
的结果是一个元组

你担心速度。但你只是在转换一个元素。在1000项数组上使用
tolist
时,担心速度是一回事,在使用1个元素时则完全是另一回事

In [283]: timeit arr[0]
131 ns ± 1.31 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In [284]: timeit arr[0].tolist()
1.25 µs ± 11.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [285]: timeit arr[0].item()
1.27 µs ± 2.39 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [286]: timeit arr.tolist()
493 ns ± 17.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [287]: timeit arr.view('f4')
1.74 µs ± 18.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

您可以以一种不会将维度减少到0的方式对元素进行索引(这对速度没有多大帮助):


视图
仍需要更改形状;考虑一个大数组:

In [299]: arrs = np.repeat(arr, 10000)
In [301]: arrs.view('f4')
Out[301]: array([105.,  34., 145., ...,  34., 145., 217.], dtype=float32)
In [303]: arrs.shape
Out[303]: (10000,)
In [304]: arrs.view('f4').shape
Out[304]: (40000,)
视图仍然是1d,我们可能需要一个(10000,4)形状的2d阵列

更好的视图更改:

In [306]: arrs.view(('f4',4))
Out[306]: 
array([[105.,  34., 145., 217.],
       [105.,  34., 145., 217.],
       [105.,  34., 145., 217.],
       ...,
       [105.,  34., 145., 217.],
       [105.,  34., 145., 217.],
       [105.,  34., 145., 217.]], dtype=float32)
In [307]: _.shape
Out[307]: (10000, 4)
这适用于1元素数组,无论是1d还是0d:

In [308]: arr.view(('f4',4))
Out[308]: array([[105.,  34., 145., 217.]], dtype=float32)
In [309]: _.shape
Out[309]: (1, 4)
In [310]: arr[0].view(('f4',4))
Out[310]: array([105.,  34., 145., 217.], dtype=float32)
In [311]: _.shape
Out[311]: (4,)
这是在您链接中的一个答案中提出的:

与你的评论相反,它对我有效:

In [312]: arr[0].view((np.float32, len(arr.dtype.names)))
Out[312]: array([105.,  34., 145., 217.], dtype=float32)
In [313]: np.__version__
Out[313]: '1.14.0'

通过编辑:

In [84]: arr = np.array([(105.0, 34.0, 145.0, 217.0)], dtype=[('a', 'f4'), ('b','f4'), ('c', 'f4'), ('d', 'f4')])
In [85]: arr2 = arr[['a', 'b']]
In [86]: arr2
Out[86]: 
array([(105., 34.)],
      dtype={'names':['a','b'], 'formats':['<f4','<f4'], 'offsets':[0,4], 'itemsize':16})

In [87]: arr2.view(('f4',2))
...
ValueError: Changing the dtype to a subarray type is only supported if the total itemsize is unchanged
arr.view('f4',4)
arr2.view('f4',4))
产生相同的结果

因此,您不能
查看
(更改数据类型)部分字段集。您必须首先查看整个数组的
视图
,然后选择行/列,或者使用
列表

我使用的是
1.14.0
1.14.1
的发行说明说:

1.14.0中的更改,即结构化数组的多字段索引返回 已还原视图而不是副本,但仍将按NumPy 1.15的顺序运行。 受影响的用户应阅读1.14.1 Numpy用户指南部分 “基础知识/结构化阵列/访问多个字段”,了解如何 管理此过渡


这仍在开发中。该文档提到了一个
repack_fields
函数,但它还不存在。

您正在寻找
np.array(arr[0].tolist())
?@pault是的,但从结构化数组到列表再到数组并不是一个有效的解决方案:/我无法重现您的错误。
arr[0]。查看((np.32,len(arr.dtype.names)))
适用于我。添加到@pault,我也无法重新创建错误,我的numpy版本为1。11@pault你使用的是哪个Numpy版本?1.14改变了结构化数组的一些行为,这就是我非常希望你给出答案的原因!我意识到我没有正确地提出我的问题。你是对的,我OP中的解决方案确实如此在我给出的示例中,确实没有导致错误。我错误地提出了示例。对此非常抱歉!我对示例进行了轻微的修改。现在它既代表了我的实际用例,又不幸地抛出了错误:/由于最近在多字段选择中的更改,您不能这样做。非常感谢编辑后的答案,一个d谢谢你给我指点相关文档!如果我应该看得更透彻一些的话。我想我现在会转换成一个列表,然后看看NumPy 1.15带来了什么。版本1.17实现了新的多域视图方法。请阅读文档和发行说明。
In [308]: arr.view(('f4',4))
Out[308]: array([[105.,  34., 145., 217.]], dtype=float32)
In [309]: _.shape
Out[309]: (1, 4)
In [310]: arr[0].view(('f4',4))
Out[310]: array([105.,  34., 145., 217.], dtype=float32)
In [311]: _.shape
Out[311]: (4,)
In [312]: arr[0].view((np.float32, len(arr.dtype.names)))
Out[312]: array([105.,  34., 145., 217.], dtype=float32)
In [313]: np.__version__
Out[313]: '1.14.0'
In [84]: arr = np.array([(105.0, 34.0, 145.0, 217.0)], dtype=[('a', 'f4'), ('b','f4'), ('c', 'f4'), ('d', 'f4')])
In [85]: arr2 = arr[['a', 'b']]
In [86]: arr2
Out[86]: 
array([(105., 34.)],
      dtype={'names':['a','b'], 'formats':['<f4','<f4'], 'offsets':[0,4], 'itemsize':16})

In [87]: arr2.view(('f4',2))
...
ValueError: Changing the dtype to a subarray type is only supported if the total itemsize is unchanged
In [93]: arr.itemsize
Out[93]: 16
In [94]: arr2.itemsize
Out[94]: 16