Jaki jest najszybszy sposób na skopiowanie danych z tablicy b do tablicy a bez modyfikowania adresu tablicy a. Potrzebuję tego, ponieważ biblioteka zewnętrzna (PyFFTW) używa wskaźnika do mojej tablicy, której nie można zmienić.
Na przykład:
a = numpy.empty(n, dtype=complex)
for i in xrange(a.size):
a[i] = b[i]
Czy można to zrobić bez pętli?
a = b
tworzy jedynie nowe odniesienie dob
.a[:] = b
oznacza „ustaw wszystkie elementy naa
równe zb
”. Różnica jest ważna, ponieważ tablice numpy są zmiennymi typami.empty()
jest około 10% szybsze niżzeros()
. Zaskakująceempty_like()
jest jeszcze szybsze.copyto(a,b)
jest szybszy niż składnia tablicya[:] = b
. Zobacz gist.github.com/bhawkins/5095558np.copyto(a, b)
i kiedya = b.astype(b.dtype)
poprawić szybkość, zobacz odpowiedź poniżej: stackoverflow.com/a/33672015/3703716empty_like
jest o wiele szybszy niżempty
, zwłaszcza żezeros_like
jest wolniejszy niżzeros
. BTW właśnie ponownie uruchomiłem mój benchmark (teraz zaktualizowany) i różnica międzycopyto(a,b)
ia[:] = b
wydaje się, że wyparowała. gist.github.com/bhawkins/5095558NumPy w wersji 1.7 ma
numpy.copyto
funkcję, która robi to, czego szukasz:Zobacz: https://docs.scipy.org/doc/numpy/reference/generated/numpy.copyto.html
źródło
AttributeError: 'module' object has no attribute 'copyto'
jest nawet szybszy niż sugerowane rozwiązania do numpy w wersji 1.6 i również tworzy kopię tablicy. Nie mogłem jednak przetestować go na copyto (a, b), ponieważ nie mam najnowszej wersji numpy.
źródło
Odpowiadając na twoje pytanie, bawiłem się kilkoma wariantami i sprofilowałem je.
Wniosek: aby skopiować dane z tablicy numpy do innej, użyj jednej z wbudowanych funkcji numpy
numpy.array(src)
lubnumpy.copyto(dst, src)
gdziekolwiek jest to możliwe.(Ale zawsze wybieraj późniejsze, jeśli
dst
pamięć jest już przydzielona, aby ponownie użyć pamięci. Zobacz profilowanie na końcu postu).konfiguracja profilowania
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()
kod profilujący
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)})
wyniki dla systemu Windows 7 z procesorem Intel i7, CPython 3.5.0, numpy v1.10.1.
Pokaż fragment kodu
globals: {'n': 100}, tested 1e+06 times time (s) speedup methods 0 0.386908 33.76x y = np.array(x) 1 0.496475 26.31x y = x.astype(x.dtype) 2 0.567027 23.03x y = np.empty_like(x); np.copyto(y, x) 3 0.666129 19.61x y = np.empty_like(x); y[:] = x 4 0.967086 13.51x y = 1*x 5 1.067240 12.24x y = np.empty_like(x); np.copyto(y, x, casting=... 6 1.235198 10.57x y = np.copy(x) 7 1.624535 8.04x y = np.zeros(n, dtype=x.dtype); y[:] = x 8 1.626120 8.03x y = np.empty(n, dtype=x.dtype); y[:] = x 9 3.569372 3.66x y = np.zeros_like(x); y[:] = x 10 13.061154 y = np.empty(n)\nfor i in range(x.size):\n\ty[... globals: {'n': 1000}, tested 1e+06 times time (s) speedup methods 0 0.666237 6.10x y = x.astype(x.dtype) 1 0.740594 5.49x y = np.empty_like(x); np.copyto(y, x) 2 0.755246 5.39x y = np.array(x) 3 1.043631 3.90x y = np.empty_like(x); y[:] = x 4 1.398793 2.91x y = 1*x 5 1.434299 2.84x y = np.empty_like(x); np.copyto(y, x, casting=... 6 1.544769 2.63x y = np.copy(x) 7 1.873119 2.17x y = np.empty(n, dtype=x.dtype); y[:] = x 8 2.355593 1.73x y = np.zeros(n, dtype=x.dtype); y[:] = x 9 4.067133 y = np.zeros_like(x); y[:] = x globals: {'n': 6309}, tested 1e+06 times time (s) speedup methods 0 2.338428 3.05x y = np.array(x) 1 2.466636 2.89x y = x.astype(x.dtype) 2 2.561535 2.78x y = np.empty_like(x); np.copyto(y, x) 3 2.603601 2.74x y = np.empty_like(x); y[:] = x 4 3.005610 2.37x y = np.empty_like(x); np.copyto(y, x, casting=... 5 3.215863 2.22x y = np.copy(x) 6 3.249763 2.19x y = 1*x 7 3.661599 1.95x y = np.empty(n, dtype=x.dtype); y[:] = x 8 6.344077 1.12x y = np.zeros(n, dtype=x.dtype); y[:] = x 9 7.133050 y = np.zeros_like(x); y[:] = x globals: {'n': 10000}, tested 1e+06 times time (s) speedup methods 0 3.421806 2.82x y = np.array(x) 1 3.569501 2.71x y = x.astype(x.dtype) 2 3.618747 2.67x y = np.empty_like(x); np.copyto(y, x) 3 3.708604 2.61x y = np.empty_like(x); y[:] = x 4 4.150505 2.33x y = np.empty_like(x); np.copyto(y, x, casting=... 5 4.402126 2.19x y = np.copy(x) 6 4.917966 1.96x y = np.empty(n, dtype=x.dtype); y[:] = x 7 4.941269 1.96x y = 1*x 8 8.925884 1.08x y = np.zeros(n, dtype=x.dtype); y[:] = x 9 9.661437 y = np.zeros_like(x); y[:] = x globals: {'n': 100000}, tested 1e+05 times time (s) speedup methods 0 3.858588 2.63x y = x.astype(x.dtype) 1 3.873989 2.62x y = np.array(x) 2 3.896584 2.60x y = np.empty_like(x); np.copyto(y, x) 3 3.919729 2.58x y = np.empty_like(x); np.copyto(y, x, casting=... 4 3.948563 2.57x y = np.empty_like(x); y[:] = x 5 4.000521 2.53x y = np.copy(x) 6 4.087255 2.48x y = np.empty(n, dtype=x.dtype); y[:] = x 7 4.803606 2.11x y = 1*x 8 6.723291 1.51x y = np.zeros_like(x); y[:] = x 9 10.131983 y = np.zeros(n, dtype=x.dtype); y[:] = x globals: {'n': 1000000}, tested 3e+04 times time (s) speedup methods 0 85.625484 1.24x y = np.empty_like(x); y[:] = x 1 85.693316 1.24x y = np.empty_like(x); np.copyto(y, x) 2 85.790064 1.24x y = np.empty_like(x); np.copyto(y, x, casting=... 3 86.342230 1.23x y = np.empty(n, dtype=x.dtype); y[:] = x 4 86.954862 1.22x y = np.zeros(n, dtype=x.dtype); y[:] = x 5 89.503368 1.18x y = np.array(x) 6 91.986177 1.15x y = 1*x 7 95.216021 1.11x y = np.copy(x) 8 100.524358 1.05x y = x.astype(x.dtype) 9 106.045746 y = np.zeros_like(x); y[:] = x
Zobacz również wyniki dla wariantu profilowania, w którym pamięć miejsca docelowego jest już wstępnie przydzielona podczas kopiowania wartości, ponieważ
y = np.empty_like(x)
jest częścią konfiguracji:Pokaż fragment kodu
globals: {'n': 100}, tested 1e+06 times time (s) speedup methods 0 0.328492 2.33x np.copyto(y, x) 1 0.384043 1.99x y = np.array(x) 2 0.405529 1.89x y[:] = x 3 0.764625 np.copyto(y, x, casting='no') globals: {'n': 1000}, tested 1e+06 times time (s) speedup methods 0 0.453094 1.95x np.copyto(y, x) 1 0.537594 1.64x y[:] = x 2 0.770695 1.15x y = np.array(x) 3 0.884261 np.copyto(y, x, casting='no') globals: {'n': 6309}, tested 1e+06 times time (s) speedup methods 0 2.125426 1.20x np.copyto(y, x) 1 2.182111 1.17x y[:] = x 2 2.364018 1.08x y = np.array(x) 3 2.553323 np.copyto(y, x, casting='no') globals: {'n': 10000}, tested 1e+06 times time (s) speedup methods 0 3.196402 1.13x np.copyto(y, x) 1 3.523396 1.02x y[:] = x 2 3.531007 1.02x y = np.array(x) 3 3.597598 np.copyto(y, x, casting='no') globals: {'n': 100000}, tested 1e+05 times time (s) speedup methods 0 3.862123 1.01x np.copyto(y, x) 1 3.863693 1.01x y = np.array(x) 2 3.873194 1.01x y[:] = x 3 3.909018 np.copyto(y, x, casting='no')
źródło
x.copy()
jest tak szybki, jaknp.array(x)
i bardziej podoba mi się składnia:$ 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
. Mam podobne wyniki dlanp.array(x)
. Testowane na Linuksie z i5-4210U i numpy 1.10.4np.copy
jest bardziej wyrozumiały:np.copy(False)
,np.copy(None)
nadal pracować, gdya = None; a.copy()
rzucaAttributeError: 'NoneType' object has no attribute 'copy'
. Ponadto jesteśmy bardziej precyzyjni w deklarowaniu tego, co chcemy, aby się wydarzyło w tym wierszu kodu, używając funkcji zamiast składni metody.np.copy(None)
że nie rzuca błędu, jest naprawdę niepytoniczny. Jeszcze jeden powód do użyciaa.copy()
:)y[:] = x
jest teraz nieznacznie szybszy niżcopyto(y, x)
. Kod i dane wyjściowe na gist.github.com/bhawkins/7cdbd5b9372cb798e34e21f92279d2dcmożesz łatwo używać:
b = 1*a
jest to najszybszy sposób, ale mają też pewne problemy. Jeśli nie zdefiniujesz bezpośrednio
dtype
of,a
a także nie zaznaczyszdtype
ofb
, możesz wpaść w kłopoty. Na przykład: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
Mam nadzieję, że potrafię jasno to wyjaśnić. Czasami będziesz mieć zmianę typu danych za pomocą jednej małej operacji.
źródło
a = numpy.zeros(len(b))
luba = numpy.empty(n,dtype=complex)
też utworzy nową tablicę.Możesz zrobić wiele różnych rzeczy:
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)
Rzeczy, które nie działają
a=b a=b[:] # This have given my code bugs
źródło
Dlaczego nie skorzystać
a = 0 + b
Myślę, że jest podobny do poprzedniego mnożenia, ale może być prostszy.
źródło