2015-10-28 9 views
12

È generalmente sicuro fornire l'array di input come argomento opzionale out a un ufunc in numpy, a condizione che il tipo sia corretto? Ad esempio, Ho verificato che i seguenti lavori:Numpy passa all'array di input come argomento `out` su ufunc

>>> import numpy as np 
>>> arr = np.array([1.2, 3.4, 4.5]) 
>>> np.floor(arr, arr) 
array([ 1., 3., 4.]) 

Il tipo array deve essere compatibile o identici con l'uscita (che è un galleggiante per numpy.floor()), o questo accade:

>>> arr2 = np.array([1, 3, 4], dtype = np.uint8) 
>>> np.floor(arr2, arr2) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: ufunc 'floor' output (typecode 'e') could not be coerced to provided output parameter (typecode 'B') according to the casting rule ''same_kind'' 

Quindi, dato che un array di tipo corretto, è generalmente sicuro applicare gli ufuncs sul posto? O è floor() un caso eccezionale? La documentazione non rende chiaro, e nemmeno i seguenti due fili che hanno cuscinetto tangenziale sulla domanda:

  1. Numpy modify array in place?
  2. Numpy Ceil and Floor "out" Argument

EDIT:

Come supposizione del primo ordine, suppongo che sia spesso, ma non sempre sicuro, basato sul tutorial su http://docs.scipy.org/doc/numpy/user/c-info.ufunc-tutorial.html. Non sembra esserci alcuna restrizione sull'uso della matrice di output come supporto temporaneo per risultati intermedi durante il calcolo. Mentre qualcosa come floor() e ciel() potrebbe non richiedere l'archiviazione temporanea, potrebbero essere necessarie funzioni più complesse. Detto questo, l'intera libreria esistente potrebbe essere scritta con questo in mente.

+2

Non è tecnicamente un ufunc, ma l'utilizzo del parametro 'out' in' np.dot' in questo modo con gli array 2D può produrre risultati errati. –

+0

Questo è quasi il controesempio che stavo cercando, ma non del tutto :) –

+3

I [ufunc docs] (http://docs.scipy.org/doc/numpy/reference/ufuncs.html) menzionano usando 'add (G, C, G) 'come ottimizzazione di' G = G + C', nel suggerimento sotto "Operazioni matematiche". Direi che è sicuro. (D'altra parte, chiamare ufuncs con input e output sovrapposti ma non identici * causerà problemi.) – user2357112

risposta

2

Il parametro out di una funzione numpy è la matrice in cui è scritto il risultato. Il vantaggio principale dell'utilizzo di out consiste nell'evitare l'allocazione di nuova memoria laddove non è necessario.

È sicuro utilizzare l'output di una funzione sullo stesso array passato come input? Non c'è una risposta generale, dipende da cosa sta facendo la funzione.

Due esempi

Ecco due esempi di funzioni ufunc simili:

In [1]: def plus_one(x, out=None): 
    ...:  if out is None: 
    ...:   out = np.zeros_like(x) 
    ...: 
    ...:  for i in range(x.size): 
    ...:   out[i] = x[i] + 1 
    ...:  return out 
    ...: 

In [2]: x = np.arange(5) 

In [3]: x 
Out[3]: array([0, 1, 2, 3, 4]) 

In [4]: y = plus_one(x) 

In [5]: y 
Out[5]: array([1, 2, 3, 4, 5]) 

In [6]: z = plus_one(x, x) 

In [7]: z 
Out[7]: array([1, 2, 3, 4, 5]) 

funzione shift_one:

In [11]: def shift_one(x, out=None): 
    ...:  if out is None: 
    ...:   out = np.zeros_like(x) 
    ...: 
    ...:  n = x.size 
    ...:  for i in range(n): 
    ...:   out[(i+1) % n] = x[i] 
    ...:  return out 
    ...: 

In [12]: x = np.arange(5) 

In [13]: x 
Out[13]: array([0, 1, 2, 3, 4]) 

In [14]: y = shift_one(x) 

In [15]: y 
Out[15]: array([4, 0, 1, 2, 3]) 

In [16]: z = shift_one(x, x) 

In [17]: z 
Out[17]: array([0, 0, 0, 0, 0]) 

Per la funzione plus_one non c'è nessun problema: il risultato atteso è ottenuto quando i parametri x e out sono della stessa matrice. Ma la funzione shift_one dà un risultato sorprendente quando i parametri x e fuori sono uguali matrice, poiché la matrice

Discussione

Per funzione della forma out[i] := some_operation(x[i]), come plus_one sopra ma anche le funzioni pavimento, ceil, sin , cos, tan, log, conj, ecc., per quanto ne so, è sicuro per scrivere il risultato nell'input utilizzando il parametro out.

È anche sicuro per le funzioni che assumono due parametri di ingresso del modulo `` out [i] = some_operation (x [i], y [i]) come la funzione NumPy aggiungere, moltiplicare, sottrarre.

Per le altre funzioni, è caso per caso. Come muggito illustrato, la moltiplicazione matrice non è sicuro:

In [18]: a = np.arange(4).reshape((2,2)) 

In [19]: a 
Out[19]: 
array([[0, 1], 
     [2, 3]]) 

In [20]: b = (np.arange(4) % 2).reshape((2,2)) 

In [21]: b 
Out[21]: 
array([[0, 1], 
     [0, 1]], dtype=int32) 

In [22]: c = np.dot(a, b) 

In [23]: c 
Out[23]: 
array([[0, 1], 
     [0, 5]]) 

In [24]: d = np.dot(a, b, out=a) 

In [25]: d 
Out[25]: 
array([[0, 1], 
     [0, 3]]) 

Ultima osservazione: se l'applicazione è multithread, il risultato di una funzione non sicura può anche essere non deterministico perché dipende dall'ordine in cui la gli elementi dell'array vengono elaborati.

Problemi correlati