我需要创建一个接受lambda,尺寸形状和Numpy dtype的函数,并生成一个数组。
我知道有fromfunction
可以做到这一点,但我不能使用它。我猜想看待它的一种方法是,我需要对fromfunction
进行硬编码。我遇到的问题是无法将lambda函数作为其函数传递。香港专业教育学院尝试使用循环和使用索引,我是后一个想法的新手,所以我可能做得不好。基本上我需要创建函数。输入内容与注释中的(预期)结果相同。
import numpy as np
def array_function(f, d, dtype=None):
return x
print(array_function(lambda i,j: (i - j)**2, [4, 4]))
# Expected Result
#[[0. 1. 4. 9.]
# [1. 0. 1. 4.]
# [4. 1. 0. 1.]
# [9. 4. 1. 0.]]
答案 0 :(得分:0)
lambda函数无法传递
lambda函数是一个函数,它是python中的一类对象。将其作为参数传递给另一个函数没有什么麻烦。您可以只看一下或理解这两个维度,然后制作和排列,然后重塑形状:
import numpy as np
def array_function(f, d, dtype=None):
a = np.array([f(i, j) for i in range(d[0]) for j in range(d[1])], dtype)
return a.reshape(d)
print(array_function(lambda i,j: (i - j)**2, [4, 4]))
结果:
[[0 1 4 9]
[1 0 1 4]
[4 1 0 1]
[9 4 1 0]]
如果您想让array_function
接受任意大小的数组,会有些棘手。一种选择是使数组具有大小,然后枚举所有元素以调用该函数:
import numpy as np
def array_function(f, d, dtype=None):
a = np.zeros(d)
for coord, val in np.ndenumerate(a):
a[coord] = f(*coord)
return a
# three dimensions
print(array_function(lambda i,j, k: k+(i - j)**2, [4, 5,2], np.float))
基于评论进行编辑
您可以使用itertools中的starmap
和product
构建一个迭代器。我不确定迭代器会用numpy为您带来很多收益,因为您通常想在创建时知道数组的大小。您可以传递一个长度,这不是必需的,但是可以提高性能:
from itertools import product, starmap
import numpy as np
from operator import mul
from functools import reduce
def array_function(f, d, dtype=None):
length = reduce(mul, d)
iterator = starmap(f, product(*[range(x) for x in d]))
a = np.fromiter(iterator, dtype, length)
return a.reshape(d)
print(array_function(lambda i,j: (i - j)**2, [4, 4], np.float))
答案 1 :(得分:0)
如何从np.ufunc
创建一个lambda
并使用reduce
将其应用于多个维度?
from functools import reduce
import numpy as np
def apply(f, shape, dtype=None):
ufunc = np.frompyfunc(f, 2, 1)
ranges = (np.arange(dim) for dim in shape)
return reduce(ufunc.outer, ranges).astype(dtype)
print(apply(lambda i, j: (i - j) ** 2, (4, 4)))
输出:
[[0. 1. 4. 9.]
[1. 0. 1. 4.]
[4. 1. 0. 1.]
[9. 4. 1. 0.]]
答案 2 :(得分:0)
为此lambda
,fromfunction
可以正常工作:
In [1]: foo = lambda i,j: (i-j)**2
In [2]: np.fromfunction(foo,(4,4))
Out[2]:
array([[0., 1., 4., 9.],
[1., 0., 1., 4.],
[4., 1., 0., 1.],
[9., 4., 1., 0.]])
fromfunction
根据形状生成索引的“网格”:
In [7]: np.indices((4,4))
Out[7]:
array([[[0, 0, 0, 0],
[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3]],
[[0, 1, 2, 3],
[0, 1, 2, 3],
[0, 1, 2, 3],
[0, 1, 2, 3]]])
并将两个平面(第一维)传递给您的函数。正如您所写,您的函数可用于这些二维网格等数组。 meshgrid
和mgrid
(和ogrid
)生成相似的索引。
但是我也可以直接创建两个数组,然后将它们传递给foo
:
In [8]: foo(np.arange(4)[:,None], np.arange(4))
Out[8]:
array([[0, 1, 4, 9],
[1, 0, 1, 4],
[4, 1, 0, 1],
[9, 4, 1, 0]])
这两个输入数组彼此广播,就像Out[7]
中的两个平面一样。实际上,它们是(4,1)和(4)形状的等价物。
请注意,在Python中,lambda
只是一个匿名函数。在这里,我将其分配给一个变量,并给出了一个名称。也可以使用def
函数。
只要您的函数可以使用所需的2d索引数组,就不需要任何特殊的编码。
如果该函数仅适用于i
和j
的标量值,则您必须求助于Python级别的迭代操作(与使用已编译的numpy
函数相反)
列表理解版本:
In [6]: np.array([[foo(i,j) for j in range(4)] for i in range(4)])
Out[6]:
array([[0, 1, 4, 9],
[1, 0, 1, 4],
[4, 1, 0, 1],
[9, 4, 1, 0]])
我更喜欢frompyfunc
,它将用作:
In [9]: f = np.frompyfunc(foo, 2,1)
In [10]: f(np.arange(4)[:,None], np.arange(4))
Out[10]:
array([[0, 1, 4, 9],
[1, 0, 1, 4],
[4, 1, 0, 1],
[9, 4, 1, 0]], dtype=object)
请注意,它返回一个对象dtype。可以使用astype
进行修改。如果您太懒惰以至于无法编写自己的可广播fromfunction
和I
数组,也可以将其传递给J
。
根据我的经验,frompyfunc
方法比列表理解要快一些(最多约2倍)。另一方面,如果foo
与[8]中的数组一起使用,则速度比更像是10倍。因此,如果您可以编写适用于整个数组而不是标量索引的函数,那么就性能而言,您将最幸福。