【问题标题】:Removing all but last non-zero sequence from numpy array从 numpy 数组中删除除最后一个非零序列之外的所有序列
【发布时间】:2017-03-10 13:19:57
【问题描述】:

问题

我有一个一维 numpy 数组,其中大部分填充了零,但也包含一些非零值组。

>> import numpy as np
>> a = np.zeros(10)
>> a[2:4] = 2
>> a[6:9] = 3
>> print a
[ 0.  0.  2.  2.  0.  0.  3.  3.  3.  0.]

我想获取仅包含最后一个非零组的数组。换句话说,除了最后一个非零组之外的所有组都应该被零替换。 (这些组可能只有 1 个元素长)。像这样:

[ 0.  0.  0.  0.  0.  0.  3.  3.  3.  0.]

非稳健解决方案

这似乎可以解决问题。反转数组并找到元素之间变化为负的第一个索引。然后用零替换所有后续元素。然后翻回来。有点啰嗦:

>> b = a[::-1]
>> b[np.where(np.ediff1d(b) < 0)[0][0] + 1:] = 0
>> c = b[::-1]
>> print c
[ 0.  0.  0.  0.  0.  0.  3.  3.  3.  0.]

在特定情况下失败

但是,它并不健壮并且在以下情况下会失败(因为 where 命令返回一个空的索引列表):

>> a = np.zeros(10)
>> a[0:4] = 2
>> print a
[ 2.  2.  2.  2.  0.  0.  0.  0.  0.  0.]
>> b = a[::-1]
>> b[np.where(np.ediff1d(b) < 0)[0][0] + 1:] = 0
>> c = b[::-1]
>> print c

Traceback (most recent call last):

  File "<ipython-input-81-8cba57558ba8>", line 1, in <module>
    runfile('C:/Users/name/test1.py', wdir='C:/Users/name')

  File "C:\ProgramData\Anaconda2\lib\site-packages\spyder\utils\site\sitecustomize.py", line 866, in runfile
    execfile(filename, namespace)

  File "C:\ProgramData\Anaconda2\lib\site-packages\spyder\utils\site\sitecustomize.py", line 87, in execfile
    exec(compile(scripttext, filename, 'exec'), glob, loc)

  File "C:/Users/name/test1.py", line 21, in <module>
    b[np.where(np.ediff1d(b) < 0)[0][0] + 1:] = 0

IndexError: index 0 is out of bounds for axis 0 with size 0

修复

所以我需要引入一个if 子句:

>> b = a[::-1]
>> if len(np.where(np.ediff1d(b) < 0)[0]) > 0:
>>     b[np.where(np.ediff1d(b) < 0)[0][0] + 1:] = 0
>> c = b[::-1]
>> print c
[ 2.  2.  2.  2.  0.  0.  0.  0.  0.  0.]

有没有更优雅的方法呢?

更新 继 Divakar 的出色回答和 mtrw 的问题之后,我想扩展规范。如果输入数组的非零值为负,则该方法也应该适用于在分组内发生变化的非零数字组。

例如np.array([1, 0, 0, 4, 5, 4, 5, 0, 0])

这意味着我们检查元素之间的正或负差异以找到组边界的方法效果不佳。

【问题讨论】:

  • 非零值是否也保证大于0?

标签: numpy


【解决方案1】:

方法#1

既然我们追求优雅,让我们自己一个单线 -

a[:(a[1:] > a[:-1]).cumsum().argmax()] = 0

示例运行 -

In [605]: a
Out[605]: array([ 0.,  0.,  2.,  2.,  0.,  0.,  3.,  3.,  3.,  0.])

In [606]: a[:(a[1:] > a[:-1]).cumsum().argmax()] = 0

In [607]: a
Out[607]: array([ 0.,  0.,  0.,  0.,  0.,  0.,  3.,  3.,  3.,  0.])

方法#2

上述方法假设最后一组数字大于0's。如果不是这种情况,并且对于非零组可能有不同数字的情况,让我们提供多行以获得通用解决方案 -

mask = a != 0
a[:(mask[1:] > mask[:-1]).cumsum().argmax()] = 0

示例运行 -

In [667]: a
Out[667]: array([-1,  0,  0, -4, -5,  4, -5,  0,  0])

In [668]: mask = a != 0

In [669]: a[:(mask[1:] > mask[:-1]).cumsum().argmax()] = 0

In [670]: a
Out[670]: array([ 0,  0,  0, -4, -5,  4, -5,  0,  0])

【讨论】:

  • 谢谢,太好了。我认为修改我的问题为时已晚,但我应该询问分组数字不恒定的数组,例如a = np.array([1, 0, 0, 4, 5, 4, 5, 0, 0])。您的方法能否适用于这种情况,而忽略组内相邻数字之间的差异也可能是正数的事实?
  • @feedMe 其实看看刚才添加的第二种方式?
猜你喜欢
  • 2017-03-17
  • 1970-01-01
  • 2022-07-11
  • 2020-12-03
  • 1970-01-01
  • 2014-04-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-03
相关资源
最近更新 更多