python / numpy:否定或补充切片

时间:2014-02-10 00:12:59

标签: python arrays numpy slice

我有一些功能,是大分析软件的一部分,需要一个布尔掩码来将数组项分成两组。这些功能是这样的:

def process(data, a_mask):
    b_mask = -a_mask
    res_a = func_a(data[a_mask])
    res_b = func_b(data[b_mask])
    return res_a, res_b

现在,我需要使用这些函数(没有修改)和一个只有类“a”的项目的大数组,但我想保存RAM并且不传递所有{{1}的布尔掩码}。例如,我可以传递像True这样的切片。

问题是如果slice(None, None)是切片,则行b_mask = -a_mask将失败。理想情况下a_mask应该给出0项选择。

我正在考虑创建一个“修改过的”切片对象,该对象将-a_mask方法实现为空切片(例如__neg__())。我不知道这是否可能。

其他允许不修改slice(0, 0)函数但同时避免分配全True布尔数组的解决方案也将被接受。

3 个答案:

答案 0 :(得分:1)

很遗憾,我们无法向__neg__()添加slice方法,因为它cannot be subclassed。但是,tuple可以是子类,我们可以使用它来保存单个slice对象。

这引出了一个非常非常讨厌的黑客攻击,它应该适合你:

class NegTuple(tuple):
    def __neg__(self):
        return slice(0)

我们可以创建一个包含单个切片对象的NegTuple

nt = NegTuple((slice(None),))

这可以用作索引,否则它将产生一个空切片,导致0长度数组被索引:

a = np.arange(5)
print a[nt]
# [0 1 2 3 4]
print a[-nt]
# []
但是,你必须非常渴望诉诸这样的事情。完全不可能像这样修改process吗?

def process(data, a_mask=None):
    if a_mask is None:
        a_mask = slice(None)  # every element
        b_mask = slice(0)     # no elements
    else:
        b_mask = -a_mask
    res_a = func_a(data[a_mask])
    res_b = func_b(data[b_mask])
    return res_a, res_b

这种方式更明确,不应对其当前用例的行为产生任何影响。

答案 1 :(得分:0)

你的解决方案非常类似于简并稀疏布尔数组,尽管我不知道它的任何实现。我的下意识反应是不喜欢的,但如果你真的无法修改process,这可能是最好的方法。

答案 2 :(得分:0)

如果您担心内存使用,那么高级索引可能不是一个好主意。来自docs

  

高级索引始终返回数据的副本(与返回视图的基本切片形成对比)。

目前,process函数有:

  • data大小n
  • a_mask,大小为n(假设为高级索引)

创造:

  • b_mask,大小为n
  • data[a_mask]大小m
  • data[b_mask],大小为n - m

这实际上是4个大小为n的数组。

基本切片似乎是你最好的选择,但是Python似乎不允许继承slice

TypeError: Error when calling the metaclass bases
    type 'slice' is not an acceptable base type

请参阅@ ali_m的答案,了解包含切片的解决方案。

或者,您可以绕过process并将结果作为

result = func_a(data), func_b([])