codememo

NumPy: max()와 min()을 동시에 사용하는 함수

tipmemo 2023. 7. 17. 21:08
반응형

NumPy: max()와 min()을 동시에 사용하는 함수

numpy.amax()는 배열에서 최대값을 찾고 numpy.amin()은 최소값에 대해 동일한 값을 찾습니다.max와 min을 모두 찾으려면 두 함수를 모두 호출해야 하는데, (매우 큰) 배열을 두 번 넘겨야 하는데, 이는 느린 것 같습니다.

numpy API에 데이터를 한 번만 통과하면 max와 min을 모두 찾을 수 있는 기능이 있나요?

numpy API에 데이터를 한 번만 통과하면 max와 min을 모두 찾을 수 있는 기능이 있나요?

아닙니다. 이 글을 쓸 당시에는 그런 기능이 없습니다. (그리고 네, 그런 기능이 있었다면, 그 성능은 호출하는 것보다 훨씬 더 좋을 것입니다.)numpy.amin()그리고.numpy.amax()대규모 어레이에서 연속적으로 실행됩니다.)

저는 어레이를 두 번 통과하는 것이 문제가 되지 않는다고 생각합니다. 다음 유사 코드를 생각해 보십시오.

minval = array[0]
maxval = array[0]
for i in array:
    if i < minval:
       minval = i
    if i > maxval:
       maxval = i

여기에 루프가 1개뿐인 반면, 여전히 2개의 체크가 있습니다. (각각 1개의 체크가 있는 루프가 2개인 대신).)실제로 절약할 수 있는 유일한 것은 1루프의 오버헤드입니다.말씀하신 것처럼 어레이가 정말 크면 실제 루프의 워크로드에 비해 오버헤드가 작습니다.(이 모든 것은 C에서 구현되므로 루프는 어느 정도 자유롭다는 점에 유의하십시오.)


편집 저를 지지하고 믿어주신 4분께 죄송합니다.이를 최적화할 수 있습니다.

여기 파이썬 모듈로 컴파일할 수 있는 포트란 코드가 있습니다.f2py (아마도)CythonGuru는 이를 최적화된 C 버전과 비교할 수 있습니다.

subroutine minmax1(a,n,amin,amax)
  implicit none
  !f2py intent(hidden) :: n
  !f2py intent(out) :: amin,amax
  !f2py intent(in) :: a
  integer n
  real a(n),amin,amax
  integer i

  amin = a(1)
  amax = a(1)
  do i=2, n
     if(a(i) > amax)then
        amax = a(i)
     elseif(a(i) < amin) then
        amin = a(i)
     endif
  enddo
end subroutine minmax1

subroutine minmax2(a,n,amin,amax)
  implicit none
  !f2py intent(hidden) :: n
  !f2py intent(out) :: amin,amax
  !f2py intent(in) :: a
  integer n
  real a(n),amin,amax
  amin = minval(a)
  amax = maxval(a)
end subroutine minmax2

다음을 통해 컴파일:

f2py -m untitled -c fortran_code.f90

이제 우리는 그것을 테스트할 수 있는 곳에 있습니다.

import timeit

size = 100000
repeat = 10000

print timeit.timeit(
    'np.min(a); np.max(a)',
    setup='import numpy as np; a = np.arange(%d, dtype=np.float32)' % size,
    number=repeat), " # numpy min/max"

print timeit.timeit(
    'untitled.minmax1(a)',
    setup='import numpy as np; import untitled; a = np.arange(%d, dtype=np.float32)' % size,
    number=repeat), '# minmax1'

print timeit.timeit(
    'untitled.minmax2(a)',
    setup='import numpy as np; import untitled; a = np.arange(%d, dtype=np.float32)' % size,
    number=repeat), '# minmax2'

결과는 저에게 조금 충격적입니다.

8.61869883537 # numpy min/max
1.60417699814 # minmax1
2.30169081688 # minmax2

저는 그것을 완전히 이해하지 못한다고 말해야 합니다. 방금비기하 비교하기.np.minminmax1그리고.minmax2아직 패배한 전투이기 때문에 단순한 기억력 문제가 아닙니다.

