【发布时间】:2020-11-09 07:25:47
【问题描述】:
简介
我有一个可矢量化的函数func,我使用np.frompyfunc 对其进行矢量化。我不想使用嵌套的for 循环,而是只想调用一次,因此我需要用np.newaxis 填充输入。
我的目标是摆脱两个嵌套的for 循环并改用numpy.array 广播功能。
这是 MWE for 循环(我想摆脱 for 循环,而是在调用 @987654333 时填充变量 c_0、c_1、rn_1、rn_2 和 factor @。
感兴趣问题的 MWE
for i, b_0 in enumerate(b_00):
for j, b_1 in enumerate(b_11):
factor = b_0 + b_1
rn = (b_0 * coord + b_1 * coord2) / factor
rn_1 = coord - rn
rn_2 = coord2 - rn
results = np.add( results,np.prod(myfunc(c_0[:,None,:], c_1[None,:,:], rn_1, rn_2, factor), axis=2) )
上面显式的for循环是正确的,为了质量保证,包含在块代码中。
我目前的努力
factor = b_00[:, None] + b_11[None, :]
rn = np.add( (b_00[:,None] * coord[None,:])[:, None, :], (b_11[:,None] * coord2[None,:])[None, :, :] ) / factor[:,:,None]
rn_1 = coord - rn
rn_2 = coord2 - rn
results2 = np.prod(myfunc(c_0[:,None,:, None, None], c_1[None,:,:, None, None], rn_1[:,:,:],rn_2[:,:, :], factor[None,:, :, None]), axis=2)
results2 = np.squeeze(results2)
results2 = np.sum(results2, axis=(2,3))
单体代码块
import numpy as np
myfunc = np.frompyfunc(func,5,1)
################################################################
# Prep arrays needed for MWE
################################################################
results = np.zeros((5,3))
coord = np.array([1,1,2])
coord2 = np.array([3,3,3])
c_0 = np.array([[0,0,2],[0,2,0],[2,0,0],[1,1,0], [1,0,1]])
c_1 = np.array([[0,0,2],[0,2,0],[2,0,0]])
b_00 = np.array([2.2, 1.1, 4.4]) # np.array([2.2, 3.3, 40.4])
b_11 = np.array([1.2, 3.3]) # np.array([1.2, 5.3])
################################################################
# This is only for comparison. `results` is the correct answer
################################################################
for i, b_0 in enumerate(b_00):
for j, b_1 in enumerate(b_11):
factor = b_0 + b_1
rn = (b_0 * coord + b_1 * coord2) / factor
rn_1 = coord - rn
rn_2 = coord2 - rn
results = np.add( results,np.prod(myfunc(c_0[:,None,:], c_1[None,:,:], rn_1, rn_2, factor), axis=2) )
################################################################
# Prep for broadcasting (My attempt)
################################################################
factor = b_00[:, None] + b_11[None, :]
rn = np.add( (b_00[:,None] * coord[None,:])[:, None, :], (b_11[:,None] * coord2[None,:])[None, :, :] ) / factor[:,:,None]
rn_1 = coord - rn
rn_2 = coord2 - rn
# The following all get the same *wrong* answer
# results2 = np.prod(myfunc(c_0[:,None,:,None, None], c_1[None,:,:, None, None], rn_1[:, None, None],rn_2[:,None, None], factor[None,:, :]), axis=2)
# results2 = np.prod(myfunc(c_0[:,None,:, None, None, None], c_1[None,:,:, None, None, None], rn_1[None, None,:,:,:, None],rn_2[None, None,:,:, :, None], factor[None,:, :, None, None]), axis=2)
# results2 = np.prod(myfunc(c_0[:,None,:, None, None], c_1[None,:,:, None, None], rn_1[None, None,:,:,:],rn_2[None, None,:,:, :], factor[None,:, :, None]), axis=2)
# this should be the only line needing work!
results2 = np.prod(myfunc(c_0[:,None,:, None, None], c_1[None,:,:, None, None], rn_1[:,:,:],rn_2[:,:, :], factor[None,:, :, None]), axis=2)
results2 = np.squeeze(results2)
results2 = np.sum(results2, axis=(2,3))
assert np.allclose(results, results2)
# Vectorized function to be sent broadcasted arrays
def func(r0, r1, x, y, at):
val = 0.0
for i in range(r0+1):
for j in range(r1+1):
val += x + i*j + at * y
return val
问题
- 通过上面的代码,我得到了结果数组的正确形状(
results2是我尝试广播,results是给出正确答案的慢 for 循环),但它的值错误。 - 正如
@hpaulj指出的那样,如果我将b_00的尺寸更改为长度4(或任何更大的长度),我的解决方案甚至无法获得正确的形状。
更新
请确保它适用于当前的b_00 = np.array([2.2, 1.1, 4.4]) 以及更通用的b_00 = np.array([2.2, 1.1, 4.4, 5.1, 6.2])。我想要一个广播解决方案,但会接受一个比for loops 更快的解决方案。
【问题讨论】:
-
我喜欢尽可能使用不同的尺寸。它使检测缺陷更容易。例如
arr=np.arange(24).reshape(2,3,4) -
@hpaulj 这是一个很好的电话。我整晚都在看这个。当我将 b_00 长度设为 4 时会出现错误。我将继续跟进。谢谢。
-
对不起,我读了你的帖子,我没有看到问题。什么是错误,你想做什么?
-
什么是函数?你也能过去吗?
-
@Dorian 就在那里,func 定义在底部
标签: python python-3.x numpy vectorization array-broadcasting