numpy 배열을 뒤집는 가장 효율적인 방법


276

현재 코드를 프로파일 링 한 후, numpy array reversion의 반복 작업은 실행 시간의 큰 덩어리를 믿었습니다. 내가 지금 가지고있는 것은 일반적인보기 기반 방법입니다.

reversed_arr = arr[::-1]

더 효율적으로 수행 할 수있는 다른 방법이 있습니까, 아니면 비현실적 인 numpy 성능에 대한 집착에서 온 환상입니까?


27
어 ... arr[::-1]그냥 반전보기를 반환합니다. 가능한 한 빠르며 보폭을 변경하기 때문에 배열의 항목 수에 의존하지 않습니다. 실제로 당신이 numpy 배열을 반전시키는 것입니까?
Joe Kington

예, 실제로 arr는 numpy 배열입니다.
nye17

12
흠 ... 글쎄, 내 노트북에서 배열의 길이에 관계없이 약 670 나노 초가 걸립니다. 이것이 병목 현상이라면 언어를 전환해야 할 수도 있습니다 ... 당신은 numpy 배열을 역전시키는 더 빠른 방법을 찾지 못할 것이라고 확신합니다. 아무튼 행운을 빌어 요!
Joe Kington

6
글쎄, 반드시 루프 안에서 실행해야합니까? 경우에 따라 수백만 개의 항목으로 numpy 배열을 만든 다음 전체 배열에서 작동하는 것이 좋습니다. 유한 차분 법 또는 결과가 이전 결과에 의존하는 유사한 방법을 사용하더라도 때때로 이렇게 할 수 있습니다. (때때로 공허함 ...) 어쨌든 속도가 주요 목표라면, 포트란은 여전히 ​​왕입니다. f2py당신의 친구입니다! 다른 언어로 알고리즘의 성능 핵심 부분 (특히 과학 컴퓨팅에서)을 작성하고 파이썬에서 호출하는 것이 종종 가치가 있습니다. 행운을 빕니다!
Joe Kington

1
@berto. 래퍼이기 때문에 느린 arr[::-1]: github.com/numpy/numpy/blob/master/numpy/lib/twodim_base.py가 . 를 검색하십시오 def flipud. 기능은 문자 그대로 4 줄입니다.
Mad Physicist

답변:


239

만들 때 reversed_arr원래 배열로보기를 만듭니다 . 그런 다음 원래 배열을 변경하면 변경 사항을 반영하여보기가 업데이트됩니다.

필요한 것보다 더 자주 뷰를 다시 작성합니까? 다음과 같은 작업을 수행 할 수 있어야합니다.

arr = np.array(some_sequence)
reversed_arr = arr[::-1]

do_something(arr)
look_at(reversed_arr)
do_something_else(arr)
look_at(reversed_arr)

나는 numpy 전문가는 아니지만 numpy에서 일을하는 가장 빠른 방법 인 것 같습니다. 이것이 당신이 이미하고있는 일이라면, 당신이 그것을 향상시킬 수 있다고 생각하지 않습니다.

추신 : numpy views에 대한 훌륭한 토론 :

numpy 배열을 보시겠습니까?


슬라이스 객체를 만든 다음 많은 배열에서 재사용하는 데 도움이됩니까?
endolith

1
실제로 방금 테스트했으며 루프 외부에서 만든 슬라이스 객체와의 차이점을 보지 못했습니다. (오, 그것은 약간 빠른 매우이다, 기다려 1000000 루프 44.3 밀리 대 반복적으로 43.4 MS.)
endolith

look_at기능 은 무엇 을해야합니까?
mrgloom

1
@mrgloom 데이터를 보는 모든 작업을 나타냅니다. 예제의 요점은 reversed_arr기본 데이터가 변경된 후에도 뷰 를 계속 사용할 수 있음을 보여주는 것입니다 . 배열에 새 값을 쓰더라도 뷰가 무효화되지는 않습니다. 실제로 새 값을 배열에 쓰는 데보기를 사용할 수도 있습니다. reversed_arr[0] = 99배열의 마지막 요소를 99와 동일하게 설정합니다 arr[-1] = 99.
steveha

60

위에서 언급했듯이 a[::-1]실제로보기 만 생성하므로 일정 시간 작업입니다 (배열이 커질수록 시간이 오래 걸리지 않습니다). 당신이 연속으로 배열을해야하는 경우 (예를 들어, 당신은 그것으로 많은 벡터 연산을 수행하고 있기 때문에) ascontiguousarray최대한 빨리 약 flipup/ fliplr:

