Ich habe mit verschiedenen Methoden experimentiert, um numpy.ndarray zu schonen. Die Dissoziation bezieht sich hier auf die Verarbeitung wie die Größenänderung von opencv. Da es sich jedoch um die nachstehend beschriebene Deregulierung handelt, handelt es sich nicht um Fälle wie die Vergrößerung des Arrays oder Fälle, in denen eine Seite der Dissoziation eine Seite des ursprünglichen Arrays nicht teilen kann.
Als ich einen Gittergasautomaten implementierte, wurde es notwendig, beim Zeichnen der Ergebnisse abzuweichen. Insbesondere möchte ich den Prozess der Mittelung von 10000 * 10000 Arrays alle 10 * 10 verarbeiten, um 1000 * 1000 Arrays zu erstellen. Es gibt eine Größenänderung in opencv, und es sollte viele Leute geben, die sie verwenden möchten. Als ich also googelte, dass es nichts (subjektives) geben würde, kam eine andere Größenänderung heraus. Dann ist es eine gute Geschichte, die Größenänderung von opencv zu verwenden, aber es ist auf subtile Weise problematisch, dass nur vorzeichenlose 1-Byte-Ganzzahlen unterstützt werden. Wenn Sie ein Array anderer Typen einfügen, wird ein Fehler ausgegeben. Da nur das Ergebnis gezeichnet wird, ist es nicht so schlecht, dies zu verwenden. Da es jedoch eine gute Idee ist, möchte ich einen genauen Wert verwenden, und habe mich daher entschlossen, ihn zu implementieren.
Ich habe die folgenden vier Typen ausprobiert.
In der folgenden Quelle wird das ursprüngliche Array als Array (Größe 10000 * 10000) und die Länge einer Seite mit geringer Dichte als mean_size (10 in der folgenden Erklärung) erläutert.
Unten ist die Quelle
mean_loop
def mean_loop(array, mean_size):
meaned_size = np.shape(array)[0] // mean_size
return_array = np.empty((meaned_size, meaned_size))
for y in range(meaned_size):
for x in range(meaned_size):
return_array[y, x] = array[mean_size*y:mean_size*(y+1), mean_size*x:mean_size*(x+1)].mean()
return return_array
Es ist eine einfache Implementierung dessen, was Sie tun möchten. Wenn es in C implementiert ist, wäre es so. Es fühlt sich jedoch unangenehm an, wenn es um Doppelschleifen in Python geht. Außerdem wird dieses Mal das 10000 * 10000-Array 1000 * 1000 sein, so dass die Ausführungszeit schrecklich sein wird.
mean_list_comprehension
def mean_list_comprehenion(array, mean_size):
meaned_size = np.shape(array)[0] // mean_size
return np.array([[array[mean_size*y:mean_size*(y+1), mean_size*x:mean_size*(x+1)].mean() for x in range(meaned_size)] for y in range(meaned_size)])
Apropos Python, Listeneinschlussnotation, und Apropos Listeneinschlussnotation, Python. Es wird gesagt, dass es schneller (subjektiv) sein wird, also können Sie es erwarten. Die Schleife ist hier jedoch auch 1000 * 1000. Wie ich es geschrieben habe, ist die Doppellisten-Einschlussnotation jedoch beschissen und schwer zu lesen.
mean_slice
def mean_slice(array, mean_size):
sum_row_array = np.array(array[::mean_size])
for row in range(1, mean_size):
sum_row_array += array[row::mean_size]
sum_column_array = sum_row_array[:,::mean_size]
for column in range(1, mean_size):
sum_column_array += sum_row_array[:,column::mean_size]
return sum_column_array / mean_size**2
Eine etwas schlammige Methode. Die Schleife ist nur 20 Mal, um 10 Zeilen und 10 Spalten hinzuzufügen. Es sollte auf jeden Fall schneller sein als die beiden oben genannten.
mean_np_roll
def mean_np_roll(array, mean_size):
sum_row_array = np.array(array)
for row in range(1, mean_size):
sum_row_array += np.roll(array, -row, axis=0)
sum_column_array = np.array(sum_row_array)
for column in range(1, mean_size):
sum_column_array += np.roll(sum_row_array, -column, axis=1)
return sum_column_array[::mean_size, ::mean_size] / mean_size ** 2
Was sie tun, ist etwas anders, aber die Idee ist dieselbe. Ich habe gehört, dass ndarray nur langsam auf Elemente zugreift, also dachte ich, dass Slice langsam sein könnte, also habe ich es geschafft. Während die Slice-Methode den hinzuzufügenden Bereich verkleinert, scheint sie in dieser Hinsicht langsamer zu sein, da sie hier dieselbe Größe wie das ursprüngliche Array hat.
Ich wollte es in verschiedenen experimentellen Einstellungen sehen, also stellte ich die durchschnittliche Größe einer Seite der ursprünglichen Sequenz als (3000, 10), (6000, 10), (9000, 10), (3000, 100), (6000, 100) ein. Ich habe es in (3000, 1000) geändert und berechnet. Das Folgende ist das Ausführungsergebnis.
Wie erwartet ist Slice schneller als die beiden oben genannten, aber die Methode mit np.roll war langsamer als erwartet. Besonders wenn die durchschnittliche Fläche groß ist, ist die Langsamkeit ziemlich erstaunlich. Das Ergebnis ist auch, dass die Notation der Listeneinbeziehung nicht so schnell ist. Angesichts dieser Ergebnisse halte ich es für eine schlechte Idee, die Einschlussnotation unter dem Gesichtspunkt der Lesbarkeit zu erzwingen. Derzeit scheint die obige Funktion mit Slice gut zu sein, daher denke ich, dass es besser ist, diese zu verwenden.
Ich habe versucht, die Top-Methode in C zu implementieren. Die Erweiterung ist cpp, aber der Inhalt ist normal C. Ich höre, dass es aus irgendeinem Grund schnell ist, also benutze ich rohen Po. Die Details sind unterschiedlich, wie zum Beispiel der Teil, in dem das eindimensionale Array als sekundär angesehen wird, aber wenn es um die Implementierung in C geht, sollte es ein solcher Code sein, also habe ich nicht in diesem Ausmaß an Fairness gedacht. Ich habe ein x64-Release in der Visual Studio 2017-Community erstellt.
mean_loop.cpp
#include "stdafx.h"
#include <stdio.h>
#include <time.h>
#include <Windows.h>
double* mean_loop(int mean_size, int array_size, double* array) {
double *return_array;
int meaned_size = array_size / mean_size;
return_array = new double[meaned_size * meaned_size];
for (size_t i = 0; i < meaned_size; i++)
{
for (size_t j = 0; j < meaned_size; j++)
{
double temp = 0;
for (size_t k = 0; k < mean_size; k++)
{
for (size_t l = 0; l < mean_size; l++)
{
temp += array[(i + k) * meaned_size * mean_size + j*mean_size + l];
}
}
return_array[i * meaned_size+ j] = temp / (mean_size * mean_size);
}
}
return return_array;
};
int main()
{
double *array, *return_array;
int mean_size = 10, array_size = 3000;
clock_t start, end, span;
int array_sizes[] = {3000, 6000, 9000};
int mean_sizes[] = { 10, 100, 1000 };
for (size_t as = 0; as < 3; as++)
{
for (size_t ms = 0; ms < 3; ms++)
{
array_size = array_sizes[as];
mean_size = mean_sizes[ms];
array = new double[array_size * array_size];
for (size_t i = 0; i < array_size * array_size; i++)
{
array[i] = i;
}
start = clock();
return_array = mean_loop(mean_size, array_size, array);
end = clock();
span = end - start;
printf("%d %4d took: %lf\n", array_size, mean_size, (double)span / CLOCKS_PER_SEC);
delete return_array, array;
}
}
system("pause");
return 0;
}
Das Ergebnis dieser Berechnung. Immerhin ist es schnell! Ich habe Angst vor Speicherlecks, weil es ein roher Po ist, aber das ist eine Anstrengung (extreme Theorie), und da umfangreiche Berechnungen häufig in numerischen Berechnungen durchgeführt werden, sollte C / C ++ weiterhin verwendet werden. Als Gegenleistung für diesen Horror bin ich jedoch der Meinung, dass diese Geschwindigkeit beim Vergleich des oben genannten relativ sicheren und relativ schnellen Codes von Python am richtigen Ort ist.
Verwenden Sie keine Skriptsprache für numerische Berechnungen.