查找元素更改值的索引numpy

Posted

技术标签:

【中文标题】查找元素更改值的索引numpy【英文标题】:Find index where elements change value numpy 【发布时间】:2013-10-08 04:07:59 【问题描述】:

假设我有

>>> v
array([1, 1, 1, 1, 1, 2, 2, 2, 3, 4, 3, 4, 3, 4, 3, 4, 5, 5, 5])

是否有一种有效的 numpy 方法来查找值发生变化的每个索引?例如,我想要一些结果,例如,

>>> index_of_changed_values(v)
[0, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16]

如果某些 numpy 例程无法做到这一点,那么在 python 中快速的方法是什么?由于我是 numpy 初学者,因此推荐一些好的 numpy 教程对我也很有用。

【问题讨论】:

【参考方案1】:

您可以通过将每个元素与其相邻元素进行比较,在 numpy 中获得此功能;

v[:-1] != v[1:]


array([False, False, False, False,  True, False, False,  True,  True,
    True,  True,  True,  True,  True,  True,  True, False, False], dtype=bool)

要获取您使用“where”函数的索引

np.where(v[:-1] != v[1:])[0]

array([ 4,  7,  8,  9, 10, 11, 12, 13, 14, 15])

您可以在此处添加第一个元素并添加一个以获取与您的问题相同的索引方案。

【讨论】:

【参考方案2】:

类似于@kith 的回答,但需要较少的按摩结果:

np.where(np.roll(v,1)!=v)[0]

无需添加 0 或添加 1。 示例:

>>> v=np.array([1, 1, 1, 2, 2, 3, 3, 4, 4, 4])
>>> np.where(np.roll(v,1)!=v)[0]
array([0, 3, 5, 7])

编辑:正如@Praveen 提到的,当最后一个元素和第一个元素相等时,这会失败。

【讨论】:

如果数组看起来像[1, 1, 1, 2, 2, 2, 1, 1, 1],这将不起作用。即,第一个和最后一个值是相同的,所以你不会像你期望的那样得到索引'0'......【参考方案3】:

差不多十年后,但我今天遇到了这个。

@kith 的答案很好,但可能没有我们想要的那么简洁(还要考虑到答案中未明确说明的步骤)。

完整的答案是,

v = np.array([1, 1, 1, 1, 1, 2, 2, 2, 3, 4, 3, 4, 3, 4, 3, 4, 5, 5, 5])
np.concatenate((np.array([0]),np.where(v[:-1] != v[1:])[0]+1),axis=0)

我更喜欢的另一种选择是,

np.where(np.diff(v,prepend=np.nan))[0]

也返回

array([ 0,  5,  8,  9, 10, 11, 12, 13, 14, 15, 16], dtype=int64)

正如我所说,这个想法与 @kith 的想法相同,但是,

我将v[:-1] != v[1:] 替换为np.diff(),然后在np.where 中将数组转换为布尔值,这并没有太大变化,但看起来更整洁。 我删除了添加 1 和前置 0 的额外步骤。这是通过在执行 np.diff() 之前添加 np.nan 来完成的。 diff 输出的第一个元素将是 np.nan,在 python 中 np.nan 总是计算 True

【讨论】:

嗨,在这里。这让我怀念我在行业中的第一个开发人员角色。几天前我发现我当时所在的团队解散了。谢谢你们多年来的回答。 我很高兴它能以任何方式帮助 ^_^。保持安全。 您必须安装 NumPy 1.16.0 或更新版本,np.where(np.diff(v,prepend=np.nan))[0] 才能工作。我为那些不知道的人发帖。 @DavidM.Helmuth 好点,我真的没有检查过。我会将其添加到答案中。【参考方案4】:

很好的问题和答案!

我正在处理一个向量,其中包含大约 100 万个从 1 到 100,000 的单调非递减整数(例如 [1, 1, 1, 2, 3, 3, 4, ..., 100000])。对于这个数据集,上面讨论的 2 个习语以及是否使用 prepend kwarg 之间似乎存在明显的性能差异:

%timeit np.where(np.diff(v, prepend=np.nan))                                                                                                                             
15.3 ms ± 113 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit np.where(np.diff(v))[0] + 1                                                                                                                                     
7.41 ms ± 72 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit np.where(v[:-1] != v[1:])[0] + 1                                                                                                                                       
2.85 ms ± 41.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

因此,与使用带有 prepend kwarg 的 diff() 相比,fancy-indexing 调用快 5 倍,并且是使用不带 prepend 的 diff 的两倍多(无论如何在我的旧 MacBook Air 上)。对于大多数用例来说,这种性能差异并不重要,但我正在处理数千个这样的数据集(总共数十亿行),所以我需要牢记性能。

【讨论】:

以上是关于查找元素更改值的索引numpy的主要内容,如果未能解决你的问题,请参考以下文章

在 numpy 数组中查找多个值的行索引

在 1D NumPy 数组中查找值的索引/位置(具有相同的值)[重复]

Python:在 List 或 numpy.ndarry 中查找最大的 Top-n 值的索引 [重复]

我需要一个 numpy 数组中的 N 个最小(索引)值

在 NumPy 数组中查找等于零的元素的索引

更改不在索引列表中的 NumPy 数组的值