在 numpy 或 python 中将一个向量广播到另一个不同大小的向量
Broadcasting a vector into another vector of different size in numpy or python
我有 Np
links(管道)和 Nj
连接点(节点)。每个linkk
都有一个起始节点i
和结束节点j
,以及一个link值为b
。如果给定节点是 link 的起始节点,我想通过添加 b
来计算 links 对每个节点的贡献,如果给定节点减去 b
是一个link的结尾。我的代码是这样的:
for k in range(Np): #iterate over pipes
F[i[k]]=F[i[k]]+b[k] #add value of b if pipe k is at the start of the node
F[j[k]]=F[j[k]]-b[k] #substract b if pipe k is at the end of the node
用于运行此代码的数据示例:
Np=7 #number of pipes
Nj=6 #number of junctions (nodes)
pipe=[0,1,2,3,4,5,6] #number of pipes are consecutive, k=0:Np
i=[0,1,2,3,3,3,0] #number of start node for each pipe, 0<=i<Nj
j=[1,5,1,1,2,4,5] #number of end node for each pipe, 0<=j<Nj
b=[1.3,0.5,1.5,2.7,1.5,2.2,3.1] #value for each pipe, Np elements
node=[0,1,2,3,4,5] #node numbers are consecutive, 0:Nj
F=np.zeros(Nj) #intializing F, size is equal to number of nodes
循环的结果是:
F=[+1.3+3.1,+0.5-1.3-1.5-2.7,+1.5-1.5,+2.7+1.5+2.2,-2.2,-0.5-3.1]
或
F=[4.4, -5.0, 0.0, 6.4, -2.2, -3.6]
在我自己的管网中,我有 Nj=150628 和 Np=157040,所以我创建的循环花费了太多时间(大约 0.6 秒)。所以我想问一下如何对其进行矢量化?谢谢!
我尝试执行以下矢量化代码:
F=np.zeros(Nj)
F[i]=F[i]+b
F[j]=F[j]-b
F=[ 3.1, -2.2, 0. , 2.2, -2.2, -3.1, 0. ]
这给出了错误的结果,因为可能有多个管道位于给定节点的开始或结束节点,但它只计算其中一个在任一侧。
另外,如果我创建两个稀疏矩阵 Mat_i 和 Mat_j 来表示连接到开始节点/结束节点的所有管道,然后迭代它会更快吗? (我正在使用 python 3.7)。
我刚刚设法让它与这个一起工作:
F=np.bincount(i,weights=b,minlength=Nj)-np.bincount(j,weights=b,minlength=Nj)
我也愿意使用 Numba,因为我在代码的另一部分中使用了 @njit(parallel=True)
作为标量函数,它通过使用我的 CPU 的所有 8 个线程加快了速度.
用纯 NumPy 做这件事很棘手,因为你多次“select”相同的索引(即 i
和 j
中的值不是唯一的)。但是 Numba 将加速代码而基本上没有变化(我冒昧地使用 +=
来简化):
@numba.njit
def smoke(F, b, i, j):
for k in range(len(i)): #iterate over pipes
F[i[k]] += b[k] #add value of b if pipe k is at the start of the node
F[j[k]] -= b[k] #subtract b if pipe k is at the end of the node
运行 如果您的输入是列表,它会像这样:
smoke(F, np.asarray(b), np.asarray(i), np.asarray(j))
我有 Np
links(管道)和 Nj
连接点(节点)。每个linkk
都有一个起始节点i
和结束节点j
,以及一个link值为b
。如果给定节点是 link 的起始节点,我想通过添加 b
来计算 links 对每个节点的贡献,如果给定节点减去 b
是一个link的结尾。我的代码是这样的:
for k in range(Np): #iterate over pipes
F[i[k]]=F[i[k]]+b[k] #add value of b if pipe k is at the start of the node
F[j[k]]=F[j[k]]-b[k] #substract b if pipe k is at the end of the node
用于运行此代码的数据示例:
Np=7 #number of pipes
Nj=6 #number of junctions (nodes)
pipe=[0,1,2,3,4,5,6] #number of pipes are consecutive, k=0:Np
i=[0,1,2,3,3,3,0] #number of start node for each pipe, 0<=i<Nj
j=[1,5,1,1,2,4,5] #number of end node for each pipe, 0<=j<Nj
b=[1.3,0.5,1.5,2.7,1.5,2.2,3.1] #value for each pipe, Np elements
node=[0,1,2,3,4,5] #node numbers are consecutive, 0:Nj
F=np.zeros(Nj) #intializing F, size is equal to number of nodes
循环的结果是:
F=[+1.3+3.1,+0.5-1.3-1.5-2.7,+1.5-1.5,+2.7+1.5+2.2,-2.2,-0.5-3.1]
或
F=[4.4, -5.0, 0.0, 6.4, -2.2, -3.6]
在我自己的管网中,我有 Nj=150628 和 Np=157040,所以我创建的循环花费了太多时间(大约 0.6 秒)。所以我想问一下如何对其进行矢量化?谢谢! 我尝试执行以下矢量化代码:
F=np.zeros(Nj)
F[i]=F[i]+b
F[j]=F[j]-b
F=[ 3.1, -2.2, 0. , 2.2, -2.2, -3.1, 0. ]
这给出了错误的结果,因为可能有多个管道位于给定节点的开始或结束节点,但它只计算其中一个在任一侧。 另外,如果我创建两个稀疏矩阵 Mat_i 和 Mat_j 来表示连接到开始节点/结束节点的所有管道,然后迭代它会更快吗? (我正在使用 python 3.7)。
我刚刚设法让它与这个一起工作:
F=np.bincount(i,weights=b,minlength=Nj)-np.bincount(j,weights=b,minlength=Nj)
我也愿意使用 Numba,因为我在代码的另一部分中使用了 @njit(parallel=True)
作为标量函数,它通过使用我的 CPU 的所有 8 个线程加快了速度.
用纯 NumPy 做这件事很棘手,因为你多次“select”相同的索引(即 i
和 j
中的值不是唯一的)。但是 Numba 将加速代码而基本上没有变化(我冒昧地使用 +=
来简化):
@numba.njit
def smoke(F, b, i, j):
for k in range(len(i)): #iterate over pipes
F[i[k]] += b[k] #add value of b if pipe k is at the start of the node
F[j[k]] -= b[k] #subtract b if pipe k is at the end of the node
运行 如果您的输入是列表,它会像这样:
smoke(F, np.asarray(b), np.asarray(i), np.asarray(j))