简体   繁体   English

获取符合我的标准的 np.array 索引的最快方法

[英]Fastest way to get indices of a np.array that meet my criteria

I am trying to find the fastest way to get the indices of the matrix elements that meet my criteria.我试图找到获得满足我的标准的矩阵元素的索引的最快方法。 I have a (7,7) np.array (named "board"), which contains int16 from 0 to 400. For example, I want to find the indices of the elements which are equal to 300.我有一个 (7,7) np.array(名为“board”),其中包含从 0 到 400 的 int16。例如,我想找到等于 300 的元素的索引。

I have tried many techniques and so far the fastest method is the np.where(board ==300)我尝试了很多技术,到目前为止最快的方法是 np.where(board ==300)

The function I am trying to optimize:我正在尝试优化的功能:

def is_end(self, board):
    ind = np.where((board > 300) & (board - 300 < 100))
    try:
        victoriousPlayer = board[ind[0][0], ind[1][0]] % 100 // 10
        return victoriousPlayer
    except:
        return -1

Because I use this function tens of thousands of times I need it to run as fast as possible.因为我数万次使用这个函数,所以我需要它尽可能快地运行。

If you want to minimize the running time of the function, probably the best you can do is avoid allocating new arrays on each call.如果你想最小化函数的运行时间,你能做的最好的事情就是避免在每次调用时分配新的数组。 That means maintaining additional arrays for temporary values outside of the function, but it does give you a significant speedup.这意味着为函数之外的临时值维护额外的数组,但它确实给你带来了显着的加速。

import numpy as np

# Original function
def is_end_1(board):
    ind = np.where((board > 300) & (board - 300 < 100))
    try:
        victoriousPlayer = board[ind[0][0], ind[1][0]] % 100 // 10
        return victoriousPlayer
    except:
        return -1

# Without array allocation
def is_end_2(board, tmpBool1, tmpBool2):
    np.less(300, board, out=tmpBool1)
    np.less(board, 400, out=tmpBool2)
    np.logical_and(tmpBool1, tmpBool2, out=tmpBool1)
    idx = np.unravel_index(np.argmax(tmpBool1), board.shape)
    return board[idx] % 100 // 10 if tmpBool1[idx] else -1

# Test
np.random.seed(0)
# Create some data
board = np.random.randint(500, size=(1000, 1000))
# Result from original function
res1 = is_end_1(board)
# Temporary arrays
tmpBool1 = np.empty_like(board, dtype=np.bool)
tmpBool2 = tmpBool1.copy()
# Result from function without allocations
res2 = is_end_2(board, tmpBool1, tmpBool2)
print(res1 == res2)
# True

# Measure time
%timeit is_end_1(board)
# 9.61 ms ± 323 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit is_end_2(board, tmpBool1, tmpBool2)
# 1.38 ms ± 53.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

You don't need the indices in this case it seems, just a mask.在这种情况下,您似乎不需要索引,只需要一个掩码。

ind = np.where((board > 300) & (board - 300 < 100))
victoriousPlayer = board[ind[0][0], ind[1][0]] % 100 // 10

is equivalent to相当于

victoriousPlayer = board[(board  > 300) & (board - 300 < 100)][0] % 100 // 10

Timings:时间:

In [1]: import numpy as np                                                                                                    

In [2]: board = np.random.randint(0,401, (7,7))                                                                               

In [3]: %timeit ind = np.where((board > 300) & (board - 300 < 100));victoriousPlayer = board[ind[0][0], ind[1][0]] % 100 // 10
6.77 µs ± 260 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [4]: %timeit victoriousPlayer = board[(board  > 300) & (board - 300 < 100)][0] % 100 // 10                                 
5.02 µs ± 26.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM