高效的重复numpy.where

时间:2017-03-22 16:44:48

标签: python pandas numpy where computational-geometry

我有一个代码,我想检查坐标对是否属于某些矩形。但是,有很多矩形,我不知道如何将以下代码推广到许多矩形。我只能在循环中使用eval来完成它,但这非常难看。

这是一个代码,用于检查由坐标组成的DataFrame的每个条目的哪个矩形。如果它属于第一个,则为0,第二个为1,否则为nan。我希望有这样一个代码可以产生类似的结果,假设我们有一个大的Rectangle对象列表,而不是在最后一行应用eval或循环。非常感谢。

from matplotlib.patches import Rectangle

rec1 = Rectangle((0,0), 100, 100)
rec2 = Rectangle((100,0), 100, 100)
x = np.random.poisson(100, size=200)
y = np.random.poisson(80, size=200)
xy = pd.DataFrame({"x" : x, "y" : y}).values
e1 = np.asarray(rec1.get_extents())
e2 = np.asarray(rec2.get_extents())
r1m1, r1m2 = np.min(e1), np.max(e1)
r2m1, r2m2 = np.min(e2), np.max(e2)
out = np.where(((xy >= r1m1) & (xy <= r1m2)).all(axis=1), 0, 
               np.where(((xy >= r2m1) & (xy <= r2m2)).all(axis=1), 1, np.nan))

编辑这是一个包含3个矩形的版本

rec1 = Rectangle((0,0), 100, 100)
rec2 = Rectangle((0,100), 100, 100)
rec3 = Rectangle((100,100), 100, 100)
x = np.random.poisson(100, size=200)
y = np.random.poisson(100, size=200)
xy = pd.DataFrame({"x" : x, "y" : y}).values
e1 = np.asarray(rec1.get_extents())
e2 = np.asarray(rec2.get_extents())
e3 = np.asarray(rec3.get_extents())
r1m1, r1m2 = np.min(e1), np.max(e1)
r2m1, r2m2 = np.min(e2), np.max(e2)
r3m1, r3m2 = np.min(e3), np.max(e3)
out = np.where(((xy >= r1m1) & (xy <= r1m2)).all(axis=1), 0, 
           np.where(((xy >= r2m1) & (xy <= r2m2)).all(axis=1), 1, 
           np.where(((xy >= r3m1) & (xy <= r3m2)).all(axis=1), 2, np.nan)))

我喜欢的是0,1,2或np.nan的值。但输出仅由0和1组成。

3 个答案:

答案 0 :(得分:2)

matplotlib有一个内置例程contains_point,用于检查一个点是否包含在一个非常快的多边形对象中。

from matplotlib.patches import Rectangle

rec1 = Rectangle((0, 0), 100, 100)
rec1.contains_point((1, 1))
# True
rec1.contains_point((101, 101))
# False

答案 1 :(得分:2)

这是一个利用NumPy broadcasting -

的矢量化方法
# Store extents in a 3D array
e = np.dstack((e1,e2,e3))

# Get a valid mask for the X's and Y's and then the combined one
x_valid_mask = (xy[:,0] >= e[0,0,:,None]) & (xy[:,0] <= e[1,0,:,None])
y_valid_mask = (xy[:,1] >= e[0,1,:,None]) & (xy[:,1] <= e[1,1,:,None])
valid_mask = x_valid_mask & y_valid_mask

# Finally use argmax() to choose the rectangle each pt belongs. We can use
# argmax to choose the first matching one and that works here because
# we are guaranteed to have the recatnagles mutually exclusive
out = np.where(valid_mask.any(0), valid_mask.argmax(0), np.nan)

我们有一个示例运行来验证这里的事情 -

1)设置随机输入:

In [315]: rec1 = Rectangle((0,0), 100, 100)
     ...: rec2 = Rectangle((0,100), 100, 100)
     ...: rec3 = Rectangle((100,100), 100, 100)
     ...: 

In [316]: e1 = np.asarray(rec1.get_extents())
     ...: e2 = np.asarray(rec2.get_extents())
     ...: e3 = np.asarray(rec3.get_extents())
     ...: 

2)查看rec3的范围:

In [317]: e3
Out[317]: 
array([[ 100.,  100.],
       [ 200.,  200.]])

3)获得xy的随机5分:

In [319]: x = np.random.poisson(100, size=5)
     ...: y = np.random.poisson(100, size=5)
     ...: xy = pd.DataFrame({"x" : x, "y" : y}).values
     ...: 

4)让我们设置pt[1]使其内部rec3。因此,此pt的o / p应为2

In [320]: xy[1] = [150,175]

5)让我们设置pt[3],使其在所有矩形之外。因此,相应的o / p应为NaN

In [321]: xy[3] = [400,400]

6)运行已过帐的代码并打印输出:

In [323]: out
Out[323]: array([ nan,   2.,   2.,  nan,   2.])

如图所示out[1] 2out[3]NaN,这是之前预料到的。

答案 2 :(得分:1)

这样的嵌套很难阅读和扩展:

where(cond1, 0, where(cond2, 1, where(cond3, 2, ..)))

您会从其他问题中看到where最常用于生成索引,即I,J=np.where(cond)版本而不是np.where(cond, 0, x)版本。

因此,为了清楚起见,我会受到诱惑,将您的代码编写为

res = xy.copy()   # or np.zeros_like(xy)
for i in range(n):
    ij = np.where(cond[i]
    res[ij] = i