【问题标题】:Python - slice array until certain condition is metPython - 切片数组直到满足特定条件
【发布时间】:2011-07-10 03:08:54
【问题描述】:

我需要从给定的索引对数组进行切片,直到满足某个条件。

>>> 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,将不胜感激。谢谢!

【问题讨论】:

  • 你能澄清你的问题吗?你是什​​么意思“直到两个方向的第一个非无值”?
  • 您使用object 数组的事实(不是很常见,也不是很节省内存)在尝试确定非None 数组项的索引时会出现一个特殊问题。你能被说服使用固定字节的数据类型吗?如果您致力于object dtype,那么当类型转换为bool 时,任何“非无”都会评估为True 是真的吗?其中任何一个都有助于简化很多事情。
  • @Paul 我正在使用object 数组来存储单个字符串。本质上,我只需要一个char 数组。有没有替代的dtype 我可以使用dtype
  • @armandino:对单字符串使用dtype='|S1'(或简称dtype=str)。
  • @armandino:另外,如果你还没有注意到,在使用dtype='S1'

标签: python arrays numpy slice


【解决方案1】:

如果你这样设置你的问题:

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' '' '' '']

等等

【讨论】:

  • 谢谢保罗。这看起来像我所追求的。
【解决方案2】:

这是一个用于掩码数组的工作,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] 数组(['','X','','',''], dtype='|S1')

或者让我们试试 8:

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

如果应该在 ipython 中玩一下这个以更好地理解它。

【讨论】:

  • 非常有趣的安德里亚。感谢您的解释。非常感谢!
【解决方案3】:

请注意,这可以在纯 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', '']

【讨论】:

    【解决方案4】:

    首先想到的是两个循环。这样的事情会起作用:

    '''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]
    

    【讨论】:

    • 谢谢迈克。该解决方案完美运行(+1)。不过,我希望有一个 numpy 方法来处理这样的事情。
    • 我投了反对票,因为这对于大型稀疏数组来说效率非常低。使用其他答案的 numpy 方法。
    • 是的,Steabert,同意...至少我学到了一些新东西:-P
    【解决方案5】:
    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]
    

    【讨论】:

    • 恐怕没用。我得到['' 'A'] ['' 'X'] ['' 'B']
    • 当我回答问题时,问题中没有空字符串,它有“无”。非零方法适用于“无”。
    猜你喜欢
    • 2019-11-15
    • 2019-08-19
    • 1970-01-01
    • 2021-12-24
    • 1970-01-01
    • 2018-11-09
    • 2014-01-23
    • 2021-06-10
    • 2018-06-29
    相关资源
    最近更新 更多