numpy 배열에서 다른 배열로 데이터를 복사하는 방법


87

배열 a의 주소를 수정하지 않고 배열 b에서 배열 a로 데이터를 복사하는 가장 빠른 방법은 무엇입니까? 외부 라이브러리 (PyFFTW)가 변경할 수없는 배열에 대한 포인터를 사용하기 때문에 이것이 필요합니다.

예를 들면 :

a = numpy.empty(n, dtype=complex)
for i in xrange(a.size):
  a[i] = b[i]

루프없이 할 수 있습니까?

답변:


89

나는 믿는다

a = numpy.empty_like (b)
a[:] = b

딥 카피를 빠르게 만들 것입니다. Funsi가 언급했듯이 최신 버전의 numpy에도 copyto기능이 있습니다.


4
+1. 그러나 numpy.emptynumpy.zeros 보다 상당히 빠르지 않습니까 ?
mg007

9
@ M.ElSaka는 a = b단지 b. a[:] = b"모든 요소를 a동일하게 설정"을 의미 b합니다. numpy 배열은 변경 가능한 유형이기 때문에 차이점이 중요합니다.
Brian Hawkins 2013 년

14
mg007 @ 내가 보여 일부 검사가 실행 empty()약 10 %보다 더 빨리이다 zeros(). 놀랍게도 empty_like()더 빠릅니다. copyto(a,b)배열 구문보다 빠릅니다 a[:] = b. gist.github.com/bhawkins/5095558
Brian Hawkins

2
@Brian Hawkins가 맞습니다. 사용시기 np.copyto(a, b)a = b.astype(b.dtype)속도 향상 시기 는 아래 답변을 참조하십시오. stackoverflow.com/a/33672015/3703716
mab

1
@michael_n 놀랐 습니다 . 특히 는보다 느리기 때문에 empty_like보다 훨씬 빠릅니다 . BTW 난 그냥 (지금 업데이트) 내 벤치 마크를-실행 다시, 그리고 사이의 차이 와는 증발 것 같습니다. gist.github.com/bhawkins/5095558emptyzeros_likezeroscopyto(a,b)a[:] = b
브라이언 호킨스


20
a = numpy.array(b)

numpy v1.6까지 제안 된 솔루션보다 훨씬 빠르며 배열의 복사본도 만듭니다. 그러나 최신 버전의 numpy가 없기 때문에 copyto (a, b)에 대해 테스트 할 수 없습니다.


이것은 배열을 복사하는 좋은 방법이지만 새로운 객체를 생성합니다. OP는 이미 생성 된 배열에 값을 빠르게 할당하는 방법을 알아야합니다.
Brian Hawkins

16

귀하의 질문에 답하기 위해 몇 가지 변형을 사용하여 프로파일 링했습니다.

결론 : numpy 배열에서 다른 배열로 데이터를 복사하려면 내장 된 numpy 함수 중 하나를 사용 numpy.array(src)하거나 numpy.copyto(dst, src)가능할 때마다 사용하십시오.

(하지만 dst의 메모리가 이미 할당 된 경우 항상 나중에 선택하여 메모리를 재사용합니다. 게시물 끝에있는 프로파일 링을 참조하십시오.)

프로파일 링 설정

import timeit
import numpy as np
import pandas as pd
from IPython.display import display

def profile_this(methods, setup='', niter=10 ** 4, p_globals=None, **kwargs):
    if p_globals is not None:
        print('globals: {0}, tested {1:.0e} times'.format(p_globals, niter))
    timings = np.array([timeit.timeit(method, setup=setup, number=niter,
                                      globals=p_globals, **kwargs) for 
                        method in methods])
    ranking = np.argsort(timings)
    timings = np.array(timings)[ranking]
    methods = np.array(methods)[ranking]
    speedups = np.amax(timings) / timings

    pd.set_option('html', False)
    data = {'time (s)': timings,
            'speedup': ['{:.2f}x'.format(s) if 1 != s else '' for s in speedups],
            'methods': methods}
    data_frame = pd.DataFrame(data, columns=['time (s)', 'speedup', 'methods'])

    display(data_frame)
    print()

프로파일 링 코드

