[Python3] Comparaison de vitesse, etc. sur la privation de numpy.ndarray

Abstrait

J'ai expérimenté plusieurs façons de réduire numpy.ndarray. La dissociation se réfère ici à un traitement tel que le redimensionnement d'opencv. Cependant, puisque nous traitons de la dérégulation comme décrit ci-dessous, nous ne traitons pas des cas tels que l'agrandissement du tableau ou des cas où un côté de la dissociation ne peut pas diviser un côté du tableau d'origine.

Préface

Lorsque je mettais en œuvre un automate à gaz à réseau, il devenait nécessaire de dévier au stade du dessin des résultats. Plus précisément, je souhaite traiter le processus de calcul de la moyenne de 10000 * 10000 tableaux tous les 10 * 10 pour créer 1000 * 1000 tableaux. Il y a un redimensionnement dans opencv, et il devrait y avoir beaucoup de gens qui veulent l'utiliser, donc quand j'ai googlé qu'il n'y aurait rien (subjectif), un redimensionnement différent est sorti. Ensuite, c'est une bonne histoire d'utiliser le redimensionnement d'opencv, mais il est subtilement gênant qu'il ne prenne en charge que les entiers non signés de 1 octet, et si vous insérez un tableau d'autres types, une erreur sera générée. Comme il ne fait que dessiner le résultat, ce n'est pas si mal de l'utiliser, mais comme c'est une bonne idée, je veux utiliser une valeur précise, j'ai donc décidé de l'implémenter.

Environnement d'exécution

Méthode essayée

J'ai essayé les quatre types suivants.

--Préparez le tableau déparsé, retirez le tableau d'origine en tant que tranche et remplacez la valeur moyenne à l'aide de l'instruction for.

Dans la source suivante, le tableau original sera expliqué en tant que tableau (taille 10000 * 10000), et la longueur d'un côté à être éparse sera expliquée par mean_size (10 dans l'explication suivante).

Préparez le tableau délimité, retirez le tableau d'origine en tant que tranche et remplacez la valeur moyenne à l'aide de l'instruction for.

Ci-dessous la source

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

C'est une mise en œuvre simple de ce que vous voulez faire. S'il est implémenté en C, ce serait comme ça. Cependant, cela semble désagréable lorsqu'il s'agit de doubles boucles en Python. De plus, cette fois, le tableau 10000 * 10000 sera 1000 * 1000, donc le temps d'exécution sera terrible.

Décrivez la procédure ci-dessus en notation d'inclusion de liste

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)])

En parlant de Python, de la notation d'inclusion de liste et de la notation d'inclusion de liste, Python. On dit que ce sera plus rapide (subjectif), donc vous pouvez vous y attendre. Cependant, la boucle est également de 1000 * 1000 ici. Cependant, comme je l'ai écrit, la notation d'inclusion de double liste est merdique et difficile à lire.

Découpez le tableau d'origine et ajoutez-le en lignes et en colonnes

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

Une méthode un peu boueuse. La boucle n'est que de 20 fois pour ajouter 10 lignes et 10 colonnes. Il devrait être plus rapide que les deux ci-dessus par tous les moyens.

Décrivez la procédure ci-dessus en utilisant np.roll

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

Ce qu'ils font est légèrement différent, mais l'idée est la même. J'ai entendu dire que ndarray est lent à accéder aux éléments, alors j'ai pensé que cette tranche pourrait être lente, alors je l'ai fait. Cependant, alors que la méthode des tranches réduit la zone à ajouter, elle semble être plus lente à cet égard car elle reste ici la même taille que le tableau d'origine.

résultat

Je voulais le voir dans divers contextes expérimentaux, j'ai donc défini la taille moyenne d'un côté de la séquence originale comme (3000, 10), (6000, 10), (9000, 10), (3000, 100), (6000, 100). Je l'ai changé en, (3000, 1000) et je l'ai calculé. Voici le résultat de l'exécution.

image.png

