2012-07-24 22 views
6

Chcę transmitować tablicę b do kształtu, który by zajął, gdyby był operacją arytmetyczną z inną tablicą a.Czy istnieje lepszy sposób nadawania tablic?

Na przykład, jeśli a.shape = (3,3) i b był skalarem, chcę uzyskać tablicę, której kształt to (3,3) i jest wypełniony skalarem.

Jednym ze sposobów na to jest tak:

>>> import numpy as np 
>>> a = np.arange(9).reshape((3,3)) 
>>> b = 1 + a*0 
>>> b 
array([[1, 1, 1], 
     [1, 1, 1], 
     [1, 1, 1]]) 

Chociaż ta działa praktycznie, nie mogę pomóc, ale czuję, że to wygląda trochę dziwnie, a nie być oczywiste dla kogoś innego patrzenia na kodować to, co próbowałem zrobić.

Czy jest jakiś bardziej elegancki sposób na zrobienie tego? Spojrzałem na dokumentację dla np.broadcast, ale wolniej to jest o rząd wielkości.

In [1]: a = np.arange(10000).reshape((100,100)) 

In [2]: %timeit 1 + a*0 
10000 loops, best of 3: 31.9 us per loop 

In [3]: %timeit bc = np.broadcast(a,1);np.fromiter((v for u, v in bc),float).reshape(bc.shape) 
100 loops, best of 3: 5.2 ms per loop 

In [4]: 5.2e-3/32e-6 
Out[4]: 162.5 

Odpowiedz

7

Jeśli chcesz po prostu wypełnić tablicę z skalara, fill jest prawdopodobnie najlepszym wyborem. Ale brzmi to tak, jakbyś chciał czegoś bardziej ogólnego. Zamiast używać broadcast możesz użyć broadcast_arrays, aby uzyskać wynik, który (jak sądzę) chcesz.

>>> a = numpy.arange(9).reshape(3, 3) 
>>> numpy.broadcast_arrays(a, 1)[1] 
array([[1, 1, 1], 
     [1, 1, 1], 
     [1, 1, 1]]) 

ten uogólnia się dowolnymi dwoma broadcastable kształtach:

>>> numpy.broadcast_arrays(a, [1, 2, 3])[1] 
array([[1, 2, 3], 
     [1, 2, 3], 
     [1, 2, 3]]) 

To nie jest aż tak szybko, jak ufunc sposobie opartym na, ale to jeszcze tego samego rzędu wielkości:

>>> %timeit 1 + a * 0 
10000 loops, best of 3: 23.2 us per loop 
>>> %timeit numpy.broadcast_arrays(a, 1)[1] 
10000 loops, best of 3: 52.3 us per loop 

Ale skalary, fill to nadal wyraźny front-runner:

>>> %timeit b = numpy.empty_like(a, dtype='i8'); b.fill(1) 
100000 loops, best of 3: 6.59 us per loop 

Wreszcie dalsze badania pokazują, że najszybszy podejście - przynajmniej w niektórych przypadkach - jest pomnożyć przez ones:

>>> %timeit numpy.broadcast_arrays(a, numpy.arange(100))[1] 
10000 loops, best of 3: 53.4 us per loop 
>>> %timeit (1 + a * 0) * numpy.arange(100) 
10000 loops, best of 3: 45.9 us per loop 
>>> %timeit b = numpy.ones_like(a, dtype='i8'); b * numpy.arange(100) 
10000 loops, best of 3: 28.9 us per loop 
+0

+1 dla 'broadcast_arrays()'. – EOL

+0

Perfect! Właśnie tego szukałem. Jestem zaskoczony, że tego nie widziałem; jest tuż obok 'broadcast' w dokumentach. – user545424

+0

W przypadku, gdy jesteś ciekawy, powodem, dla którego mnie to interesuje jest to, że funkcja 'scipy.ndimage.map_coordinates' nie wysyła automatycznie współrzędnych wejściowych, więc muszę to zrobić ręcznie. – user545424

1

Jeśli wystarczy nadawać skalar w pewnym dowolnym kształcie, można zrobić coś takiego:

a = b*np.ones(shape=(3,3)) 

Edit: np.tile jest bardziej ogólne. Można go używać do powielać żadnej skalarne/wektor w dowolnej liczbie wymiarów:

b = 1 
N = 100 
a = np.tile(b, reps=(N, N)) 
+1

'b * np.ones()' zawiera * multiplikacje *, podczas gdy my tylko potrzebujemy * kopiować * wartości. 'fill()' jest zarówno bardziej odpowiedni, jak i szybszy. – EOL

2

fill brzmi jak najprostszy sposób:

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

EDIT: W @EOL zaznacza, don” t potrzebujesz arange, jeśli chcesz utworzyć nową tablicę, lepiej jest dla tego np.empty((100,100)) (lub innego kształtu).

Timings:

In [3]: a = np.arange(10000).reshape((100,100)) 
In [4]: %timeit 1 + a*0 
100000 loops, best of 3: 19.9 us per loop 

In [5]: a = np.arange(10000).reshape((100,100)) 
In [6]: %timeit a.fill(1) 
100000 loops, best of 3: 3.73 us per loop 
+0

Dlaczego upadek? – Bruno

+0

Nie ma powodu, aby używać 'arange()': to marnuje czas na nic, ponieważ tablica musi zostać utworzona i wypełniona liczbami, które zostaną usunięte. – EOL

+1

@EOL, Właśnie brałem przykład w pytaniu, aby utworzyć tablicę. Nie ma to znaczenia dla tego pytania (zakładałem, że tablica już tam jest, czekając na wypełnienie). – Bruno

1

Najszybszy i najczystsze rozwiązanie znam to:

b_arr = numpy.empty(a.shape) # Empty array 
b_arr.fill(b) # Filling with one value 
Powiązane problemy