我还没有找到numpy
中的关键概念。
我想创建一个三维数组,并使用函数调用的结果填充每个单元格 - 即该函数将使用不同的索引多次调用并返回不同的值。
注意:自撰写此问题以来,文档已更新为更清晰。
我可以用零(或空)创建它,然后使用for循环覆盖每个值,但直接从函数填充它似乎更清晰。
fromfunction
听起来很完美。 Reading the documentation听起来每个单元格会调用一次函数。
但是当我真正尝试的时候......
from numpy import *
def sum_of_indices(x, y, z):
# What type are X, Y and Z ? Expect int or duck-type equivalent.
# Getting 3 individual arrays
print "Value of X is:"
print x
print "Type of X is:", type(x)
return x + y + z
a = fromfunction(sum_of_indices, (2, 2, 2))
我希望得到类似的东西:
Value of X is:
0
Type of X is: int
Value of X is:
1
Type of X is: int
重复4次。
我明白了:
Value of X is:
[[[ 0. 0.]
[ 0. 0.]]
[[ 1. 1.]
[ 1. 1.]]]
[[[ 0. 0.]
[ 1. 1.]]
[[ 0. 0.]
[ 1. 1.]]]
[[[ 0. 1.]
[ 0. 1.]]
[[ 0. 1.]
[ 0. 1.]]]
Type of X is: <type 'numpy.ndarray'>
该函数只被调用一次,并且似乎返回整个数组。
基于对索引函数的多次调用来填充数组的正确方法是什么?
答案 0 :(得分:32)
文档非常在这方面具有误导性。就像你注意到的那样:numpy执行
而不是执行f(0,0), f(0,1), f(1,0), f(1,1)
f([[0., 0.], [1., 1.]], [[0., 1.], [0., 1.]])
当你尝试使用类似lambda i: l[i]
的东西时,使用ndarrays而不是承诺的整数坐标是非常令人沮丧的,其中l
是另一个数组或列表(尽管如此,可能有更好的方法来执行此操作在numpy)。
numpy vectorize
函数解决了这个问题。你在哪里
m = fromfunction(f, shape)
尝试使用
g = vectorize(f)
m = fromfunction(g, shape)
答案 1 :(得分:18)
我显然没有说清楚。我得到的答案fromfunc
实际上正如我的测试代码所示,我已经知道了,因为我的测试代码证明了这一点。
我一直在寻找的答案分为两部分:
fromfunc
文档具有误导性。它可以立即填充整个数组。
注意:自撰写此问题以来,文档已更新为更清晰。
特别是documentation 中的这一行不正确(或者至少是误导性的)
例如,如果
shape
为(2,2),则参数依次为(0,0),(0,1),(1,0),(1,1)。< / p>
没有。如果shape
(即从上下文,到fromfunction
的第二个参数)是(2,2),则参数将是(不是'依次',而是在唯一的调用中):
(array([[ 0., 0.], [ 1., 1.]]), array([[ 0., 1.], [ 0., 1.]]))
文档已更新,目前读取更准确:
使用N个参数调用函数,其中N是形状的等级。每个参数表示沿特定轴变化的阵列的坐标。例如,如果形状是(2,2),那么参数将是数组([[0,0],[1,1]])和数组([[0,1],[0,1]])
(我的简单示例,源自手册中的示例,可能会产生误导,因为+
可以对数组和索引进行操作。这种模糊性是文档不清楚的另一个原因。我想要最终使用的函数不是基于数组的,而是基于单元格的 - 例如,每个值都可以根据索引从URL或数据库中获取,甚至可以从用户输入。)
回到问题 - 我如何从每个元素调用一次的函数填充数组,答案似乎是:
您无法以功能样式执行此操作。
你可以用命令式/迭代式的方式来做 - 即编写嵌套的for循环,并自己管理索引长度。
您也可以将其作为迭代器,但迭代器仍需要跟踪自己的索引。
答案 2 :(得分:4)
我认为你误解了fromfunction
的作用。
来自numpy
source code。
def fromfunction(function, shape, **kwargs):
dtype = kwargs.pop('dtype', float)
args = indices(shape, dtype=dtype)
return function(*args,**kwargs)
其中indices
与meshgrid
相当,其中每个变量都为np.arange(x)
。
>>> side = np.arange(2)
>>> side
array([0, 1])
>>> x,y,z = np.meshgrid(side,side,side)
>>> x
array([[[0, 0],
[1, 1]],
[[0, 0],
[1, 1]]])
>>> x+y+z #Result of your code.
array([[[0, 1],
[1, 2]],
[[1, 2],
[2, 3]]])
答案 3 :(得分:1)
这会给你一个不正确的结果吗? a
应该符合预期(当我测试它时)并且似乎是做你想要的好方法。
>>> a
array([[[ 0., 1.], # 0+0+0, 0+0+1
[ 1., 2.]], # 0+1+0, 0+1+1
[[ 1., 2.], # 1+0+0, 1+0+1
[ 2., 3.]]]) # 1+1+0, 1+1+1
由于fromfunction
适用于输入的数组索引,
你可以看到只需要调用一次。文档没有说清楚,但你可以看到函数是在源代码中的索引数组上调用的(来自numeric.py
):
def fromfunction(function, shape, **kwargs):
. . .
args = indices(shape, dtype=dtype)
return function(*args,**kwargs)
在数组输入上调用 sum_of_indices
,其中每个数组都包含其索引值
尺寸。
array([[[ 0., 0.],
[ 1., 1.]],
[[ 1., 1.],
[ 1., 1.]]])
+
array([[[ 0., 0.],
[ 1., 1.]],
[[ 0., 0.],
[ 1., 1.]]])
+
array([[[ 0., 1.],
[ 0., 1.]],
[[ 0., 1.],
[ 0., 1.]]])
=
array([[[ 1., 1.],
[ 1., 2.]],
[[ 1., 2.],
[ 2., 3.]]])
答案 4 :(得分:0)
以下是我对您的问题的看法:
如克里斯·琼斯(Chris Jones)所述,解决方案的核心是使用np.vectorize
。
# Define your function just like you would
def sum_indices(x, y, z):
return x + y + z
# Then transform it into a vectorized lambda function
f = sum_indices
fv = np.vectorize(f)
如果您现在执行np.fromfunction(fv, (3, 3, 3))
,则会得到以下提示:
array([[[0., 1., 2.],
[1., 2., 3.],
[2., 3., 4.]],
[[1., 2., 3.],
[2., 3., 4.],
[3., 4., 5.]],
[[2., 3., 4.],
[3., 4., 5.],
[4., 5., 6.]]])
这是您想要的吗?
答案 5 :(得分:0)
我认为from函数的大多数示例都使用平方数组有点困惑。
也许查看非正方形数组会有所帮助吗?
def f(x,y):
print(f'x=\n{x}')
print(f'y=\n{y}')
return x+y
z = np.fromfunction(f,(4,3))
print(f'z=\n{z}')
结果:
x=
[[0 0 0]
[1 1 1]
[2 2 2]
[3 3 3]]
y=
[[0 1 2]
[0 1 2]
[0 1 2]
[0 1 2]]
z=
[[0 1 2]
[1 2 3]
[2 3 4]
[3 4 5]]
答案 6 :(得分:0)
如果您将参数 dtype
设置为 int
,您可以获得所需的输出:
a = fromfunction(sum_of_indices, (2, 2, 2), dtype=int)
https://numpy.org/doc/stable/reference/generated/numpy.fromfunction.html