참고 - 크기를 다음의 비율로 늘립니다.10**a그리고 반복 횟수를 몇 배로 감소시킵니다.10**a(문제 크기를 일정하게 유지하는 것은 성능을 변화시키지만 파이썬에서 메모리 성능과 함수 호출 오버헤드 사이에 어느 정도 상호 작용이 있음을 보여주는 일관된 방식은 아닙니다.단순한 것을 비교하는 것 조차도minFortran의 구현은 numpy를 약 2배 능가합니다...

LLVM을 사용하는 NumPy 인식 동적 파이썬 컴파일러인 Numba를 사용할 수 있습니다.결과적으로 구현은 매우 간단하고 명확합니다.

import numpy
import numba


@numba.jit
def minmax(x):
    maximum = x[0]
    minimum = x[0]
    for i in x[1:]:
        if i > maximum:
            maximum = i
        elif i < minimum:
            minimum = i
    return (minimum, maximum)


numpy.random.seed(1)
x = numpy.random.rand(1000000)
print(minmax(x) == (x.min(), x.max()))

Numpy보다 .min() & max()코드 도 작성하지 됩니다.C/Fortran 코드 라인을 하나도 작성하지 않아도 됩니다.

항상 아키텍처, 데이터, 패키지 버전에 따라 다르므로 성능 테스트를 직접 수행하십시오.

numpy.ptp라고 하는 (max-min)을 찾는 기능이 있습니다. 이 기능이 유용한 경우:

>>> import numpy
>>> x = numpy.array([1,2,3,4,5,6])
>>> x.ptp()
5

하지만 한 번의 횡단으로 최소와 최대를 모두 찾을 수 있는 방법은 없다고 생각합니다.

편집: ptp는 후드 아래에서 최소와 최대를 호출합니다.

다음과 같은 접근 방식을 고려할 때 예상할 수 있는 숫자에 대한 아이디어를 얻으려고 합니다.

import numpy as np


def extrema_np(arr):
    return np.max(arr), np.min(arr)
import numba as nb


@nb.jit(nopython=True)
def extrema_loop_nb(arr):
    n = arr.size
    max_val = min_val = arr[0]
    for i in range(1, n):
        item = arr[i]
        if item > max_val:
            max_val = item
        elif item < min_val:
            min_val = item
    return max_val, min_val
import numba as nb


@nb.jit(nopython=True)
def extrema_while_nb(arr):
    n = arr.size
    odd = n % 2
    if not odd:
        n -= 1
    max_val = min_val = arr[0]
    i = 1
    while i < n:
        x = arr[i]
        y = arr[i + 1]
        if x > y:
            x, y = y, x
        min_val = min(x, min_val)
        max_val = max(y, max_val)
        i += 2
    if not odd:
        x = arr[n]
        min_val = min(x, min_val)
        max_val = max(x, max_val)
    return max_val, min_val
%%cython -c-O3 -c-march=native -a
#cython: language_level=3, boundscheck=False, wraparound=False, initializedcheck=False, cdivision=True, infer_types=True


import numpy as np


cdef void _extrema_loop_cy(
        long[:] arr,
        size_t n,
        long[:] result):
    cdef size_t i
    cdef long item, max_val, min_val
    max_val = arr[0]
    min_val = arr[0]
    for i in range(1, n):
        item = arr[i]
        if item > max_val:
            max_val = item
        elif item < min_val:
            min_val = item
    result[0] = max_val
    result[1] = min_val


def extrema_loop_cy(arr):
    result = np.zeros(2, dtype=arr.dtype)
    _extrema_loop_cy(arr, arr.size, result)
    return result[0], result[1]
%%cython -c-O3 -c-march=native -a
#cython: language_level=3, boundscheck=False, wraparound=False, initializedcheck=False, cdivision=True, infer_types=True


import numpy as np


cdef void _extrema_while_cy(
        long[:] arr,
        size_t n,
        long[:] result):
    cdef size_t i, odd
    cdef long x, y, max_val, min_val
    max_val = arr[0]
    min_val = arr[0]
    odd = n % 2
    if not odd:
        n -= 1
    max_val = min_val = arr[0]
    i = 1
    while i < n:
        x = arr[i]
        y = arr[i + 1]
        if x > y:
            x, y = y, x
        min_val = min(x, min_val)
        max_val = max(y, max_val)
        i += 2
    if not odd:
        x = arr[n]
        min_val = min(x, min_val)
        max_val = max(x, max_val)
    result[0] = max_val
    result[1] = min_val


def extrema_while_cy(arr):
    result = np.zeros(2, dtype=arr.dtype)
    _extrema_while_cy(arr, arr.size, result)
    return result[0], result[1]

(그)extrema_loop_*()접근법은 여기서 제안된 것과 유사하지만, 반면에extrema_while_*()접근 방식은 여기서 제공하는 코드를 기반으로 합니다.)

