Python 一个涉及到填充物放置位置的广播问题 介绍
我有一个可向量化的函数Python 一个涉及到填充物放置位置的广播问题 介绍,python,python-3.x,numpy,vectorization,array-broadcasting,Python,Python 3.x,Numpy,Vectorization,Array Broadcasting,我有一个可向量化的函数func,我使用np.frompyfunc对其进行向量化。我不想对循环使用嵌套的,我只想调用它一次,因此我需要用np.newaxis填充输入 我的目标是摆脱两个嵌套的for循环,改用numpy.array广播功能 这里是MWEfor循环(我想去掉for循环,而是在调用myfunc时填充变量c_0,c_1,rn_1,rn_2,以及因子) 利益问题的解决 上述显式for循环是正确的,并包含在质量保证的块代码中 我目前的努力 单片代码块 问题 通过上面的代码,我得到了结果数组的正
func
,我使用np.frompyfunc
对其进行向量化。我不想对循环使用嵌套的,我只想调用它一次,因此我需要用np.newaxis
填充输入
我的目标是摆脱两个嵌套的for
循环,改用numpy.array
广播功能
这里是MWEfor
循环(我想去掉for循环,而是在调用myfunc
时填充变量c_0
,c_1
,rn_1
,rn_2
,以及因子
)
利益问题的解决
上述显式for循环是正确的,并包含在质量保证的块代码中
我目前的努力
单片代码块
问题
通过上面的代码,我得到了结果数组的正确形状(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循环更快的解决方案
#Definitions
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])
#Vectorized code for prep
b_0 = np.outer(b_00, coord)
b_1 = np.outer(b_11, coord2)
factor = (b_00+b_11.reshape(-1,1)).T[:,:,None]
rn = np.divide((b_0[:,None]+b_1), factor)
rn_1 = coord-rn
rn_2 = coord2-rn
#THIS IS YOUR INTERESTING PART
results = np.prod(myfunc(c_0[:,None,:,None,None], c_1[None,:,:,None,None], rn_1.transpose(2,0,1), rn_2.transpose(2,0,1), factor.transpose(2,0,1)).transpose(3,4,0,1,2), axis=4)
results = np.add.reduce(results, axis=(0,1))
results
出于理解目的,因为在旧的循环解决方案中,myfunc在rn_1和rn_2的第一个轴上运行,广播频道需要是最后2个,而不是第一个。因此,我在c_0和c_1的末尾添加了2个频道,然后我将最后一个轴带到前面,使(3,2,3)rn_1变成(3,3,2).与因子类似。因此,现在myfunc可以在突出显示广播频道的张量上运行-
(5,1,3,1,1),(1,3,3,1,1),(3,3,2),(1,3,2)
最后,我再次转置,将广播的频道放在前面,这样我们就有了一个(3,2,5,3,3)形状的张量,其中前两个频道是3,2嵌套循环的广播版本,5,3,3是现在需要在轴=4而不是轴=2上np.prod的矩阵
在此之后,只需使用np.add.reduce对0,1轴求和即可将结果转换为5,3矩阵。最终结果应与循环结果完全相同
我有点冒昧地修改了第一部分,因为这对我的眼睛来说更舒服,但是可以忽略这一部分
PS.检查您提到的示例是否可以无缝工作
b_00 = np.array([2.2, 1.1, 4.4, 5.1, 6.2])
我喜欢在可能的情况下使用不同的尺寸。这样可以更容易地检测缺陷。例如,arr=np.arange(24)。重塑(2,3,4)
@hpaulj这是一个很好的决定。我整晚都在看这个问题。当我把b_00长度定为4时,它出现了一个错误。我会跟进这个线索。谢谢。对不起,我读了你的帖子,我看不到这个问题。错误是什么,你想做什么?func是什么?你能过那个吗?@Dorian都在那里,func是在机器人上定义的汤姆
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
#Definitions
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])
#Vectorized code for prep
b_0 = np.outer(b_00, coord)
b_1 = np.outer(b_11, coord2)
factor = (b_00+b_11.reshape(-1,1)).T[:,:,None]
rn = np.divide((b_0[:,None]+b_1), factor)
rn_1 = coord-rn
rn_2 = coord2-rn
#THIS IS YOUR INTERESTING PART
results = np.prod(myfunc(c_0[:,None,:,None,None], c_1[None,:,:,None,None], rn_1.transpose(2,0,1), rn_2.transpose(2,0,1), factor.transpose(2,0,1)).transpose(3,4,0,1,2), axis=4)
results = np.add.reduce(results, axis=(0,1))
results
array([[6707.793061061082, 5277.838468285241, 5277.838468285241],
[5277.838468285241, 5992.8157646731615, 5277.838468285241],
[5277.838468285241, 5277.838468285241, 5992.8157646731615],
[7037.117957713655, 7513.7694886389345, 7513.7694886389345],
[7990.421019564216, 7037.117957713655, 7513.7694886389345]],
dtype=object)
b_00 = np.array([2.2, 1.1, 4.4, 5.1, 6.2])