首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Numpy astype "upcasting“数组,而不是跨列应用dtype

Numpy astype "upcasting“数组,而不是跨列应用dtype
EN

Stack Overflow用户
提问于 2018-04-30 12:09:28
回答 3查看 347关注 0票数 3

我有一个2D的numpy数组,我想对每个列应用一个特定的dtype

代码语言:javascript
复制
a = np.arange(25).reshape((5,5))

In [40]: a
Out[40]: 
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19],
       [20, 21, 22, 23, 24]])

In [41]: a.astype(dtype=[('width', '<i4'), ('height', '<i4'), ('depth', '<i4'), ('score', '<f4'), ('auc', '<f4')])

我期望第41行应用我想要的dtype,但是通过创建一个新的轴,为每个dtype复制整个数组一次,从而实现它的“向上转换”:

代码语言:javascript
复制
Out[41]: 
array([[(0, 0, 0, 0.0, 0.0), (1, 1, 1, 1.0, 1.0), (2, 2, 2, 2.0, 2.0),
        (3, 3, 3, 3.0, 3.0), (4, 4, 4, 4.0, 4.0)],
       [(5, 5, 5, 5.0, 5.0), (6, 6, 6, 6.0, 6.0), (7, 7, 7, 7.0, 7.0),
        (8, 8, 8, 8.0, 8.0), (9, 9, 9, 9.0, 9.0)],
       [(10, 10, 10, 10.0, 10.0), (11, 11, 11, 11.0, 11.0),
        (12, 12, 12, 12.0, 12.0), (13, 13, 13, 13.0, 13.0),
        (14, 14, 14, 14.0, 14.0)],
       [(15, 15, 15, 15.0, 15.0), (16, 16, 16, 16.0, 16.0),
        (17, 17, 17, 17.0, 17.0), (18, 18, 18, 18.0, 18.0),
        (19, 19, 19, 19.0, 19.0)],
       [(20, 20, 20, 20.0, 20.0), (21, 21, 21, 21.0, 21.0),
        (22, 22, 22, 22.0, 22.0), (23, 23, 23, 23.0, 23.0),
        (24, 24, 24, 24.0, 24.0)]], 
      dtype=[('width', '<i4'), ('height', '<i4'), ('depth', '<i4'), ('score', '<f4'), ('auc', '<f4')])

既然dtype的数量与列的数量相匹配,为什么会发生这种情况(所以我没有期望向上转换)?

如何像我在第41行中所希望的那样,在内存中使用现有的数组并应用每列的dtype?谢谢。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-04-30 12:59:44

这是我从未遇到过的奇怪的情况,但我相信答案与这样一个事实有关:通常,numpy只支持结构化数组的很少形式的转让

在这种情况下,我认为numpy遵循了标量分配用于结构化数组的约定,然后在整个输入数组上广播赋值,以生成与原始数组形状相同的结果。

为什么是极限?

我认为结构化数组的赋值形式是有限的,因为结构化数组的“列”与普通二维数组的列不太一样。实际上,将一个十行、三列结构化数组看作一个由原子行类型的十个实例组成的一维数组更有意义。

这些原子行类型称为"结构化标量“。它们有一个固定的内部内存布局,不能被动态地重新塑造,所以用与二维数组的行相同的方式对待它们是没有意义的。

如何创建现有数组的结构化视图

老实说,我不知道!如果我找到了一个好的方法,我会更新这个答案。但是我不认为我会找到一个好的方法,因为如上所述,结构化标量有自己独特的内存布局。可以使用具有正确布局的缓冲区来破解一些东西,但是您需要深入了解numpy内部的内容,这并不理想。话虽如此,请看疯狂物理学家的这个答案,他所做的比我想象的更优雅。

同样值得一提的是,astype 默认情况下创建副本。您可以通过copy=False,但是如果某些需求没有得到满足,numpy可能仍然会复制。

其他选择..。

我很少发现我的实际上需要一个视图;经常创建一个副本不会导致性能上的明显变化。我解决这个问题的第一种方法就是使用记录数组的标准分配策略之一。在这种情况下,这可能意味着使用子阵列分配。首先,我们创建数组。注意到了元组。它们是预期行为所必需的。

代码语言:javascript
复制
>>> a = np.array([(1, 2), (3, 4)], dtype=[('x', 'f8'), ('y', 'i8')])
>>> a
array([(1., 2), (3., 4)], dtype=[('x', '<f8'), ('y', '<i8')])

现在,如果我们尝试将一个普通的二维数组赋值给a,我们会得到一个错误:

代码语言:javascript
复制
>>> a[:] = np.array([[11, 22], [33, 44]])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: could not broadcast input array from shape (2,2) into shape (2)

但我们可以很容易地以一种按列的方式分配:

代码语言:javascript
复制
>>> a['x'] = [11, 22]
>>> a['y'] = [33, 44]
>>> a
array([(11., 33), (22., 44)], dtype=[('x', '<f8'), ('y', '<i8')])