다음 시간:

bm

extrema_while_*()가장 빠릅니다.extrema_while_nb()가장빠른. 한쨌어도 야.extrema_loop_nb()그리고.extrema_loop_cy() 접근 방식(NumPy 사용)을 합니다.np.max()그리고.np.min()별도)

마지막으로, 이 중 어느 것도 다음과 같이 유연하지 않습니다.np.min()/np.max()지원의 에서, (n-dim 지측서에면원,서n에측),axis매개변수 등).

(전체 코드는 여기에서 사용할 수 있습니다.

아무도 마비에 대해 언급하지 않았습니다.백분위수, 그래서 그렇게 생각했어요.만약 당신이 요구한다면[0, 100]백분위수는 최소(0번째 백분위수) 및 최대(100번째 백분위수)의 두 요소 배열을 제공합니다.

하지만, 그것은 OP의 목적을 만족시키지 못합니다: 그것은 min과 max를 따로따로 하는 것보다 빠르지 않습니다.그것은 아마도 극단적이지 않은 백분위수를 허용하는 일부 기계 때문일 것입니다(더 어려운 문제, 오래 걸릴 것입니다).

In [1]: import numpy

In [2]: a = numpy.random.normal(0, 1, 1000000)

In [3]: %%timeit
   ...: lo, hi = numpy.amin(a), numpy.amax(a)
   ...: 
100 loops, best of 3: 4.08 ms per loop

In [4]: %%timeit
   ...: lo, hi = numpy.percentile(a, [0, 100])
   ...: 
100 loops, best of 3: 17.2 ms per loop

In [5]: numpy.__version__
Out[5]: '1.14.4'

Numpy의 미래 버전은 다음과 같은 경우 정규 백분위수 계산을 건너뛰기 위해 특별한 경우를 포함할 수 있습니다.[0, 100]하지 에게 한은 이 인터페이스에 아무것도 추가하지 않고 Numpy에게 한 번의 통화로 min과 max를 요청하는 방법이 있지만(승인된 답변에서 말한 것과 반대로) 라이브러리의 표준 구현은 이 사례를 활용하여 가치를 높이지 않습니다.

일반적으로 한 번에 두 개의 요소를 처리하고 더 작은 것을 임시 최소값과 비교하고 더 큰 것을 임시 최대값과 비교하여 최소 최대값에 대한 비교 양을 줄일 수 있습니다.평균적으로 단순한 접근 방식보다 3/4만 비교하면 됩니다.

이것은 corfortran(또는 다른 낮은 수준의 언어)으로 구현될 수 있으며 성능 면에서 거의 독보적일 것입니다.는 numba를 사용하여 원리를 설명하고 매우 빠르고 dtype 독립적인 구현을 하고 있습니다.

import numba as nb
import numpy as np

@nb.njit
def minmax(array):
    # Ravel the array and return early if it's empty
    array = array.ravel()
    length = array.size
    if not length:
        return

    # We want to process two elements at once so we need
    # an even sized array, but we preprocess the first and
    # start with the second element, so we want it "odd"
    odd = length % 2
    if not odd:
        length -= 1

    # Initialize min and max with the first item
    minimum = maximum = array[0]

    i = 1
    while i < length:
        # Get the next two items and swap them if necessary
        x = array[i]
        y = array[i+1]
        if x > y:
            x, y = y, x
        # Compare the min with the smaller one and the max
        # with the bigger one
        minimum = min(x, minimum)
        maximum = max(y, maximum)
        i += 2

    # If we had an even sized array we need to compare the
    # one remaining item too.
    if not odd:
        x = array[length]
        minimum = min(x, minimum)
        maximum = max(x, maximum)

    return minimum, maximum

Peque가 제시한 순진한 접근 방식보다 훨씬 빠릅니다.

arr = np.random.random(3000000)
assert minmax(arr) == minmax_peque(arr)  # warmup and making sure they are identical 
%timeit minmax(arr)            # 100 loops, best of 3: 2.1 ms per loop
%timeit minmax_peque(arr)      # 100 loops, best of 3: 2.75 ms per loop

구현에 의 약밖에 걸리지 (minmax 구현에는 3/4 정도의 시간이 소요됩니다).2.1 / 2.75 = 0.7636363636363637)

