Ove*_*gon 5 python precision numpy
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])
Run Code Online (Sandbox Code Playgroud)
[ True False]
[False] [False]
True False
Run Code Online (Sandbox Code Playgroud)
这是怎么回事?是的,b.dtype == 'float64'但是它的切片b[0]&b[1]和a仍然是'float32'。
注意:我问的是为什么会发生这种情况,而不是如何规避它,我知道(例如将两者都转换为'float64')。
正如我在另一个答案中指出的,numpy 中的类型转换非常复杂,这是您所看到的行为的根本原因。该答案中链接的文档清楚地表明,标量(/0d 数组)和 1d 数组在类型转换方面有所不同,因为后者不被视为逐个值。
您已经知道问题的前半部分:问题是类型转换对于您的两种情况发生的方式不同:
>>> (a + b).dtype
dtype('float64')
>>> (a + b[0]).dtype
dtype('float32')
>>> (a[0] + b[0]).dtype
dtype('float64')
Run Code Online (Sandbox Code Playgroud)
还有一个名为的帮助程序numpy.result_type()可以告诉您相同的信息,而无需执行二进制运算:
>>> np.result_type(a, b)
dtype('float64')
>>> np.result_type(a, b[0])
dtype('float32')
>>> np.result_type(a[0], b[0])
dtype('float64')
Run Code Online (Sandbox Code Playgroud)
我相信,如果我们考虑类型转换表,我们就可以理解您的示例中发生的情况:
>>> 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
[...]
Run Code Online (Sandbox Code Playgroud)
以上是目前基于价值的促销的促销表的一部分。它表示在配对给定类型的两个 numpy 对象时,不同类型如何影响结果类型(有关特定类型,请参阅第一列和第一行)。这些类型应根据单字符 dtype 规范(“单字符字符串”下方)来理解,特别np.dtype('f')是对应于np.float32(f 表示 C 样式 float)和np.dtype('d')(d 表示 C 样式 double)np.float64(另请参见np.typename('f')和与 ) 相同'd'。
我在上表中以黑体字注明了两项:
标量 f + 标量 d --> d
数组 f + 标量 d --> f
现在让我们看看您的案例。前提是你有一个'f'数组a和一个'd'数组b。事实上,a只有一个元素并不重要:它是一个长度为 1 的 1d 数组,而不是 0d 数组。
当您a > b比较两个数组时,上表中没有指出这一点。我不确定这里的行为是什么;我的猜测是,它a被广播为bs 形状,然后其类型被转换为'd'. 我认为这是因为现在np.can_cast(a, np.float64)和True现在np.can_cast(b, np.float32)都是False。但这只是一个猜测,numpy 中的很多机制对我来说并不直观。
当您这样做时,a > b[0]您正在将'f'数组与'd'标量进行比较,因此根据上面的内容您会得到一个'f'数组。这就是(a + b[0]).dtype告诉我们的。(当您使用时,a > b[0]您看不到转换步骤,因为结果始终是布尔值。)
当您这样做时,a[0] > b[0]您正在将'f'标量与'd'标量进行比较,因此根据上面的内容您会得到一个'd'标量。这就是(a[0] + b[0]).dtype告诉我们的。
所以我相信这与 numpy 中类型转换的怪癖是一致的。虽然它看起来像是一个不幸的极端情况,其值为0.4双精度和单精度,但此功能更深入,该问题充当一个大红色警告,表明您在混合不同的数据类型时应该非常小心。
最安全的做法是自己转换类型,以控制代码中发生的情况。特别是因为有关于重新考虑类型提升的某些方面的讨论。
作为旁注(目前),2021 年 5 月创建了一个正在进行中的NEP 50,它解释了当涉及标量时类型提升可能会多么令人困惑,并计划最终简化一些规则。由于这还涉及重大更改,因此它在 NumPy 中的实现不会一蹴而就。