numpy 不同的切片对相同的元素给予不同的不等式

fumotvh3  于 2022-11-23  发布在  其他
关注(0)|答案(1)|浏览(143)

第一个
这是怎么回事?是的,b.dtype == 'float64',但它的切片b[0]b[1]也是,a仍然是'float32'

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

w46czmvw1#

正如我所提到的in another answer,numpy中的类型转换是相当复杂的,这也是你所看到的行为的根本原因。答案中链接的文档清楚地表明标量(/0 d数组)和1d数组在类型转换上是不同的,因为后者不是逐值的。
问题的前半部分你已经知道了:问题是类型转换在两种情况下发生的不同:

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

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

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

还有一个名为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')

我相信,如果我们考虑一下类型转换表,就能理解示例中发生的情况:

>>> 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对象进行配对时,不同的类型对结果类型的贡献(具体类型见第一列第一行)。这些类型应根据单字符数据类型规范来理解。(在“单字符字符串”下面),特别是np.dtype('f')对应于np.float32(f表示C样式浮点数),np.dtype('d')(d表示C样式双精度数)对应于np.float64(另见np.typename('f')'d')。
我在上表中用黑体字标出了两项:
标量f +标量d --〉d
数组f +标量d --〉f
现在让我们看看你的例子。假设你有一个'f'数组a和一个'd'数组b。事实上a只有一个元素并不重要:它是长度为1的1d数组而不是0 d数组。
1.当你做a > b的时候,你是在比较两个数组,这在上面的表格中没有说明。我的猜测是a被广播到b的形状,然后它的类型被转换为'd'。我认为这是因为np.can_cast(a, np.float64)Truenp.can_cast(b, np.float32)False。但这只是一个猜测,numpy中的许多机制对我来说并不直观。
1.当你执行a > b[0]时,你是在比较'f'数组和'd'标量,所以根据上面的内容,你会得到一个'f'数组。这就是(a + b[0]).dtype告诉我们的。(当你使用a > b[0]时,你看不到转换步骤,因为结果总是一个bool。)
1.当你做a[0] > b[0]的时候,你是在比较'f'标量和'd'标量,所以根据上面的,你得到了一个'd'标量,这就是(a[0] + b[0]).dtype告诉我们的。
所以我相信这与numpy中类型转换的怪癖是一致的。虽然双精度和单精度的0.4值看起来像是一个不幸的角落,但这个特性更深入,这个问题是一个红色的警告,警告你在混合不同的dtype时应该非常小心。
最安全的做法是自己转换类型,以便控制代码中发生的事情,特别是在讨论重新考虑类型提升的某些方面时。
顺便提一句(目前),2021年5月创建的一个正在进行中的NEP 50解释了当涉及标量时类型提升是多么令人困惑,并计划最终简化一些规则。由于这也涉及到突破性的变化,它在NumPy中的实现不会在一夜之间发生。

相关问题