检查 numpy 数组是否全为非负数的最佳方法

问题描述 投票:0回答:2

这可行,但在算法上不是最优的,因为我不需要在函数解析数组时存储最小值:

def is_non_negative(m):
    return np.min(m) >= 0

编辑:根据数据,最佳函数确实可以节省很多,因为它会在第一次遇到负值时终止。如果预期只有一个负值,则时间将平均缩短两倍。然而,在 numpy 库之外构建最佳算法将付出巨大的代价(Python 代码与 C++ 代码)。

python numpy numpy-ndarray
2个回答
0
投票

一个可能的解决方案是使用 C: 中的函数

#include <stdio.h>
#include <stdlib.h>

int is_negative(double* data, int num_elems) {
    for (int i = 0; i < num_elems; i++) {
        if (data[i] < 0) {
            return 1;
        }
    }
    return 0;
}

编译:

gcc -c -fPIC is_negative.c -o is_negative.o

链接:

gcc -shared is_negative.o -o libis_negative.so

然后,在 Python 中:

import numpy as np
import ctypes

lib = ctypes.cdll.LoadLibrary('/tmp/libis_negative.so')

a = np.array([1.0, 2.0, -3.0, 4.0])
num_elems = a.size

lib.is_negative.restype = ctypes.c_int
lib.is_negative.argtypes = [
    np.ctypeslib.ndpointer(dtype=np.float64),
    ctypes.c_int,
]

result = lib.is_negative(a, num_elems)

if result:
    print("It has negative elements")
else:
    print("It does not have negative elements")

0
投票

一个纯 Numpy 解决方案是使用基于块的策略:

def is_non_negative(m):
    chunkSize = max(min(65536, m.size/8), 4096) # Auto-tunning
    for i in range(0, m.size, chunkSize):
        if np.min(m[i:i+chunkSize]) < 0:
            return False
    return True

这个解决方案只有在数组很大时才有效,并且块足够大以使得 Numpy 调用开销小到足以将全局数组分成许多部分(以便从早期切割中受益)。块大小需要相当大,以平衡

np.min
在小阵列上相对较大的开销。


这是一个 Numba 解决方案:

import numba as nb

# Eagerly compiled funciton for some mainstream data-types.
@nb.njit(['(float32[::1],)', '(float64[::1],)', '(int_[::1],)'])
def is_non_negative_nb(m):
    for e in m:
        if e < 0:
            return False
    return True

事实证明,这比在我的机器上使用

np.min
更快,尽管 LLVM-Lite(Numba 的 JIT)代码没有很好地自动矢量化(即不使用 SIMD 指令)。

对于更快的代码,您需要使用 C/C++ 代码并使用基于块的 SIMD 友好代码,并且如果编译器未生成高效代码,则可能使用 SIMD 内在函数,不幸的是,在这种情况下相当频繁。

© www.soinside.com 2019 - 2024. All rights reserved.