Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 是否可以在numpy数组切片运算符中组合逻辑条件和限制条件_Python_Arrays_Numpy_Slice - Fatal编程技术网

Python 是否可以在numpy数组切片运算符中组合逻辑条件和限制条件

Python 是否可以在numpy数组切片运算符中组合逻辑条件和限制条件,python,arrays,numpy,slice,Python,Arrays,Numpy,Slice,我有下面的代码,它正是我想要的,但是它太慢了,因为它涉及到一个不必要的具体化步骤: ### init a = np.array([[1,2,3],[4,5,6],[7,8,9],[10,11,12]]) ### condition 1) element 0 has to be larger than 1 ### condition 2) limit the output to 2 elements b = a[a[:,0] > 1][:2] 问题是,当我有一个大数组时,速度非常慢(考虑

我有下面的代码,它正是我想要的,但是它太慢了,因为它涉及到一个不必要的具体化步骤:

### init
a = np.array([[1,2,3],[4,5,6],[7,8,9],[10,11,12]])

### condition 1) element 0 has to be larger than 1
### condition 2) limit the output to 2 elements
b = a[a[:,0] > 1][:2]
问题是,当我有一个大数组时,速度非常慢(考虑到我只想用条件2切掉一小块)。这很容易做到,但我还没有找到一种方法把它放进一行

因此,是否有一种简洁的方法可以在一行中有效地实现这一点?大概是这样的:

b = a[a[:,0] > 1 and :2]
a = np.array([[1,2,3],[4,5,6],[7,8,9],[10,11,12]])

# Check your condition
mask = a[:, 0] > 1

# Copy those rows the array that satisfy the condition 
temp = a[mask]

# Take first two rows of temp
b = temp[:2]

谢谢大家!

您可能可以稍微加快这段代码的速度,您当前的代码是这样工作的:

b = a[a[:,0] > 1 and :2]
a = np.array([[1,2,3],[4,5,6],[7,8,9],[10,11,12]])

# Check your condition
mask = a[:, 0] > 1

# Copy those rows the array that satisfy the condition 
temp = a[mask]

# Take first two rows of temp
b = temp[:2]
我怀疑最昂贵的操作是中间的复制操作,你可以通过这样做来避免它:
mask = a[:, 0] > 1

# Find the first two True values in mask
where = np.where(mask)[0][:2]

# Only copy the rows you really want
b = a[where]

也许有一种更有效的方法可以找到前两个真值,我没有考虑太多,但关键是先找到您想要的值,然后只复制这些行。

我想不出一个更快速的解决方案,但您可以使用
numba

from numba import autojit

def filtfunc(a):
    idx = []
    for ii in range(a.shape[0]):
        if (a[ii, 0] > 1):
            idx.append(ii)
            if (len(idx) == 2):
                break
    return a[idx]

jit_filter = autojit(filtfunc)
以下是另外两个建议的解决方案供参考:

def marco_filter(a):
    return a[a[:,0] > 1][:2]

def rico_filter(a):
    mask = a[:, 0] > 1
    where = np.where(mask)[0][:2]
    return a[where]
一些时间安排:

%%timeit a = np.random.random_integers(1, 12, (1000,1000))
marco_filter(a)
# 100 loops, best of 3: 11.6 ms per loop

%%timeit a = np.random.random_integers(1, 12, (1000,1000))
rico_filter(a)
# 10000 loops, best of 3: 44.8 µs per loop

%%timeit a = np.random.random_integers(1, 12, (1000,1000))
jit_filter(a)
# 10000 loops, best of 3: 30.7 µs per loop

如果
n=2
a.shape[0]
相比非常小,那么使用这个小函数可能是值得的。其基本思想是计算一个掩码,该掩码刚好足够大,可以给出所需的最终行数。在这里,我迭代地进行。通常迭代速度很慢,但如果迭代次数足够少,在其他地方节省的时间可能是值得的

def mask(a):
    return a[:,0]>1

def paul_filter1(a,n):
    # incremental w/ sum
    j = a.shape[0]
    for i in xrange(n,j+1):
        am = mask(a[:i,:])
        if np.sum(am)>=n:
            j = i
            break
    return a[am,:]
请注意,遮罩
am
可能比其正在处理的尺寸短。它有效地用
False
填充其余部分。我还没有检查这是否有文件记录

在这个小例子中,
foo
a[a[:,0]>1,:][:2,:]
慢3倍

但是对于更大的数组,比如说
a2=np.tile(a,[1000,1])
,使用
foo
的时间保持不变,但是“蛮力”不断变慢,因为它必须将掩码应用于更多行。当然,这些计时确实取决于所需行在
a
中的位置。如果
foo
必须使用几乎所有的行,就不会有任何节省

编辑

解决Bi Rico对重复的
np.sum
(即使是快速编译的代码)的担忧,我们可以增量地构建
,其中

def paul_filter3(a,n):
    # incremental adding index
    j = a.shape[0]
    am = mask(a[:n,:])
    am = np.where(am)[0].tolist()
    if len(am)<n:
        for i in xrange(n,j):
            if mask(a[[i],:]):
                am.append(i)
                if len(am)>=n:
                    break
    am = np.array(am)
    return a[am,:]
使用
1000x1000
随机整数数组(1:12)进行测试,时间为(使用20而不是2,调整掩码使更多行为假)

In [172]: timeit paul_filter4(a,20)
1000 loops, best of 3: 690 us per loop

In [173]: timeit paul_filter3(a,20)
1000 loops, best of 3: 1.22 ms per loop

In [175]: timeit paul_filter1(a,20)
1000 loops, best of 3: 994 us per loop

In [176]: timeit rico_filter(a,20)
1000 loops, best of 3: 668 us per loop

In [177]: timeit marco_filter(a,20)
10 loops, best of 3: 21 ms per loop  
rico\u过滤器
使用
其中
最快,但我的选择使用
cumsum
并不落后。3个增量过滤器的速度相似,大约是快速过滤器的一半

在生成和测试的
a
中,大多数行都是
True
。这与
marco的
担忧一致,即极限条件是逻辑条件的一小部分。在这些条件下,Bi Rico担心
paul_filter1
可能爆炸是不现实的

如果更改测试参数,则必须测试
a
的所有行(
a[:,0]>11
),
然后,使用
where
cumsum
的过滤器与原始过滤器一样长。增量过滤器的速度较慢,是原来的15倍或更多。但我第一次尝试使用
np.sum
时,速度最快。

如果是代码本身还是numpy背后的数学问题,你应该解释问题是什么。这个问题是更适合codereview.stackexchange我认为…但我不认为您可以…为什么不简单地颠倒索引顺序?通过执行
a[:,:2][a[:,0]>1]
您将不会“物化”大数组,但只有一个包含您要查找的元素。不幸的是,这不起作用,因为您可能会在第二步中删除元素。如果有
n
元素,我需要
n
元素。现在似乎不太可能有一种超干净的方法来完成此操作。事实上,短路
find
for numpy还不存在;根据对的第一个回答,这是2.0版本的一个功能要求。如果他们甚至没有,我不确定有没有一种好的方法可以不使用普通python或编写自己的扩展来实现这一点。是的,我有类似的方法,但希望有一种更优雅的方法。嗯,看看ali_m的时间安排s、 这是一个令人印象深刻的有效解决方案!虽然您的基本想法在这里是正确的,但通过使用
am=am[:i,0]>1;如果np.sum(am)=n…
您已将其转化为O(n**2)方法。即使n很小,如果
a[:,0],也可能会爆炸
有很多小值。你可以通过做类似于@ali\m的回答来解决这个问题。关键是要避免O(n)循环中的操作,如
sum
。我尝试了一些替代的增量函数,这些函数在循环中不使用
sum
,并且没有任何加速。
np.sum
是编译代码,所以即使它是O(n)它不会降低循环的速度。如果增量方法最终测试了大多数行,那么它的速度就会变慢。