【问题标题】:Applying operation to unevenly split portions of numpy array将操作应用于 numpy 数组的不均匀分割部分
【发布时间】:2017-02-25 04:55:29
【问题描述】:

我有三个 1D numpy 数组:

  1. 一些测量发生的时间列表 (t)。
  2. t (y) 中每个时间发生的测量列表。
  3. 影响这些测量的一些外部更改的(较短的)时间列表 (b)。

这是一个例子:

t = np.array([0.33856697, 1.69615293, 1.70257872, 2.32510279, 2.37788203、2.45102176、2.87518307、3.60941650、 3.782759074.37970516、4.56480259、5.33306546、 6.00867792、7.40217571、7.46716989、7.6791613、 7.96938078、8.41620336、9.1711634910.87530965]) y = np.array([ 3.70209916, 6.31148802, 2.96578172, 3.90036915, 5.11728629, 2.85788050、4.50077811、4.05113322、3.55551093、7.58624384、 5.47249362、5.00286872、6.26664832、7.08640263、5.28350628、 7.71646500, 3.75513591, 5.72849991, 5.60717179, 3.99436659]) b = np.array([ 1.7, 3.9, 9.5])

b 的元素位于粗体和斜体元素 t 之间,将其分成四个大小不一的片段,长度分别为 2、7、10、1。

我想对y 的每个段应用一个操作,以获得大小为b.size + 1 的数组。具体来说,我想知道更多每个段中y 的值是否超过或低于某个偏差。

我目前正在使用 for 循环和切片来应用我的测试:

bias = 5
categories = np.digitize(t, b)
result = np.empty(b.size + 1, dtype=np.bool_)
for i in range(result.size):
    mask = (categories == i)
    result[i] = (np.count_nonzero(y[mask] > bias) / np.count_nonzero(mask)) > 0.5

这似乎效率极低。不幸的是,np.where 在这种情况下无济于事。有没有办法对我在这里描述的操作进行矢量化以避免 Python for 循环?


顺便说一下,这里是ytbias 以及由b 分隔的区域的图,以说明为什么预期的resultarray([False, False, True, False], dtype=bool)

生成者

from matplotlib import pyplot as plt
from matplotlib.patches import Rectangle
plt.ion()
f, a = plt.subplots()
a.plot(t, y, label='y vs t')
a.hlines(5, *a.get_xlim(), label='bias')
plt.tight_layout()
a.set_xlim(0, 11)
c = np.concatenate([[0], b, [11]])
for i in range(len(c) - 1):
    a.add_patch(Rectangle((c[i], 2.5), c[i+1] - c[i], 8 - 2.5, alpha=0.2, color=('red' if i % 2 else 'green'), zorder=-i-5))
a.legend()

【问题讨论】:

  • 由于您的类别是连续的,您不能在通过与偏差比较获得的布尔值上使用add.reduceat 吗?使用searchsorted 可能最便宜的分割点?另外,如果我没有完全弄错,您可以使用分割点的diff 作为分母
  • @PaulPanzer。您能否用完整的答案澄清这一点。我只是了解您在这里的目标,但老实说,我不知道您在具体实施方面的意思。

标签: python numpy vectorization


【解决方案1】:

这不应该产生相同的结果吗?

split_points = np.searchsorted(t, np.r_[t[0], b, t[-1]])
numerator = np.add.reduceat(y > bias, split_points[:-1])
denominator = np.diff(split_points)
result = (numerator / denominator) > 0.5

注意事项:这种方法依赖于对 t 进行排序。那么相对于 b 的 bin 都将是整齐的块,所以我们不需要掩码来描述它们,只需要以索引形式的端点到 t。这就是 searchsorted 为我们找到的。

由于您的标准似乎不依赖于组,我们可以一次性为所有 y 制作一个大面具。在布尔数组中计算非零值与求和相同,因为 True 将被强制转换为等值。这种情况下的优点是我们可以使用 add.reduceat 获取数组、分割点列表,然后对块求和在分裂之间,这正是我们想要的。

为了标准化,我们需要计算每个 bin 中的总数,但由于这些 bin 是连续的,我们只需要划分该 bin 的 split_points 的差异,这就是我们使用diff 的地方。

【讨论】:

  • r_ vs concatenate 有什么原因吗?
  • 另外,这很好看。我很佩服。谢谢。
  • 另外,我完全不知道reduceat。它确实可以满足我的需要。
  • @MadPhysicist r_ 只是个人喜好。 -- 是的reduceat 非常有用。 ——欢迎你。 ——只有一个问题:它真的有效吗?因为我没有测试。
  • 是的,工作得很好。我检查了每个步骤是否符合我的要求,并且确实做到了。
猜你喜欢
  • 2013-05-27
  • 1970-01-01
  • 1970-01-01
  • 2022-08-19
  • 2015-11-18
  • 1970-01-01
  • 1970-01-01
  • 2016-12-16
相关资源
最近更新 更多