对于相同的元素,不同的切片给出了不同的不等式

2022-04-10 00:00:00 python numpy precision

问题描述

import numpy as np

a = np.array([.4], dtype='float32')
b = np.array([.4, .6])

print(a > b)
print(a > b[0], a > b[1])
print(a[0] > b[0], a[0] > b[1])
[ True False]
[False] [False]
True False

这是怎么回事?是的,b.dtype == 'float64',但其切片b[0]&;b[1]a剩余'float32'

注意:我是问为什么会发生这种情况,而不是问如何规避它,我知道这一点(例如,将两者都转换为'float64')。


解决方案

正如我已经提到的in another answer,NumPy中的类型转换相当复杂,这是您看到的行为的根本原因。答案中链接的文档清楚地表明,标量(/0d数组)和一维数组在类型转换方面不同,因为后者不被视为逐值计算。

您已经知道问题的前半部分:问题是两种情况下类型转换的方式不同:

>>> (a + b).dtype
dtype('float64')

>>> (a + b[0]).dtype
dtype('float32')

>>> (a[0] + b[0]).dtype
dtype('float64')

如果我们考虑类型转换表,我相信我们可以理解您的示例中发生的事情:

>>> from numpy.testing import print_coercion_tables
can cast
[...]

In these tables, ValueError is '!', OverflowError is '@', TypeError is '#'

scalar + scalar
+ ? b h i l q p B H I L Q P e f d g F D G S U V O M m 
? ? b h i l q l B H I L Q L e f d g F D G # # # O ! m 
b b b h i l q l h i l d d d e f d g F D G # # # O ! m 
h h h h i l q l h i l d d d f f d g F D G # # # O ! m 
i i i i i l q l i i l d d d d d d g D D G # # # O ! m 
l l l l l l q l l l l d d d d d d g D D G # # # O ! m 
q q q q q q q q q q q d d d d d d g D D G # # # O ! m 
p l l l l l q l l l l d d d d d d g D D G # # # O ! m 
B B h h i l q l B H I L Q L e f d g F D G # # # O ! m 
H H i i i l q l H H I L Q L f f d g F D G # # # O ! m 
I I l l l l q l I I I L Q L d d d g D D G # # # O ! m 
L L d d d d d d L L L L Q L d d d g D D G # # # O ! m 
Q Q d d d d d d Q Q Q Q Q Q d d d g D D G # # # O ! m 
P L d d d d d d L L L L Q L d d d g D D G # # # O ! m 
e e e f d d d d e f d d d d e f d g F D G # # # O ! # 
f f f f d d d d f f d d d d f f d g F D G # # # O ! # 
d d d d d d d d d d d d d d d d d g D D G # # # O ! # 
g g g g g g g g g g g g g g g g g g G G G # # # O ! # 
F F F F D D D D F F D D D D F F D G F D G # # # O ! # 
D D D D D D D D D D D D D D D D D G D D G # # # O ! # 
G G G G G G G G G G G G G G G G G G G G G # # # O ! # 
S # # # # # # # # # # # # # # # # # # # # # # # O ! # 
U # # # # # # # # # # # # # # # # # # # # # # # O ! # 
V # # # # # # # # # # # # # # # # # # # # # # # O ! # 
O O O O O O O O O O O O O O O O O O O O O O O O O ! # 
M ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! 
m m m m m m m m m m m m m m # # # # # # # # # # # ! m 

scalar + neg scalar
[...]

array + scalar
+ ? b h i l q p B H I L Q P e f d g F D G S U V O M m 
? ? b h i l q l B H I L Q L e f d g F D G # # # O ! m 
b b b b b b b b b b b b b b e f d g F D G # # # O ! m 
h h h h h h h h h h h h h h f f d g F D G # # # O ! m 
i i i i i i i i i i i i i i d d d g D D G # # # O ! m 
l l l l l l l l l l l l l l d d d g D D G # # # O ! m 
q q q q q q q q q q q q q q d d d g D D G # # # O ! m 
p l l l l l l l l l l l l l d d d g D D G # # # O ! m 
B B B B B B B B B B B B B B e f d g F D G # # # O ! m 
H H H H H H H H H H H H H H f f d g F D G # # # O ! m 
I I I I I I I I I I I I I I d d d g D D G # # # O ! m 
L L L L L L L L L L L L L L d d d g D D G # # # O ! m 
Q Q Q Q Q Q Q Q Q Q Q Q Q Q d d d g D D G # # # O ! m 
P L L L L L L L L L L L L L d d d g D D G # # # O ! m 
e e e e e e e e e e e e e e e e e e F F F # # # O ! # 
f f f f f f f f f f f f f f f f f f F F F # # # O ! # 
d d d d d d d d d d d d d d d d d d D D D # # # O ! # 
g g g g g g g g g g g g g g g g g g G G G # # # O ! # 
F F F F F F F F F F F F F F F F F F F F F # # # O ! # 
D D D D D D D D D D D D D D D D D D D D D # # # O ! # 
G G G G G G G G G G G G G G G G G G G G G # # # O ! # 
S # # # # # # # # # # # # # # # # # # # # # # # O ! # 
U # # # # # # # # # # # # # # # # # # # # # # # O ! # 
V # # # # # # # # # # # # # # # # # # # # # # # O ! # 
O O O O O O O O O O O O O O O O O O O O O O O O O ! # 
M ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! 
m m m m m m m m m m m m m m # # # # # # # # # # # ! m

[...]
以上是基于价值的促销的当前促销表的一部分。它表示在将给定类型的两个NumPy对象配对时,不同类型对结果类型的贡献(有关特定类型,请参阅第一列和第一行)。类型按照single-character dtype specifications(以下一字符串)来理解,特别是np.dtype('f')对应np.float32(对于C样式的浮点类型为f)和np.dtype('d')(对于C样式的双精度类型为d)到np.float64(另见np.typename('f')'d'相同)。

我在上表中注意到两项黑体:

标量f+标量d-->;d
数组f+标量d-->;f

现在让我们看看你的案例。前提是您有一个'f'数组a和一个'd'数组ba只有一个元素这一事实并不重要:它是长度为1的一维数组,而不是0维数组。

  1. 当您执行a > b时,您是在比较两个数组,上面的表中没有表示这一点。我不确定这里的行为是什么;我猜测a被广播到b的形状,然后它的类型被转换为'd'。我认为这是因为np.can_cast(a, np.float64)Truenp.can_cast(b, np.float32)False。但这只是一个猜测,NumPy中的许多机制对我来说并不直观。

  2. 当您执行a > b[0]时,您是在将'f'数组与'd'标量进行比较,因此根据上面的说明,您将得到'f'数组。这就是(a + b[0]).dtype告诉我们的。(当您使用a > b[0]时,您看不到转换步骤,因为结果始终是bool。)

  3. 当您执行a[0] > b[0]操作时,您是在将'f'标量与'd'标量进行比较,因此根据上面的说明,您将得到一个'd'标量。这是(a[0] + b[0]).dtype告诉我们的。

所以我认为这与NumPy中类型转换的怪癖是一致的。虽然它可能看起来像是双精度和单精度的0.4值的不幸的转折点,但该功能更深入,该问题充当一个红色大警告,提示您在混合不同的数据类型时应该非常小心。

最安全的做法是自己转换类型,以便控制代码中发生的事情。尤其是因为有关于重新考虑类型提升的某些方面的讨论。

相关文章