我们还可以使用Python 元组。这覆盖了整个数组:

代码语言:javascript
复制
>>> a[:] = [(111, 222), (333, 444)]
>>> a
array([(111., 222), (333., 444)], dtype=[('x', '<f8'), ('y', '<i8')])

我们还可以使用元组按行分配数据:

代码语言:javascript
复制
>>> a[1] = (3333, 4444)
>>> a
array([( 111.,  222), (3333., 4444)], dtype=[('x', '<f8'), ('y', '<i8')])

如果我们试图传递一个列表或数组,这再次失败:

代码语言:javascript
复制
>>> a[1] = [3333, 4444]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: setting an array element with a sequence.
>>> a[1] = np.array([3333, 4444])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: setting an array element with a sequence.

最后,请注意,在尝试从嵌套列表或astype数组创建结构化数组时,我们看到了与numpy相同的行为。numpy只对数据类型广播输入数组,生成一个结构化标量的2-d数组:

代码语言:javascript
复制
>>> a
array([[(1., 1), (2., 2)],
       [(3., 3), (4., 4)]], dtype=[('x', '<f8'), ('y', '<i8')])
>>> a = np.array(np.array([[1, 2], [3, 4]]), dtype=[('x', 'f8'), ('y', 'i8')])
>>> a
array([[(1., 1), (2., 2)],
       [(3., 3), (4., 4)]], dtype=[('x', '<f8'), ('y', '<i8')])

如果您的目标只是创建一个新数组,那么请查看这个问题的答案。它们涵盖了几种有用的方法,包括numpy.core.records.fromarraysnumpy.core.records.fromrecords。还请参阅保罗·潘泽的答案,其中讨论了如何创建新的记录数组(允许属性访问列的结构化数组)。

票数 1
EN

Stack Overflow用户

发布于 2018-04-30 13:32:52

正如@senderle正确地指出的那样,您很少需要view,但是这里有一个可能的解决方案来实现这个几乎就地只是为了好玩。您需要做的唯一修改就是确保您的类型都是相同大小的。

代码语言:javascript
复制
a = np.arange(25, dtype='<i4').reshape((5,5))
b = a.view(dtype=[('width', '<i4'), ('height', '<i4'), ('depth', '<i4'), ('score', '<f4'), ('auc', '<f4')])
b['score'] = a[:, -2, np.newaxis].astype('<f4')
b['auc'] = a[:, -1, np.newaxis].astype('<f4')

如果我们要做不推荐的事情,您也可以在获得视图之后插入一行b.shape = (5,),以消除a中保留的额外维度,并简化下面的赋值。

这将为您提供一个视图b,它具有所有所需的属性,但当然会搞乱a的内容。

代码语言:javascript
复制
>>> a
array([[         0,          1,          2, 1077936128, 1082130432],
       [         5,          6,          7, 1090519040, 1091567616],
       [        10,         11,         12, 1095761920, 1096810496],
       [        15,         16,         17, 1099956224, 1100480512],
       [        20,         21,         22, 1102577664, 1103101952]])
>>> b
array([[( 0,  1,  2,  3.,  4.)],
       [( 5,  6,  7,  8.,  9.)],
       [(10, 11, 12, 13., 14.)],
       [(15, 16, 17, 18., 19.)],
       [(20, 21, 22, 23., 24.)]],
      dtype=[('width', '<i4'), ('height', '<i4'), ('depth', '<i4'), ('score', '<f4'), ('auc', '<f4')])
票数 2
EN

Stack Overflow用户

发布于 2018-04-30 13:51:41

下面是使用np.rec.fromarrays的解决办法

代码语言:javascript
复制
>>> dtype = [('width', '<i4'), ('height', '<i4'), ('depth', '<i4'), ('score', '<f4'), ('auc', '<f4')]
>>> np.rec.fromarrays(a.T, dtype=dtype)
rec.array([( 0,  1,  2,  3.,  4.), ( 5,  6,  7,  8.,  9.),
           (10, 11, 12, 13., 14.), (15, 16, 17, 18., 19.),
           (20, 21, 22, 23., 24.)],
          dtype=[('width', '<i4'), ('height', '<i4'), ('depth', '<i4'), ('score', '<f4'), ('auc', '<f4')])

这是一个recarray,但如果需要,我们可以转换为ndarray。此外,dtype是np.record,我们需要(视图-)将其转换为void,以获得“干净”的numpy结果。

代码语言:javascript
复制
>>> np.asarray(np.rec.fromarrays(a.T, dtype=dtype)).view(dtype)
array([( 0,  1,  2,  3.,  4.), ( 5,  6,  7,  8.,  9.),
       (10, 11, 12, 13., 14.), (15, 16, 17, 18., 19.),
       (20, 21, 22, 23., 24.)],
      dtype=[('width', '<i4'), ('height', '<i4'), ('depth', '<i4'), ('score', '<f4'), ('auc', '<f4')])
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50100246

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档