查找元素更改值numpy的索引

lia*_*ang 28 indexing numpy unique python-2.7

假设我有

>>> v
array([1, 1, 1, 1, 1, 2, 2, 2, 3, 4, 3, 4, 3, 4, 3, 4, 5, 5, 5])
Run Code Online (Sandbox Code Playgroud)

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

>>> index_of_changed_values(v)
[0, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16]
Run Code Online (Sandbox Code Playgroud)

如果使用一些numpy例程是不可能的,那么在python中执行它的快速方法是什么?因为我是一个笨拙的初学者,所以我可以参考一些好的numpy教程.

kit*_*ith 47

您可以通过将每个元素与其邻居进行比较来获得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)
Run Code Online (Sandbox Code Playgroud)

获取你使用"where"函数的索引

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

array([ 4,  7,  8,  9, 10, 11, 12, 13, 14, 15])
Run Code Online (Sandbox Code Playgroud)

从这里开始,您可以添加第一个元素并添加一个元素以获得您在问题中使用的相同索引方案.


And*_*nis 9

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

np.where(np.roll(v,1)!=v)[0]
Run Code Online (Sandbox Code Playgroud)

无需添加 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])
Run Code Online (Sandbox Code Playgroud)

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

  • 如果数组看起来像`[1, 1, 1, 2, 2, 2, 1, 1, 1]`,这将不起作用。即,第一个和最后一个值相同,因此您不会像预期的那样获得索引“0”... (3认同)

Kar*_*ley 9

很好的问题和答案!

\n

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

\n
%timeit np.where(np.diff(v, prepend=np.nan))                                                                                                                             \n15.3 ms \xc2\xb1 113 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 100 loops each)\n\n%timeit np.where(np.diff(v))[0] + 1                                                                                                                                     \n7.41 ms \xc2\xb1 72 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 100 loops each)\n\n%timeit np.where(v[:-1] != v[1:])[0] + 1                                                                                                                                       \n2.85 ms \xc2\xb1 41.7 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 100 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n

因此,与使用带前缀 kwarg 的 diff() 相比,花式索引调用速度快 5 倍,比使用不带前缀的 diff 快两倍以上(无论如何在我古老的 MacBook Air 上)。对于大多数用例来说,这种性能差异并不重要,但我正在处理数千个这样的数据集(总共数十亿行),因此我需要牢记性能。

\n


myr*_*dio 5

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

@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)
Run Code Online (Sandbox Code Playgroud)

我更喜欢的一个选择是,

np.where(np.diff(v,prepend=np.nan))[0]
Run Code Online (Sandbox Code Playgroud)

这也返回

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

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

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

  • 嗨,OP在这里。这让我对我在行业中的第一个开发人员角色产生了深深的怀念。几天前我发现我当时所在的团队解散了。谢谢你们这些年来的回答。 (3认同)