Cython con array di lunghezza variabile
Gli array in crescita dinamica sono un tipo di array. Sono molto utili quando non si conosce la dimensione esatta dell'array in fase di progettazione. Per prima cosa devi definire un numero iniziale di elementi. ( Wikipedia )
Ho scritto una soluzione Python e l'ho convertita in Cython . Cython può essere utilizzato per migliorare la velocità dei cicli for annidati in Python. Dove il mio codice Cython è leggermente più veloce. La mia soluzione Cython ovviamente non è la più veloce. Sto cercando di eseguire un ciclo for annidato simile a quello nel mio codice Python il più velocemente possibile in Cython.
Sarebbe utile avere un po 'di esperienza in C, cosa che io no. Il problema principale che ho riscontrato è che Cython ha regole di scoping diverse da Python. Poiché C e Python hanno regole di scoping differenti. In altre parole, non possiamo creare un nuovo vettore nel ciclo e assegnargli lo stesso nome.
La mia soluzione funziona ma è troppo lenta. Chiunque può migliorare il codice Cython sopra utilizzando un approccio più simile a C.
Pitone
import numpy as np
my_list = [1,2,3]
n = 10
a = 0.5
Estimate_1_list = []
Estimate_2_list = []
for l in my_list:
# Resizable matrices
a_mat = np.zeros((l,n+1),float)
b_mat = np.zeros((l,n+1),float)
for i in range(n):
t = i*a
for j in range(l):
# Fill matrices
a_mat[j,i+1] = a_mat[j,i+1] + np.random.random()
b_mat[j,i+1] = a_mat[j,i+1]/(2*t+3)
# Append values of interest to use at different values of matrix size
Estimate_1_list.append(np.mean(a_mat[:,n]))
Estimate_2_list.append(np.std(a_mat[:,n]))
results = [Estimate_1_list,Estimate_2_list]
Cython
import cython
# Load cython extension
%load_ext Cython
%%cython
import numpy as np
def my_function(list my_list, int n, int a ):
cdef list Estimate_1_list = []
cdef list Estimate_2_list = []
cdef int l,i,t,j
for l in my_list:
# Resizable matrices (could I use memory view?)
a_mat = np.zeros((l,n+1),float)
b_mat = np.zeros((l,n+1),float)
for i in range(n):
t = i*a
for j in range(l):
# Fill matrices
a_mat[j,i+1] = a_mat[j,i+1] + np.random.random()
b_mat[j,i+1] = a_mat[j,i+1]/(2*t+3)
# Append values of interest to use at different values of matrix size
Estimate_1_list.append(np.mean(a_mat[:,n]))
Estimate_2_list.append(np.std(a_mat[:,n]))
# Return results
results = [Estimate_1_list,Estimate_2_list]
return results
Test
# Test cython to show that the function is running
my_list = [1,2,3]
n = 10
a = 0.5
my_function(my_list, n, a)
[[0.13545224609230933, 0.6603542545719762, 0.6632002117071227],
[0.0, 0.19967544614685195, 0.22125180486616808]]
Risposte
Zeri
Questo:
a_mat = np.zeros
non è la chiamata giusta per il tuo scopo. Vuoi np.emptyinvece, perché in realtà non ti interessa quali sono i valori iniziali poiché fai un ciclo di inizializzazione completo subito dopo.
Inoltre: dal momento che stai aggiungendo random()a ogni elemento di a_mat, inizializza semplicemente a_mata una singola chiamata di random()con la forma corretta, piuttosto che dover eseguire l'aggiunta in termini di elemento.
Vettorizzazione
Hai una dimensione esterna ( lattraverso my_list), una seconda dimensione ( l) e una terza dimensione ( n + 1). La seconda dimensione è variabile; il primo e il terzo sono costanti. Ciò significa che puoi rappresentarlo in modo più efficiente se riorganizzi le dimensioni in modo che quelle fisse siano all'interno. In altre parole, se lo avessi fatto
len(my_list) = 3
l = 1, 2, 3
n = 10
allora puoi effettivamente rappresentarlo come un'unica matrice tridimensionale di dimensioni 6 * 3 * 10, dove 6 == len(my_list) * (len(my_list) - 1). Penso che sia possibile fare tutto questo senza un singolo forloop, che è l'ideale per le prestazioni vettorializzate.