numpy 在np.fromfunction()中使用多个逻辑条件

kt06eoxx  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(79)

我对编程比较陌生。作为一名物理老师,我正在努力学习Python,因为我不想给孩子们上编码入门课。目前我正在学习数组。作为我自己的一个实践,我尝试用np.fromfunction()创建levi-Cita-tensor。它似乎不接受一个以上的逻辑条件,这个问题可能与数组和列表的不同性质有关,但我不明白到底出了什么问题。
我写了一个函数来检查两个或三个索引是否相同(返回0),如果不是,则索引是循环的(返回1)还是反循环的(返回-1)。当使用np.fromfunction()中的函数时,我得到:
ValueError:具有多个元素的数组的真值是不明确的。使用.any()或a.all()
而不是无聊的人在这个网站上与我可能不那么优雅的书面功能;)我尝试了一个更简单的命令来测试np.fromfunction()中逻辑条件的使用:

np.fromfunction(lambda i, j, k: i == j, (3,3,3), dtype=int)

它返回一个带有布尔数据的数组
但如果我使用两个逻辑条件,例如:

np.fromfunction(lambda i, j, k: i==j or j==k, (3,3,3), dtype=int)

我得到的valueError和我原来的函数一样。我可能没有正确理解矢量化的概念。在我对这个过程的理解中,计算机从位置i=0,j=0,k=0开始,执行两个逻辑条件,en返回位置i=0,j=0,k=0的真值。它似乎只对一个逻辑条件起作用,为什么不对两个(或更多)逻辑条件起作用呢?

mw3dktmi

mw3dktmi1#

您好,欢迎来到网站!谢谢你的深思熟虑的问题!
不幸的是,这些文档(在我看来)对np.fromfunction来说并不是很好。我认为我们都期望的是,它是这样实现的:

arr = np.empty(shape)
for i, j, k in indices:
    arr[i, j, k] = your_func(i, j, k)

这意味着your_func的执行次数与索引的三元组一样多。
然而,查看源代码,它的实现更像是:

i, j, k = np.indices(shape)
arr = your_func(i, j, k)

这意味着your_func只被调用一次,不是用标量,而是用每个ijk填充的Tensor。那看起来像什么?使用print尝试np.fromfunction

>>> np.fromfunction(lambda i, j, k: print(f"{i!r}\n{j!r}\n{k!r}"), (3, 3, 3), dtype=int)
array([[[0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]],

       [[1, 1, 1],
        [1, 1, 1],
        [1, 1, 1]],

       [[2, 2, 2],
        [2, 2, 2],
        [2, 2, 2]]])
array([[[0, 0, 0],
        [1, 1, 1],
        [2, 2, 2]],

       [[0, 0, 0],
        [1, 1, 1],
        [2, 2, 2]],

       [[0, 0, 0],
        [1, 1, 1],
        [2, 2, 2]]])
array([[[0, 1, 2],
        [0, 1, 2],
        [0, 1, 2]],

       [[0, 1, 2],
        [0, 1, 2],
        [0, 1, 2]],

       [[0, 1, 2],
        [0, 1, 2],
        [0, 1, 2]]])

这就是np.indices返回的数组。
因此,np.fromfunction的输入函数需要能够处理整个数组作为输入,而or-ing两个数组不起作用!
我建议远离np.fromfunction,即使你设法向量化你的代码。相反,您可以使用broadcasting(提示:直接使用sparse=True),使您的代码更好。
相反,你也可以遍历所有的索引,并像在初始伪代码中那样多次调用你的函数!
为什么我们不能or两个numpy数组?
这是由于Python的限制。当你写a or b时,python会检查a是否是“Truthy”(即通过调用bool(a)),然后如果检查是True,则返回a,否则返回b。这种行为被称为短路,并可能导致some useful tricks
因此,当ab是numpy数组时,python在a上调用bool,numpy响应数组的真值(或“truthyness”)是不明确的。这是有意义的,因为应该如何处理一个同时填充了TrueFalse的数组?;)
值得庆幸的是,numpy实现了一个函数(np.logical_or)来复制所需的行为。对于布尔数组,“按位或”运算符|也是这样工作的。但是由于运算符优先级的原因,你必须注意在表达式中加上括号,就像hpaulj在他的评论中所做的那样。
希望这对你有帮助!

omhiaaxx

omhiaaxx2#

为'[numpy] fromfunction'搜索SO表明这个函数已经被误解了很长一段时间。我怀疑这更多的是一个一厢情愿的问题,而不是文档本身。源代码是令人难以置信的简单,远远短于文档,旧的或重写,暗示。
它所做的就是生成一些索引数组,并将它们传递给你的函数。没有神奇的“矢量化”或逐个单元的迭代。这个动作,如果有的话,必须内置到你自己的函数中。
indices创建一个数组:

In [94]: np.indices((2,3))
Out[94]: 
array([[[0, 0, 0],
        [1, 1, 1]],

       [[0, 1, 2],
        [0, 1, 2]]])

可以使用meshgridmgrid
让我们把这个数组解压缩成两个(基本的python功能):

In [95]: I,J = np.indices((2,3))
In [96]: I,J
Out[96]: 
(array([[0, 0, 0],
        [1, 1, 1]]),
 array([[0, 1, 2],
        [0, 1, 2]]))

所以我们现在有两个(或者在你的例子3中)数组。我们可以用这些来做各种计算。请参阅numpy基础文档以获得一些想法。
例如,我们可以做I+J。但根据你的情况,我们可以比较一下:

In [97]: I==J
Out[97]: 
array([[ True, False, False],
       [False,  True, False]])

结果是相同形状的布尔数组。这种逐元素比较的能力内置于numpy数组的编译方法中。在这里,它们在形状上是匹配的,但是broadcasting增加了一些魔力,允许我们在一定范围内处理不同形状的数组。
但是如果我尝试使用2个测试,我会得到'ambiguity'错误:

In [98]: I==J or J>0
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[98], line 1
----> 1 I==J or J>0

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

这是一个独立于fromfunction的问题,尽管相当常见。当我们试图在python上下文中使用需要标量布尔值的数组时,就会得到这样一个错误。if子句是一个经典的例子,但这里是or-它有一个试图短路的底层if
我们需要做的是使用()来控制精度,|来执行元素逻辑运算。

In [99]: (I==J) | (J>0)
Out[99]: 
array([[ True,  True,  True],
       [False,  True,  True]])

在好的numpy代码中,我们尝试使用编译后的方法来处理整个数组。这可能需要思维的转变。所以当我们想做一些只能用标量表示的事情时
用这些术语来思考:在[100]中:def foo(i,j):...:if(j>0)or(i==j):.:return True.:else:.:return False.:
使用nest list comprehension:

In [101]: [[foo(i,j) for j in range(3)] for i in range(2)]
Out[101]: [[True, True, True], [False, True, True]]

尝试将我们的indices数组应用于此函数会产生模糊性错误:

In [102]: foo(I,J)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[102], line 1
----> 1 foo(I,J)

Cell In[100], line 2, in foo(i, j)
      1 def foo(i,j):
----> 2        if (j>0) or (i==j):
      3            return True
      4        else:

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

有一个函数可以将数组应用于这样的标量函数,尽管我有点犹豫要不要演示它,因为它也经常被误用,

In [103]: np.vectorize(foo, otypes=[bool])(I,J)
Out[103]: 
array([[ True,  True,  True],
       [False,  True,  True]])

它的文档,包括一个性能免责声明,是一个有点清楚。
对不起,这比我预期的要长得多,但希望这里有一些有用的东西。

相关问题