Numpy矢量化小于/大于比较

时间:2014-11-04 23:43:46

标签: python numpy

我有一些代码可以将角度与它们所属的圆圈的象限相匹配。它目前给了我想要的结果,但是我试图失去for循环以充分利用numpy的速度。

import numpy as np

angle = np.array([350, 10, 80, 100, 170, 190, 260, 280])
# Center of each quadrant
spawn_angles = np.array([0, 90, 180, 270])

segment_degrees = np.diff(spawn_angles)[0]
lower_bounds = spawn_angles - (segment_degrees / 2)
upper_bounds = spawn_angles + (segment_degrees / 2)
max_upper = upper_bounds.max()
# Wrap angles larger than the upper bound of the last segment
# back to a negative angle
angle[angle > max_upper] -= 360
quadrant = np.zeros_like(angle, dtype=np.float64)
# Want to make sure that quadrants that don't get calculated
# properly get assigned an invalid number, i.e. -1
quadrant.fill(-1)
for segment_num in range(len(spawn_angles)):
    in_segment = ((angle > lower_bounds[segment_num]) & 
                  (angle < upper_bounds[segment_num]))
    quadrant[in_segment] = segment_num

# Expected/current output
quadrant
Out[16]: array([ 0.,  0.,  1.,  1.,  2.,  2.,  3.,  3.])

基本上,我无法弄清楚如何在numpy中做的部分是> / <比较。 如果角度介于lower_bounds[0]upper_bounds[0]之间,则为相应的条目 quadrant的{​​0}被赋予0,类似于象限1,2,3,有没有办法 将角度数组同时与lower_bound和/或upper_bound的所有条目进行比较?

(如果此代码看起来过于复杂,其中一些是因为spawn_angles /象限中心 不总是[0, 90, 180, 270],它们也可以是例如[45, 135, 225, 315]

2 个答案:

答案 0 :(得分:1)

您需要将所有内容提升到一个维度。您需要一个2D数组,每个角度为一行,每个segment_num为一列。 (或许你想要转置,但如果是这样,你应该能够从这里想出来。)

如果您只是a > b ab都是1D数组,那么您需要进行1对1的元素比较。

但如果a是2D数组,那么您需要进行笛卡尔积比较。

换句话说:

>>> array.reshape((8,1)) > lower_bounds
array([[ True,  True,  True,  True],
       [ True, False, False, False],
       [ True,  True, False, False],
       [ True,  True, False, False],
       [ True,  True,  True, False],
       [ True,  True,  True, False],
       [ True,  True,  True,  True],
       [ True,  True,  True,  True]], dtype=bool)

你应该能够从那里弄明白。

答案 1 :(得分:1)

感谢abarnert对这里的关键见解。我重写的矢量化代码:

import numpy as np

angle = np.array([350, 10, 80, 100, 170, 190, 260, 280])
# Center of each quadrant
spawn_angles = np.array([0, 90, 180, 270])

segment_degrees = np.diff(spawn_angles)[0]
lower_bounds = spawn_angles - (segment_degrees / 2)
upper_bounds = spawn_angles + (segment_degrees / 2)
max_upper = upper_bounds.max()
# Wrap angles larger than the upper bound of the last segment
# back to a negative angle
angle[angle > max_upper] -= 360
angle_2d = angle.reshape((len(angle), 1))
cmp_array = ((angle_2d > lower_bounds) & 
             (angle_2d < upper_bounds))
quadrant = np.argwhere(cmp_array)[:, 1]
quadrant
Out[29]: array([0, 0, 1, 1, 2, 2, 3, 3], dtype=int64)