Cython mit Arrays variabler Länge
Dynamisch wachsende Arrays sind eine Art Array. Sie sind sehr nützlich, wenn Sie die genaue Größe des Arrays zur Entwurfszeit nicht kennen. Zuerst müssen Sie eine anfängliche Anzahl von Elementen definieren. ( Wikipedia )
Ich habe eine Python-Lösung geschrieben und in Cython konvertiert . Cython kann verwendet werden, um die Geschwindigkeit von verschachtelten for-Schleifen in Python zu verbessern. Wo mein Cython-Code etwas schneller ist. Meine Cython-Lösung ist offensichtlich nicht die schnellste. Ich versuche, eine verschachtelte for-Schleife ähnlich der in meinem Python-Code so schnell wie möglich in Cython auszuführen.
Es würde helfen, etwas Erfahrung in C zu haben, was ich nicht tue. Das Hauptproblem, auf das ich gestoßen bin, ist, dass Cython andere Gültigkeitsregeln als Python hat. Da C und Python unterschiedliche Gültigkeitsregeln haben. Mit anderen Worten, wir können keinen neuen Vektor in der Schleife erstellen und ihn demselben Namen zuweisen.
Meine Lösung funktioniert, ist aber zu langsam. Kann jemand den obigen Cython-Code verbessern, indem er einen C-ähnlichen Ansatz verwendet?
Python
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
Tests
# 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]]
Antworten
Nullen
Dies:
a_mat = np.zeros
ist nicht der richtige Anruf für Ihren Zweck. Sie möchten np.emptystattdessen, weil es Ihnen eigentlich egal ist, wie die Anfangswerte lauten, da Sie direkt danach eine umfassende Initialisierungsschleife durchführen.
Darüber hinaus: Da Sie random()zu jedem Element von hinzufügen a_mat, initialisieren Sie einfach a_mateinen einzelnen Aufruf von random()mit der richtigen Form, anstatt elementweise hinzufügen zu müssen.
Vektorisierung
Sie haben eine äußere Dimension ( ldurch my_list), eine zweite Dimension ( l) und eine dritte Dimension ( n + 1). Die zweite Dimension ist variabel; der erste und der dritte sind konstant. Dies bedeutet, dass Sie dies effizienter darstellen können, wenn Sie Ihre Abmessungen so neu anordnen, dass sich die festen im Innenraum befinden. Mit anderen Worten, wenn Sie hatten
len(my_list) = 3
l = 1, 2, 3
n = 10
dann können Sie dies tatsächlich als eine einzelne dreidimensionale Matrix der Dimensionen 6 * 3 * 10 darstellen, wobei 6 == len(my_list) * (len(my_list) - 1). Ich denke, es ist möglich, all dies ohne eine einzige forSchleife zu tun , was ideal für vektorisierte Leistung ist.