setup = '''import numpy as np; x = np.random.random(n)'''
methods = (
    '''y = np.zeros(n, dtype=x.dtype); y[:] = x''',
    '''y = np.zeros_like(x); y[:] = x''',
    '''y = np.empty(n, dtype=x.dtype); y[:] = x''',
    '''y = np.empty_like(x); y[:] = x''',
    '''y = np.copy(x)''',
    '''y = x.astype(x.dtype)''',
    '''y = 1*x''',
    '''y = np.empty_like(x); np.copyto(y, x)''',
    '''y = np.empty_like(x); np.copyto(y, x, casting='no')''',
    '''y = np.empty(n)\nfor i in range(x.size):\n\ty[i] = x[i]'''
)

for n, it in ((2, 6), (3, 6), (3.8, 6), (4, 6), (5, 5), (6, 4.5)):
    profile_this(methods[:-1:] if n > 2 else methods, setup, 
                 niter=int(10 ** it), p_globals={'n': int(10 ** n)})

Intel i7 CPU, CPython v3.5.0, numpy v1.10.1의 Windows 7에 대한 결과 .


또한는 설정의 일부 이므로 값 복사 중에 대상의 메모리가 이미 사전 할당 된 프로파일 링 변형에 대한 결과를 참조하십시오 y = np.empty_like(x).


또한 x.copy()빠르며 np.array(x)구문이 훨씬 더 좋습니다 $ python3 -m timeit -s "import numpy as np; x = np.random.random((100, 100))" "x.copy()".- 100000 loops, best of 3: 4.7 usec per loop. 에 대해 비슷한 결과가 np.array(x)있습니다. i5-4210U 및 numpy 1.10.4로 Linux에서 테스트 됨
Marco Sulla

예, Marco, 그것은 오히려 개인적인 취향의 문제입니다. 그러나 그것은 np.copy더 용서합니다 : np.copy(False), np.copy(None)여전히 작동하지만 a = None; a.copy()던지기 AttributeError: 'NoneType' object has no attribute 'copy'. 또한 메서드 구문 대신 함수를 사용하여이 코드 줄에서 원하는 작업을 선언하는 데 더 정확합니다.
mab

1
글쎄, 사실 np.copy(None)은 오류를 던지지 않는다는 것은 정말 비 파이썬 적입니다. 더 사용하는 한 가지 이유 a.copy():
마르코 술라

1
방금 Python 2.7.12, NumPy 1.11.2로이 벤치 마크를 실행 한 y[:] = x결과 copyto(y, x). gist.github.com/bhawkins/7cdbd5b9372cb798e34e21f92279d2dc의
Brian Hawkins

10

쉽게 사용할 수 있습니다.

b = 1*a

이것은 가장 빠른 방법이지만 몇 가지 문제가 있습니다. dtypeof를 직접 정의 a하지 않고 dtypeof b를 확인하지 않으면 문제가 발생할 수 있습니다. 예를 들면 :

a = np.arange(10)        # dtype = int64
b = 1*a                  # dtype = int64

a = np.arange(10.)       # dtype = float64
b = 1*a                  # dtype = float64

a = np.arange(10)        # dtype = int64
b = 1. * a               # dtype = float64

나는 요점을 분명히 할 수 있기를 바랍니다. 때로는 작은 작업만으로 데이터 유형이 변경 될 수 있습니다.


1
아니요. 이렇게하면 새 어레이가 생성됩니다. b = a.copy ()와 같습니다.
Charles Brunet 2011 년

미안하지만 이해가 안 돼요 새 어레이 생성이란 무엇을 의미합니까? 여기에 제시된 다른 모든 방법은 동일한 동작을합니다. a = numpy.zeros(len(b))또는 a = numpy.empty(n,dtype=complex)새 배열을 만듭니다.
ahelm

2
= numpy.empty (1000)이 있다고 가정합니다. 이제 메모리에서 주소를 변경하지 않고 데이터로 a를 채워야합니다. a [0] = 1을 수행하면 배열을 다시 만들지 않고 배열의 내용 만 변경합니다.
Charles Brunet 2011 년

1
@CharlesBrunet 배열은 어느 시점에서 생성되어야합니다. 이 영리한 원 라이너는 한 번의 작업으로 모든 작업을 수행합니다.
heltonbiker 2013 년

7

수행 할 수있는 작업에는 여러 가지가 있습니다.

a=np.copy(b)
a=np.array(b) # Does exactly the same as np.copy
a[:]=b # a needs to be preallocated
a=b[np.arange(b.shape[0])]
a=copy.deepcopy(b)

작동하지 않는 것

a=b
a=b[:] # This have given my code bugs 

2

사용하지 않는 이유

a = 0 + b

이전 곱셈과 비슷하지만 더 간단 할 수 있습니다.

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