Python 连接两个网格及其结果数组的numpy方法
考虑两个n维的,可能重叠的,Python 连接两个网格及其结果数组的numpy方法,python,arrays,sorting,numpy,Python,Arrays,Sorting,Numpy,考虑两个n维的,可能重叠的,numpy网格,比如 m1 = (x1, y1, z1, ...) m2 = (x2, y2, z2, ...) 在m1和m2中,没有重复的坐标元组。每个meshgrid都有一个结果数组,它可能由不同的函数产生: r1 = f1(m1) r2 = f2(m2) 使f1(m)!=f2(m)。现在,我想将这两个网格及其结果数组连接起来,例如m=m1&m2和r=r1&r2(其中&表示某种联合),这样m中的坐标元组仍然被排序,r中的值仍然对应于原始坐标元组。新创建的坐标元
numpy网格
,比如
m1 = (x1, y1, z1, ...)
m2 = (x2, y2, z2, ...)
在m1
和m2
中,没有重复的坐标元组。每个meshgrid
都有一个结果数组,它可能由不同的函数产生:
r1 = f1(m1)
r2 = f2(m2)
使f1(m)!=f2(m)
。现在,我想将这两个网格
及其结果数组连接起来,例如m=m1&m2
和r=r1&r2
(其中&
表示某种联合),这样m
中的坐标元组仍然被排序,r
中的值仍然对应于原始坐标元组。新创建的坐标元组应该是可识别的(例如,使用特殊值)
为了详细说明我所追求的,我有两个例子,它们可以通过简单的for
和if
语句来实现我想要的。下面是一个1D示例:
x1 = [1, 5, 7]
r1 = [i**2 for i in x1]
x2 = [2, 4, 6]
r2 = [i*3 for i in x2]
x,r = list(zip(*sorted([(i,j) for i,j in zip(x1+x2,r1+r2)],key=lambda x: x[0])))
给
x = (1, 2, 4, 5, 6, 7)
r = (1, 6, 12, 25, 18, 49)
对于2D,它开始变得相当复杂:
import numpy as np
a1 = [1, 5, 7]
b1 = [2, 5, 6]
x1,y1 = np.meshgrid(a1,b1)
r1 = x1*y1
a2 = [2, 4, 6]
b2 = [1, 3, 8]
x2, y2 = np.meshgrid(a2,b2)
r2 = 2*x2
a = [1, 2, 4, 5, 6, 7]
b = [1, 2, 3, 5, 6, 8]
x,y = np.meshgrid(a,b)
r = np.ones(x.shape)*-1
for i in range(x.shape[0]):
for j in range(x.shape[1]):
if x[i,j] in a1 and y[i,j] in b1:
r[i,j] = r1[a1.index(x[i,j]),b1.index(y[i,j])]
elif x[i,j] in a2 and y[i,j] in b2:
r[i,j] = r2[a2.index(x[i,j]),b2.index(y[i,j])]
这将得到所需的结果,新坐标对的值为-1
:
x=
[[1 2 4 5 6 7]
[1 2 4 5 6 7]
[1 2 4 5 6 7]
[1 2 4 5 6 7]
[1 2 4 5 6 7]
[1 2 4 5 6 7]]
y=
[[1 1 1 1 1 1]
[2 2 2 2 2 2]
[3 3 3 3 3 3]
[5 5 5 5 5 5]
[6 6 6 6 6 6]
[8 8 8 8 8 8]]
r=
[[ -1. 4. 4. -1. 4. -1.]
[ 2. -1. -1. 5. -1. 6.]
[ -1. 8. 8. -1. 8. -1.]
[ 10. -1. -1. 25. -1. 30.]
[ 14. -1. -1. 35. -1. 42.]
[ -1. 12. 12. -1. 12. -1.]]
但随着维数和数组大小的增加,速度也会很快变慢。最后一个问题是:如何仅使用
numpy
函数来实现这一点。如果不可能,在python
中实现这一点的最快方法是什么。如果有什么关系,我更喜欢使用Python3。请注意,我在示例中使用的函数不是我使用的实际函数。我们可以使用一些掩蔽来替换B部分中的A,以提供1D
掩蔽。然后,我们可以使用这些遮罩来扩展到所需的维数
因此,对于一个2D
的情况,应该是这样的-
# Initialize o/p array
r_out = np.full([len(a), len(b)],-1)
# Assign for the IF part
mask_a1 = np.in1d(a,a1)
mask_b1 = np.in1d(b,b1)
r_out[np.ix_(mask_b1, mask_a1)] = r1.T
# Assign for the ELIF part
mask_a2 = np.in1d(a,a2)
mask_b2 = np.in1d(b,b2)
r_out[np.ix_(mask_b2, mask_a2)] = r2.T
可以像这样创建一个
-
a = np.concatenate((a1,a2))
a.sort()
同样,对于b
此外,我们可以使用索引而不是掩码来与np.ix
一起使用。同样,我们可以使用np.searchsorted
。因此,我们可以用np.searchsorted(a,a1)
等来获得其余掩码的相应索引,而不是掩码np.inad(a,a1)
。这应该要快得多
对于3D
的情况,我假设我们会有另一个数组,比如c
。因此,初始化部分将涉及使用len(c)
。还有一个掩码/索引数组对应于c
,因此还有一个术语进入,r1
和r2
,Divakar的答案正是我需要的。然而,我想继续尝试这个答案中的第二个建议,最重要的是我做了一些分析。我想其他人可能会对结果感兴趣。以下是我用于分析的代码:
import numpy as np
import timeit
import random
def for_join_2d(x1,y1,r1, x2,y2,r2):
"""
The algorithm from the question.
"""
a = sorted(list(x1[0,:])+list(x2[0,:]))
b = sorted(list(y1[:,0])+list(y2[:,0]))
x,y = np.meshgrid(a,b)
r = np.ones(x.shape)*-1
for i in range(x.shape[0]):
for j in range(x.shape[1]):
if x[i,j] in a1 and y[i,j] in b1:
r[i,j] = r1[a1.index(x[i,j]),b1.index(y[i,j])]
elif x[i,j] in a2 and y[i,j] in b2:
r[i,j] = r2[a2.index(x[i,j]),b2.index(y[i,j])]
return x,y,r
def mask_join_2d(x1,y1,r1,x2,y2,r2):
"""
Divakar's original answer.
"""
a = np.sort(np.concatenate((x1[0,:],x2[0,:])))
b = np.sort(np.concatenate((y1[:,0],y2[:,0])))
# Initialize o/p array
x,y = np.meshgrid(a,b)
r_out = np.full([len(a), len(b)],-1)
# Assign for the IF part
mask_a1 = np.in1d(a,a1)
mask_b1 = np.in1d(b,b1)
r_out[np.ix_(mask_b1, mask_a1)] = r1.T
# Assign for the ELIF part
mask_a2 = np.in1d(a,a2)
mask_b2 = np.in1d(b,b2)
r_out[np.ix_(mask_b2, mask_a2)] = r2.T
return x,y,r_out
def searchsort_join_2d(x1,y1,r1,x2,y2,r2):
"""
Divakar's second suggested solution using searchsort.
"""
a = np.sort(np.concatenate((x1[0,:],x2[0,:])))
b = np.sort(np.concatenate((y1[:,0],y2[:,0])))
# Initialize o/p array
x,y = np.meshgrid(a,b)
r_out = np.full([len(a), len(b)],-1)
#the IF part
ind_a1 = np.searchsorted(a,a1)
ind_b1 = np.searchsorted(b,b1)
r_out[np.ix_(ind_b1,ind_a1)] = r1.T
#the ELIF part
ind_a2 = np.searchsorted(a,a2)
ind_b2 = np.searchsorted(b,b2)
r_out[np.ix_(ind_b2,ind_a2)] = r2.T
return x,y,r_out
##the profiling code:
if __name__ == '__main__':
N1 = 100
N2 = 100
coords_a = [i for i in range(N1)]
coords_b = [i*2 for i in range(N2)]
a1 = random.sample(coords_a, N1//2)
b1 = random.sample(coords_b, N2//2)
a2 = [i for i in coords_a if i not in a1]
b2 = [i for i in coords_b if i not in b1]
x1,y1 = np.meshgrid(a1,b1)
r1 = x1*y1
x2,y2 = np.meshgrid(a2,b2)
r2 = 2*x2
print("original for loop")
print(min(timeit.Timer(
'for_join_2d(x1,y1,r1,x2,y2,r2)',
setup = 'from __main__ import for_join_2d,x1,y1,r1,x2,y2,r2',
).repeat(7,1000)))
print("with masks")
print(min(timeit.Timer(
'mask_join_2d(x1,y1,r1,x2,y2,r2)',
setup = 'from __main__ import mask_join_2d,x1,y1,r1,x2,y2,r2',
).repeat(7,1000)))
print("with searchsort")
print(min(timeit.Timer(
'searchsort_join_2d(x1,y1,r1,x2,y2,r2)',
setup = 'from __main__ import searchsort_join_2d,x1,y1,r1,x2,y2,r2',
).repeat(7,1000)))
对于每个函数,我使用了7组1000次迭代,并选择了最快的一组进行评估。两个10x10阵列的结果为:
original for loop
0.5114614190533757
with masks
0.21544912096578628
with searchsort
0.12026709201745689
对于两个100x100阵列,它是:
original for loop
247.88183582702186
with masks
0.5245905339252204
with searchsort
0.2439237720100209
对于大型矩阵,numpy
功能的使用不足为奇地产生了巨大的差异,事实上,searchsort
和索引而不是屏蔽大约一半的运行时间。非常有效,谢谢!我不太确定我是否了解所有的细节。为什么必须转换r1
和r2
?此外,要添加到您的答案中,a
和b
可以使用np.concatenate
和np.sort
,即a=np.concatenate((a1,a2))
和a.sort()
——也许你仍然可以把它添加到你的答案中…@ThomasKühn似乎我们需要这个转置来解释网格是如何用x,y=np.meshgrid(a,b)
创建的。添加了您的评论代码。很抱歉花了这么长时间才接受您的答案,但我仍然想尝试您的第二个建议,并对这两个选项进行分析。如果您感兴趣,请参阅下面我的辅助答案。@ThomasKühn很高兴看到searchsorted实现和更快的确认!