여기에 이미지 설명을 입력하십시오


플롯을 생성하는 코드 :

import numpy
import perfplot


perfplot.show(
    setup=lambda n: numpy.random.randint(0, 1000, n),
    kernels=[
        lambda a: a[::-1],
        lambda a: numpy.ascontiguousarray(a[::-1]),
        lambda a: numpy.fliplr([a])[0],
    ],
    labels=["a[::-1]", "ascontiguousarray(a[::-1])", "fliplr"],
    n_range=[2 ** k for k in range(25)],
    xlabel="len(a)",
    logx=True,
    logy=True,
)

perfplot 파이썬 3.6은 F-문자열 (리터럴 문자열 보간)을 사용하기 때문에 적어도 필요
fivef

42

이 답변은 아직 답변으로 표시되지 않은 것 같습니다 ... Thomas Arildsen의 답변은 올바른 답변이어야합니다.

np.flipud(your_array) 

1d 배열 인 경우 (열 배열)

matrizes와 함께

fliplr(matrix)

flipud(matrix)을 뒤집고 열을 뒤집 으려는 경우. 1 차원 열 배열을 2 차원 행 배열 (하나의 없음 레이어가있는 행렬)로 만든 다음 뒤집을 필요가 없습니다.


38

np.fliplr() 배열을 왼쪽에서 오른쪽으로 뒤집습니다.

1d 배열의 경우 약간 트릭해야합니다.

arr1d = np.array(some_sequence)
reversed_arr = np.fliplr([arr1d])[0]

34
reversed_arr = np.flipud(arr1d)직접 작동하는 것 같습니다.
Thomas Arildsen

3

에 대한 이전 답변을 확장하겠습니다 np.fliplr(). 다음은 1d 배열 구성, 2d 배열로 변환, 뒤집기, 다시 1d 배열로 변환하는 방법을 보여주는 코드입니다. time.clock()시간을 유지하는 데 사용되며 초 단위로 표시됩니다.

import time
import numpy as np

start = time.clock()
x = np.array(range(3))
#transform to 2d
x = np.atleast_2d(x)
#flip array
x = np.fliplr(x)
#take first (and only) element
x = x[0]
#print x
end = time.clock()
print end-start

주석이 인쇄되지 않은 상태에서 :

[2 1 0]
0.00203907123594

주석이 인쇄 된 상태에서 :

5.59799927506e-05

따라서 효율성 측면에서 보면 괜찮습니다. 한 줄로 그것을 좋아하는 당신을 위해, 여기 그 형태가 있습니다.

np.fliplr(np.atleast_2d(np.array(range(3))))[0]

3
그런 작은 배열로 무언가를 타이밍하는 것은 꽤 쓸모가 없습니다. 사물을 비교하려면 3000 이상 또는 더 많은 요소와 같이 시간이 오래 걸리는 것을 사용하는 것이 좋습니다.
바라 바스

0

다른 사람들이 말한 것을 확장하면 간단한 예를 들어 보겠습니다.

1D 어레이가있는 경우 ...

>>> import numpy as np
>>> x = np.arange(4) # array([0, 1, 2, 3])
>>> x[::-1] # returns a view
Out[1]: 
array([3, 2, 1, 0])

그러나 2D 배열로 작업하는 경우 ...

>>> x = np.arange(10).reshape(2, 5)
>>> x
Out[2]:
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])

>>> x[::-1] # returns a view:
Out[3]: array([[5, 6, 7, 8, 9],
               [0, 1, 2, 3, 4]])

이것은 실제로 매트릭스를 반전시키지 않습니다.

실제로 요소를 반전시키기 위해 np.flip을 사용해야합니다

>>> np.flip(x)
Out[4]: array([[9, 8, 7, 6, 5],
               [4, 3, 2, 1, 0]])

행렬의 요소를 하나씩 인쇄하려면 뒤집기와 함께 평면을 사용하십시오.

>>> for el in np.flip(x).flat:
>>>     print(el, end = ' ')
9 8 7 6 5 4 3 2 1 0

-1

음수와 긴 목록으로 작업하려면 다음을 수행하십시오.

b = numpy.flipud(numpy.array(a.split(),float))

flipud는 1d arra를위한 곳

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.