Comme prévu, slice est plus rapide que les deux ci-dessus, mais la méthode utilisant np.roll était plus lente que prévu. Surtout quand la surface moyenne est grande, la lenteur est assez incroyable. En outre, le résultat est que la notation d'inclusion de liste n'est pas si rapide. Compte tenu de ces résultats, je pense que ce serait une mauvaise idée de forcer la notation du point de vue de la lisibilité. Pour le moment, la fonction ci-dessus utilisant slice semble être bonne, donc je pense qu'il vaut mieux l'utiliser.

(Bonus?) Comparaison avec C

J'ai essayé d'implémenter la méthode supérieure en C. L'extension est cpp, mais le contenu est ordinaire C. J'entends que c'est rapide pour une raison quelconque, alors j'utilise du po brut. Les détails sont différents, comme la partie où le tableau unidimensionnel est considéré comme secondaire, mais quand il s'agit de l'implémentation en C, cela devrait être un tel code, donc je n'ai pas pensé à l'équité dans cette mesure. J'ai créé une version x64 dans la communauté Visual Studio 2017.

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;
}

Le résultat de ce calcul. loop_c++.PNG Après tout, c'est rapide! J'ai peur des fuites de mémoire parce que c'est brut, mais c'est un effort (théorie extrême), et comme les calculs à grande échelle sont souvent effectués dans des calculs numériques, C / C ++ doit toujours être utilisé. Cependant, en échange d'une telle horreur, je pense que cette vitesse est au bon endroit lorsque l'on compare le code de Python relativement sûr et raisonnablement rapide ci-dessus.

Résumé

N'utilisez pas de langage de script pour les calculs numériques.

Recommended Posts

[Python3] Comparaison de vitesse, etc. sur la privation de numpy.ndarray
Comparaison de la vitesse de la perspective XML Python
Comparaison de vitesse de Python, Java, C ++
Comparaison de 4 types de frameworks Web Python
Exemples tels que les getters et les setters Python
Comparaison de vitesse du traitement de texte intégral de Wiktionary avec F # et Python
Comparaison de la vitesse de calcul en implémentant python mpmath (calcul de précision arbitraire) (Note)
Comparaison des modules de conversion japonais en Python3
comparaison de chaînes python / utiliser 'list' et 'in' au lieu de '==' et 'ou'
Comparaison de vitesse de partage en Python / janome, sudachi, ginza, mecab, fugashi, tinysegmenter
Essayez la comparaison de vitesse de l'API BigQuery Storage
Comparaison des frameworks sans serveur Python-Zappa vs Chalice
Comparaison de la vitesse de transposition de la matrice par Python
Comparaison de vitesse de murmurhash3, md5 et sha1
Comparaison de vitesse Python regex vs startswith vs str [: word_length]
Fonctionnement sans assistance des feuilles de calcul Google (etc.) en Python
Comparez la vitesse d'ajout et de carte Python
Comparaison approfondie de trois bibliothèques d'analyse morphologique Python
Comparaison simple des bibliothèques Python qui exploitent Excel
Vitesse: ajouter un élément à la fin du tableau Python
Comparaison d'écriture R et Python (méthode de division mutuelle euclidienne)
Évaluation de la vitesse de sortie du fichier CSV en Python
Comparaison de Python et Ruby (Environment / Grammar / Literal Edition)
Quoi utiliser pour les piles et les files d'attente Python (comparaison de vitesse de chaque structure de données)
Premier Python 3 ~ Première comparaison ~
Les bases de Python ①
Bases de python ①
Copie de python
Introduction de Python
Comparaison de vitesse de chaque langue par la méthode de Monte Carlo
Vitesse de lecture Python netCDF4 et imbrication d'instructions for
Expérience de comparaison de la vitesse d'écriture de fichier entre python 2.7.9 et pypy 2.5.0
Comparaison de l'implémentation de plusieurs moyennes mobiles exponentielles (DEMA, TEMA) en Python
Une comparaison rapide des bibliothèques de test Python et node.js
Tableau de comparaison des processus fréquemment utilisés de Python et Clojure
Comparaison de CoffeeScript avec la grammaire JavaScript, Python et Ruby