【问题标题】:Different slices give different inequalities for same elements不同的切片对相同的元素给出不同的不等式
【发布时间】:2026-02-09 19:45:02
【问题描述】:
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')。

【问题讨论】:

    标签: python numpy precision


    【解决方案1】:

    正如我所指出的in another answer,numpy 中的类型转换非常复杂,这是您所看到行为的根本原因。该答案中链接的文档清楚地表明,标量(/0d 数组)和 1d 数组在类型转换方面不同,因为后者不被视为逐个值。

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

    >>> (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(f代表C风格的float)和np.dtype('d')(d代表C风格double) 到np.float64(另见np.typename('f')'d' 相同)。

    我在上面的表格中用粗体标出了两个项目:

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

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

    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] 时,您看不到转换步骤,因为结果始终是布尔值。)

    3. 当您执行a[0] > b[0] 时,您会将'f' 标量与'd' 标量进行比较,因此根据上述内容,您将得到'd' 标量。这是(a[0] + b[0]).dtype 告诉我们的。

    所以我相信这一切都与 numpy 中类型转换的怪癖一致。虽然在双精度和单精度中 0.4 的值看起来像是一个不幸的极端情况,但此功能更深入,并且问题作为一个大红色警告,在混合不同的 dtype 时应该非常小心。

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

    【讨论】:

    • 很好的研究!我确实设法让自己对我(现已删除)的答案感到困惑。我看到你到了你的笔记本电脑。你的手机上没有 Pythonista? ;) 我安装过的最好的应用程序!
    • @Ethan 谢谢 :) 几年前我研究了 python 应用程序,但我只发现了一个,而且那个需要可疑的权限。我确定这不是 Pythonista,所以我会调查一下,谢谢!
    • 太好了,谢谢。接受之前的澄清:'f''d' 代表什么?链接阅读就足够了 - 以及如何解释 print_coercion_tables 输出(对我来说看起来就像随机字母)。
    • @OverLordGoldDragon 感谢格式修复!对不起,我是想添加那些字符规格但我忘记了;请在表格下查看我的更新。
    • @AndrasDeak 完美