이건 오래된 실타래지만, 어쨌든, 누군가 이걸 다시 본다면...

최소값과 최대값을 동시에 찾을 때 비교 횟수를 줄일 수 있습니다.비교 중인 플로트라면 계산 복잡성은 아니지만 시간을 절약할 수 있습니다.

(파이썬 코드) 대신:

_max = ar[0]
_min=  ar[0]
for ii in xrange(len(ar)):
    if _max > ar[ii]: _max = ar[ii]
    if _min < ar[ii]: _min = ar[ii]

먼저 배열에서 인접한 두 값을 비교한 다음 작은 값을 전류 최소값과 비교하고 큰 값을 전류 최대값과 비교할 수 있습니다.

## for an even-sized array
_max = ar[0]
_min = ar[0]
for ii in xrange(0, len(ar), 2)):  ## iterate over every other value in the array
    f1 = ar[ii]
    f2 = ar[ii+1]
    if (f1 < f2):
        if f1 < _min: _min = f1
        if f2 > _max: _max = f2
    else:
        if f2 < _min: _min = f2
        if f1 > _max: _max = f1

여기서 코드는 Python으로 작성되어 있으며, 속도를 위해 C, Fortran 또는 Cython을 사용할 것이 분명하지만, 이 방법으로 len(ar)/2번 반복하여 반복당 3/2 * len(ar) 비교를 수행할 수 있습니다.이와 반대로, "명백한 방법"으로 비교를 수행하면 반복당 두 번의 비교를 수행하여 2*len(ar)의 비교로 이어집니다.비교 시간을 25% 절약할 수 있습니다.

아마도 언젠가 누군가가 이것을 유용하게 여길 것입니다.

언뜻 보기에 는 속임수를 쓰는 것처럼 보입니다.

count, (amin, amax) = numpy.histogram(a, bins=1)

