2011-03-07 122 views
5

我需要从给定索引切片数组,直到满足特定条件。Python - 切片数组,直到满足某些条件

>>> a = numpy.zeros((10), dtype='|S1') 
>>> a[2] = 'A' 
>>> a[4] = 'X' 
>>> a[8] = 'B' 
>>> a 
array(['', '', 'A', '', 'X', '', '', '', 'B', ''], dtype='|S1') 

例如,对于上述阵列我想从一个给定的索引,直到在两个方向上的第一非零值的子集。例如,对于指数值2,4,8个中的结果将是:

['', '', A, '']  # 2 
['', X, '', '', ''] # 4 
['', '', '', B, ''] # 8 

上做到这一点最简单的方法使用numpy的API有什么建议?学习python和numpy,将不胜感激任何帮助。谢谢!

+0

你能澄清你的问题吗?你是什​​么意思“直到第一个非None值在两个方向”? – 2011-03-07 05:55:42

+0

当您尝试确定非无数组项目的索引时,使用'object'数组(不是很常见,也不是非常有效的内存)的事实在尝试确定非无数组项目的索引时会出现一个特殊问题。你能说服使用固定字节的dtype吗?如果你致力于'object' dtype,那么当类型为'bool'时,任何“non-None”都会评估为“True”吗?这两者都可以帮助简化很多事情。 – Paul 2011-03-07 06:04:13

+0

@Paul我正在使用'object'数组来存储单个字符串。从本质上讲,我需要的只是一个'char'数组。有没有另一种'dtype'我可以使用'dtype'? – armandino 2011-03-07 06:15:31

回答

6

这是蒙面阵列工作,numpy.ma有很多的功能与子集工作。

a = np.zeros((10), dtype=str) 
a[2] = 'A' 
a[4] = 'X' 
a[8] = 'B' 

让屏蔽掉不空元素:

am=np.ma.masked_where(a!='', a) 

np.ma.notmasked_contiguous穿过阵列(非常有效),并发现其中阵列没有被屏蔽的连续元素的所有切片:

slices = np.ma.notmasked_contiguous(am) 
[slice(0, 1, None), slice(3, 3, None), slice(5, 7, None), slice(9, 9, None)] 

因此,例如,元素5和7之间的数组连续为空。 现在,你只需要加入你感兴趣的切片,首先你会得到每片的起始索引:

slices_start = np.array([s.start for s in slices]) 

那么你得到的索引的位置,你正在寻找:

slices_start.searchsorted(4) #4 
Out: 2 

所以你想片1和片2: a [slices [1] .start:slices [2] .stop + 1] array(['','X','','',''], dtype ='| S1')

或让我们试试8:

i = slices_start.searchsorted(8) 
a[slices[i-1].start:slices[i].stop+1] 
Out: array(['', '', '', 'B', ''], 
    dtype='|S1') 

如果应该在ipython中使用它来更好地理解它。

+0

非常有趣的安德烈。感谢您的解释。非常感激! – armandino 2011-03-07 17:42:09

0

想到两个循环是首先想到的。像这样的东西会工作:

'''Given an array and an index...''' 
def getNoneSlice(a, i): 

    # get the first non-None index before i 
    start = 0 
    for j in xrange(i - 1, -1, -1): 
     if a[j] is not None: # or whatever condition 
      start = j + 1 
      break 

    # get the first non-None index after i 
    end = len(a) - 1 
    for j in xrange(i + 1, len(a)): 
     if a[j] is not None: # or whatever condition 
      end = j - 1 
      break 

    # return the slice 
    return a[start:end + 1] 
+0

谢谢迈克。该解决方案完美运作(+1)。但是我希望不会有类似这样的“numpy”方法。 – armandino 2011-03-07 06:21:17

+0

我低估了,因为对于大型稀疏数组来说这是非常低效的。使用其他答案的numpy方法。 – steabert 2011-03-07 06:48:45

+0

是的,Steabert,同意......至少我学到了一些新东西:-P – 2011-03-07 22:07:19

-2
def getSlice(a, n): 
    try: 
     startindex = a[:n].nonzero()[0][-1] 
    except IndexError: 
     startindex = 0 
    try: 
     endindex = a[(n+1):].nonzero()[0][0] + n+1 
    except IndexError: 
     endindex = len(a) 
    return a[startindex: endindex] 
+0

恐怕它不起作用。我得到'['''A'] ['''X'] ['''B'] ' – armandino 2011-03-07 06:48:13

+0

非零方法不适用于空字符串 – steabert 2011-03-07 07:03:37

+0

该问题没有空字符串当我回答时,它有'没有'。它的非零方法适用于'None'。 – pwdyson 2011-03-08 01:57:09

7

如果您设置的问题是这样的:

import numpy 
a = numpy.zeros((10), dtype=str) 
a[2] = 'A' 
a[4] = 'X' 
a[8] = 'B' 

你可以很容易地得到非空字符串的指数,像这样:

i = numpy.where(a!='')[0] # array([2, 4, 8]) 

或者,numpy.argwhere(..)也适用。

然后你就可以离开切片使用此阵:

out2 = a[:i[1]]  # 2 ['' '' 'A' ''] 
out4 = a[i[0]+1:i[2]] # 4 ['' 'X' '' '' ''] 

+0

谢谢保罗。这看起来像我之后。 – armandino 2011-03-07 06:49:32

2

请注意,这可以在纯Python中使用itertools和functools干净地完成。

import functools, itertools 
arr = ['', '', 'A', '', 'X', '', '', '', 'B', ''] 

f = functools.partial(itertools.takewhile, lambda x: not x) 
def g(a, i): 
    return itertools.chain(f(reversed(a[:i])), [a[i]], f(a[i+1:])) 

我们将f通过寻找,直到元素评估为真找到了子迭代器,和g作为应用此的指数和指标后,列表前的列表的反白区域的组合。

这将返回可以转换为包含我们结果的列表的生成器。

>>> list(g(arr, 2)) 
['', '', 'A', ''] 
>>> list(g(arr, 4)) 
['', 'X', '', '', ''] 
>>> list(g(arr, 8)) 
['', '', '', 'B', ''] 
相关问题