하지만 그 기능의 소스를 보면 단순히 호출됩니다.a.min()그리고.a.max() 문제를 못합니다 :-(으)로, 이 질문에서 언급된 성능 문제를 피할 수 . :-(

마찬가지로, 가능성처럼 보이지만, 그것 역시 단순히 전화를 걸 뿐입니다.a.min()그리고.a.max()독자적으로

어쨌든 저에게는 노력할 가치가 있었기 때문에, 관심이 있는 사람이라면 누구나 여기서 가장 어렵고 덜 우아한 해결책을 제안하겠습니다.제 솔루션은 C++에서 멀티스레드 최소-최대 알고리즘을 한 번에 구현하고 이를 사용하여 파이썬 확장 모듈을 만드는 것입니다.이러한 노력은 Python 및 NumPy C/C++ API를 사용하는 방법을 배우는 데 약간의 오버헤드가 필요하며, 여기서 코드를 보여주고 이 길을 가고자 하는 사람들을 위해 몇 가지 작은 설명과 참조를 제공할 것입니다.

멀티스레드 최소/최대

여기에는 너무 흥미로운 것이 없습니다.가 큰 청크로 분할됩니다.length / workers는 소최/대값의청대계다니의 각 됩니다.future그런 다음 전역 최소/최대 값을 검색합니다.

    // mt_np.cc
    //
    // multi-threaded min/max algorithm

    #include <algorithm>
    #include <future>
    #include <vector>

    namespace mt_np {

    /*
     * Get {min,max} in interval [begin,end)
     */
    template <typename T> std::pair<T, T> min_max(T *begin, T *end) {
      T min{*begin};
      T max{*begin};
      while (++begin < end) {
        if (*begin < min) {
          min = *begin;
          continue;
        } else if (*begin > max) {
          max = *begin;
        }
      }
      return {min, max};
    }

    /*
     * get {min,max} in interval [begin,end) using #workers for concurrency
     */
    template <typename T>
    std::pair<T, T> min_max_mt(T *begin, T *end, int workers) {
      const long int chunk_size = std::max((end - begin) / workers, 1l);
      std::vector<std::future<std::pair<T, T>>> min_maxes;
      // fire up the workers
      while (begin < end) {
        T *next = std::min(end, begin + chunk_size);
        min_maxes.push_back(std::async(min_max<T>, begin, next));
        begin = next;
      }
      // retrieve the results
      auto min_max_it = min_maxes.begin();
      auto v{min_max_it->get()};
      T min{v.first};
      T max{v.second};
      while (++min_max_it != min_maxes.end()) {
        v = min_max_it->get();
        min = std::min(min, v.first);
        max = std::max(max, v.second);
      }
      return {min, max};
    }
    }; // namespace mt_np

Python 확장 모듈

여기서 상황이 악화되기 시작합니다.Python에서 C++ 코드를 사용하는 한 가지 방법은 확장 모듈을 구현하는 것입니다.은 이모은사구및수있다를 하여 구축 및 할 수 .distutils.core표준 모듈이 문제에 대한 자세한 설명은 Python 문서 https://docs.python.org/3/extending/extending.html 에서 확인할 수 있습니다. 참고: https://docs.python.org/3/extending/index.html#extending-index 를 인용하면 비슷한 결과를 얻을 수 있는 다른 방법이 분명히 있습니다.

이 안내서에서는 이 버전의 CPython의 일부로 제공되는 확장 기능을 만드는 데 필요한 기본 도구에 대해서만 설명합니다.Cython, cffi, SWIG 및 Numba와 같은 타사 도구는 Python용 C 및 C++ 확장을 만드는 더 간단하고 정교한 접근 방식을 제공합니다.

본질적으로, 이 경로는 아마도 실용적이기보다는 더 학문적일 것입니다.그 다음에 제가 한 일은 튜토리얼에 매우 가깝게 모듈 파일을 만드는 것이었습니다.이것은 기본적으로 배포자들이 코드로 무엇을 해야 하는지 알고 그것으로 Python 모듈을 만들기 위한 보일러 플레이트입니다.이 작업을 수행하기 전에 시스템 패키지를 오염시키지 않도록 Python 가상 환경을 만드는 것이 현명할 것입니다(https://docs.python.org/3/library/venv.html#module-venv) 참조).

다음은 모듈 파일입니다.

// mt_np_forpy.cc
//
// C++ module implementation for multi-threaded min/max for np

#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION

#include <python3.6/numpy/arrayobject.h>

#include "mt_np.h"

#include <cstdint>
#include <iostream>

using namespace std;

/*
 * check:
 *  shape
 *  stride
 *  data_type
 *  byteorder
 *  alignment
 */
static bool check_array(PyArrayObject *arr) {
  if (PyArray_NDIM(arr) != 1) {
    PyErr_SetString(PyExc_RuntimeError, "Wrong shape, require (1,n)");
    return false;
  }
  if (PyArray_STRIDES(arr)[0] != 8) {
    PyErr_SetString(PyExc_RuntimeError, "Expected stride of 8");
    return false;
  }
  PyArray_Descr *descr = PyArray_DESCR(arr);
  if (descr->type != NPY_LONGLTR && descr->type != NPY_DOUBLELTR) {
    PyErr_SetString(PyExc_RuntimeError, "Wrong type, require l or d");
    return false;
  }
  if (descr->byteorder != '=') {
    PyErr_SetString(PyExc_RuntimeError, "Expected native byteorder");
    return false;
  }
  if (descr->alignment != 8) {
    cerr << "alignment: " << descr->alignment << endl;
    PyErr_SetString(PyExc_RuntimeError, "Require proper alignement");
    return false;
  }
  return true;
}

template <typename T>
static PyObject *mt_np_minmax_dispatch(PyArrayObject *arr) {
  npy_intp size = PyArray_SHAPE(arr)[0];
  T *begin = (T *)PyArray_DATA(arr);
  auto minmax =
      mt_np::min_max_mt(begin, begin + size, thread::hardware_concurrency());
  return Py_BuildValue("(L,L)", minmax.first, minmax.second);
}

static PyObject *mt_np_minmax(PyObject *self, PyObject *args) {
  PyArrayObject *arr;
  if (!PyArg_ParseTuple(args, "O", &arr))
    return NULL;
  if (!check_array(arr))
    return NULL;
  switch (PyArray_DESCR(arr)->type) {
  case NPY_LONGLTR: {
    return mt_np_minmax_dispatch<int64_t>(arr);
  } break;
  case NPY_DOUBLELTR: {
    return mt_np_minmax_dispatch<double>(arr);
  } break;
  default: {
    PyErr_SetString(PyExc_RuntimeError, "Unknown error");
    return NULL;
  }
  }
}

static PyObject *get_concurrency(PyObject *self, PyObject *args) {
  return Py_BuildValue("I", thread::hardware_concurrency());
}

static PyMethodDef mt_np_Methods[] = {
    {"mt_np_minmax", mt_np_minmax, METH_VARARGS, "multi-threaded np min/max"},
    {"get_concurrency", get_concurrency, METH_VARARGS,
     "retrieve thread::hardware_concurrency()"},
    {NULL, NULL, 0, NULL} /* sentinel */
};

static struct PyModuleDef mt_np_module = {PyModuleDef_HEAD_INIT, "mt_np", NULL,
                                          -1, mt_np_Methods};

PyMODINIT_FUNC PyInit_mt_np() { return PyModule_Create(&mt_np_module); }

이 파일에는 NumPy API뿐만 아니라 Python도 많이 사용됩니다. 자세한 내용은 https://docs.python.org/3/c-api/arg.html#c.PyArg_ParseTuple, 및 NumPy: https://docs.scipy.org/doc/numpy/reference/c-api.array.html 을 참조하십시오.

모듈 설치

다음으로 모듈을 설치하기 위해 디스틸을 사용해야 합니다.설정 파일이 필요합니다.

# setup.py

from distutils.core import setup,Extension

module = Extension('mt_np', sources = ['mt_np_module.cc'])

setup (name = 'mt_np', 
       version = '1.0', 
       description = 'multi-threaded min/max for np arrays',
       ext_modules = [module])

하려면 모을최실다설다니행합음을을 합니다.python3 setup.py install가상 환경에서 사용할 수 있습니다.

모듈 테스트

마지막으로, 우리는 C++ 구현이 실제로 NumPy의 순진한 사용을 능가하는지 테스트할 수 있습니다.이를 위해 다음은 간단한 테스트 스크립트입니다.

# timing.py
# compare numpy min/max vs multi-threaded min/max

import numpy as np
import mt_np
import timeit

def normal_min_max(X):
  return (np.min(X),np.max(X))

print(mt_np.get_concurrency())

for ssize in np.logspace(3,8,6):
  size = int(ssize)
  print('********************')
  print('sample size:', size)
  print('********************')
  samples = np.random.normal(0,50,(2,size))
  for sample in samples:
    print('np:', timeit.timeit('normal_min_max(sample)',
                 globals=globals(),number=10))
    print('mt:', timeit.timeit('mt_np.mt_np_minmax(sample)',
                 globals=globals(),number=10))

이 모든 작업을 통해 얻은 결과는 다음과 같습니다.

8  
********************  
sample size: 1000  
********************  
np: 0.00012079699808964506  
mt: 0.002468645994667895  
np: 0.00011947099847020581  
mt: 0.0020772050047526136  
********************  
sample size: 10000  
********************  
np: 0.00024697799381101504  
mt: 0.002037393998762127  
np: 0.0002713389985729009  
mt: 0.0020942929986631498  
********************  
sample size: 100000  
********************  
np: 0.0007130410012905486  
mt: 0.0019842900001094677  
np: 0.0007540129954577424  
mt: 0.0029724110063398257  
********************  
sample size: 1000000  
********************  
np: 0.0094779249993735  
mt: 0.007134920000680722  
np: 0.009129883001151029  
mt: 0.012836456997320056  
********************  
sample size: 10000000  
********************  
np: 0.09471094200125663  
mt: 0.0453535050037317  
np: 0.09436299200024223  
mt: 0.04188535599678289  
********************  
sample size: 100000000  
********************  
np: 0.9537652180006262  
mt: 0.3957935369980987  
np: 0.9624398809974082  
mt: 0.4019058070043684  

이러한 결과는 스레드에서 앞서 언급한 결과보다 훨씬 덜 고무적입니다. 이 결과는 속도가 약 3.5배 빨라지고 멀티스레딩이 통합되지 않은 것으로 나타났습니다.는 어느 정도이며, 커질 때까지 됩니다. 이 됩니다.std::thread::hardware_concurrencyx 증가

결론

특히 멀티 스레드와 관련하여 일부 NumPy 코드에 대한 애플리케이션별 최적화의 여지가 분명히 있습니다.그것이 노력할 가치가 있는지 아닌지는 저에게 명확하지 않지만, 그것은 확실히 좋은 운동처럼 보입니다.저는 Cython과 같은 "제3자 도구"를 배우는 것이 시간을 더 잘 사용할 수 있다고 생각하지만, 누가 알겠어요.

이전 답변에서 영감을 받아 2-D 어레이에서 axis=0에 대한 minmax를 반환하는 numba 구현을 작성했습니다.numpy min/max를 호출하는 것보다 최대 5배 더 빠릅니다.아마도 누군가가 그것을 유용하게 여길 것입니다.

from numba import jit

@jit
def minmax(x):
    """Return minimum and maximum from 2D array for axis=0."""    
    m, n = len(x), len(x[0])
    mi, ma = np.empty(n), np.empty(n)
    mi[:] = ma[:] = x[0]
    for i in range(1, m):
        for j in range(n):
            if x[i, j]>ma[j]: ma[j] = x[i, j]
            elif x[i, j]<mi[j]: mi[j] = x[i, j]
    return mi, ma

x = np.random.normal(size=(256, 11))
mi, ma = minmax(x)

np.all(mi == x.min(axis=0)), np.all(ma == x.max(axis=0))
# (True, True)


%timeit x.min(axis=0), x.max(axis=0) 
# 15.9 µs ± 9.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit minmax(x) 
# 2.62 µs ± 31.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

제가 생각해낸 가장 짧은 방법은 다음과 같습니다.

mn, mx = np.sort(ar)[[0, -1]]

하지만 배열을 정렬하기 때문에 가장 효율적이지는 않습니다.

또 다른 짧은 방법은 다음과 같습니다.

mn, mx = np.percentile(ar, [0, 100])

이 방법이 더 효율적이어야 하지만 결과가 계산되고 플로트가 반환됩니다.

사용할 수 있음numpy.unique이와 같은 경우:

min_, max_ = numpy.unique(arr)[[0, -1]]

다양성을 위해 여기에 추가했습니다 :) 그것은 정렬만큼 느립니다.

언급URL : https://stackoverflow.com/questions/12200580/numpy-function-for-simultaneous-max-and-min

반응형