[PYTHON] Comparaison des performances entre le calcul matriciel bidimensionnel et pour avec numpy

Dans cet article, comment écrivez-vous le calcul matriciel bidimensionnel suivant dans numpy de Python? C'est.

for i in range(0, ni-1):
    for j in range(0, nj-1):
        y[i, j] = x[i, j] + x[i+1, j] - x[i+1, j+1] * x[i, j+1]

Plus tard, nous comparerons les performances. La version Python est la 3.7.4. J'utilise anaconda3-2019.10.

Préface

COVID-19 + En changeant d'emploi, j'ai décidé de gagner du temps et d'apprendre une nouvelle langue chaque jour alors que je restais coincé chez moi à Tokyo. Python semble être la chose principale dans le prochain lieu de travail, donc Python. Je dois réduire mon argent pour être sérieux, j'ai donc suivi un cours à Udemy et passé environ une semaine à apprendre les bases. Je programme depuis longtemps, mais Python est un débutant avec environ deux semaines d'expérience.

Après avoir essayé toutes les étapes, j'ai l'impression de pouvoir faire du développement Web avec Python, mais puisque je vais faire Python, j'aimerais faire de l'analyse de données et de l'apprentissage automatique. J'ai donc réécrit la solution de l'équation de translocation unidimensionnelle que j'ai faite il y a longtemps en Python.

1 Dimensional Flow Calculation by Python

Je n'ai pas vérifié les détails et j'ai pris des raccourcis, mais j'étais satisfait des résultats que je souhaitais pour la première fois. Mais quel sentiment d'accomplissement? Je ne pouvais pas ressentir quelque chose comme ça, alors j'ai essayé un calcul bidimensionnel, mais le calcul matriciel était extrêmement terne. Mon fantôme murmure que je ne devrais plus continuer à écrire. Et En Python

--Si vous écrivez pour, vous perdez

C'est juste une rumeur. Il a été dit que numpy etc. serait utilisé comme solution, alors j'ai essayé de l'utiliser, mais c'est juste déroutant et il semble que je ne pourrai pas l'apprendre immédiatement, alors je vais le laisser comme mémo.

Tout ce que vous pouvez obtenir en lisant cet article, c'est que vous n'avez pas à lire "Utiliser numpy pour calculer les matrices (ne pas utiliser pour)". À part cela, je ne pense pas que cela vous viendra à l'esprit même si vous le lisez, donc si vous le comprenez, vous devriez en fait bouger votre main pour le vérifier et le répéter jusqu'à ce qu'il tienne dans votre main.

Comparaison de la façon d'écrire une liste et un tableau numpy

Python a list, tuple, dict, etc. pour représenter les tableaux, et pour les tableaux à deux dimensions, `` `` list vient d'autres langages. Il est facile de comprendre s'il s'agit de x [i] [j] '' etc. Cependant, d'après la notation mathématique, x [i, j] '' est plus facile à comprendre. Dans le tableau de numpy```, il est écrit comme ce dernier. Comme vous pouvez le voir en l'écrivant, écrire x [i] [j] '' plusieurs fois est ennuyeux et difficile à voir, donc comme x [i, j] Je suis reconnaissant de pouvoir écrire.

Puis immédiatement. Par exemple, supposons que vous ayez la formule suivante qui calcule x, y sous la forme `` `ndarray.

y[i, j] = x[i, j] + x[i+1, j] - x[i+1, j+1] * x[i, j+1]

Ce n'est pas une formule particulièrement significative, mais vous devriez souvent voir ce type de calcul non seulement dans les systèmes numériques, mais aussi dans le traitement des calculs numériques. Imbriquer ceci dans une boucle de i et `` `j```,

for i in range(0, x.shape[0]-1):
    for j in range(0, x.shape[1]-1):
        y[i, j] = x[i, j] + x[i+1, j] - x[i+1, j+1] * x[i, j+1]

Sera. Très facile à comprendre. Si le nombre maximum de divisions est ni, `` nj, etc.

for i in range(0, ni-1):
    for j in range(0, nj-1):
        y[i, j] = x[i, j] + x[i+1, j] - x[i+1, j+1] * x[i, j+1]

Ça veut dire.

Au fait, dans numpy, il semble judicieux d'écrire ce calcul comme suit.

y[0:-1, 0:-1] = x[0:-1, 0:-1] + x[1:, 0:-1] - x[1:, 1:] * x[0:-1, 1:]

e? Quoi?

Si vous regardez de plus près, qu'est-ce que c'est? L'expression correspond-elle à la plage découpée? Je ne me sens pas comme ça. Je n'ai pas envie d'écrire librement.

Essayer

Vérifions si cela correspond vraiment.

import numpy as np


x = np.random.randint(10, size=(100, 50))
y = np.zeros((100, 50))

for i in range(0, x.shape[0]-1):
    for j in range(0, x.shape[1]-1):
        y[i, j] = x[i, j] + x[i+1, j] - x[i+1, j+1] * x[i, j+1]

z = np.zeros_like(y)
z[0:-1, 0:-1] = x[0:-1, 0:-1] + x[1:, 0:-1] - x[1:, 1:] * x[0:-1, 1:]

if (z == y).all():
    print('Allumettes')
else:
    print('Faux')

Le résultat de l'exécution est ... correct. 0 dans la plage n'est pas nécessaire, mais par souci de compréhension. Autre

--De `0``` à` `ni, nj``` (` `x.shape [0], x.shape [1]` `) --De 1``` à ni, nj``` ( `x.shape [0], x.shape [1]` `) --``` 1``` à ni-1, nj-1``` ( x.shape [0] -1, x.shape [1] -1```) --De `` 2 à` `ni-3, nj-3 ( x.shape [0] -3, x.shape [1] -3 ''`)

Etc.

#0 à ni, nj (x.shape[0], x.shape[1])
for i in range(0, x.shape[0]):
    for j in range(x.shape[1]):
        y[i, j] = x[i, j] + x[i, j]

z[0:, 0:] = x[0:, 0:] + x[0:, 0:]

#1 à ni, nj (x.shape[0], x.shape[1])
for i in range(1, x.shape[0]):
    for j in range(1, x.shape[1]):
        y[i, j] = x[i, j] + x[i-1, j] - x[i-1, j-1] * x[i, j-1]

z[1:, 1:] = x[1:, 1:] + x[0:-1, 1:] - x[0:-1, 0:-1] * x[1:, 0:-1]

#1 à ni-1, nj-1 (x.shape[0]-1, x.shape[1]-1)
for i in range(1, x.shape[0]-1):
    for j in range(1, x.shape[1]-1):
        y[i, j] = x[i, j] + x[i-1, j] - x[i+1, j-1] * x[i, j+1]

z[1:-1, 1:-1] = x[1:-1, 1:-1] + x[0:-2, 1:-1] - x[2:, 0:-2] * x[1:-1, 2:]

#2 à ni-3, nj-3 (x.shape[0]-3, x.shape[1]-3)
for i in range(2, x.shape[0]-3):
    for j in range(2, x.shape[1]-3):
        y[i, j] = x[i, j] + x[i-1, j] - x[i+1, j-1] * x[i, j+1]

z[2:-3, 2:-3] = x[2:-3, 2:-3] + x[1:-4, 2:-3] - x[3:-2, 1:-4] * x[2:-3, 3:-2]

Résumé de la façon d'écrire

Hmmm, est-ce quelque chose comme ça?

# i,j de n à ni-m, nj-Boucle à m
# x[i, j], x[i-ln, j], x[i+ln, j-ln], x[i, j+ln]Etc

for i in range(n, x.shape[0]-m):
    for j in range(n, x.shape[1]-m):
        y[i, j] = x[i, j] + x[i-ln, j] - x[i+ln, j-ln] * x[i, j+ln]

z[n:-m, n:-m] = x[n:-m, n:-m] + x[n-ln:-m-ln, n:-m] - \
    x[n+ln:-m+ln, n-ln:-m-ln] * x[n:-m, n+ln:-m+ln

Beaucoup de désordre sommaire. C'est extrêmement difficile à lire, alors je vais en faire un tableau.

start end i i-1 i+1 i-ln
0 ni 0: - - -
0 ni-1 0:-1 - 1: -
1 ni 1: 0:-1 - -
1 ni-1 1:-1 0:-2 2: -
n ni-m n:-m n-1:-m-1 n+1:-m+1 n-ln:-m-ln

ni = x.shape[0]

Est-ce correct? C'est difficile à comprendre, peu importe comment vous l'écrivez. En tant que débutant en Python, j'ai la franche impression qu'il ne devrait pas être utilisé du point de vue de la maintenabilité. Au moins à ce stade, je le pensais.

Comparaison de la vitesse de traitement

J'ai bouclé et mesuré pour que le calcul tourne 100 millions de fois. Dans le premier calcul unidimensionnel, j'ai rendu le maillage plus fin et calculé environ 20 millions de fois, il semble donc qu'il y en ait plusieurs 100 millions de fois, mais dans le calcul réel, il n'y en a pas du tout. Il était difficile de faire correspondre les fractions, alors laissez-le tel quel. Le résultat de la mesure est la moyenne de 10 exécutions chacune.

loop for
(sec)
slice
(sec)
ave:
s/f %
max:
s/f %
min:
s/f %
median:
s/f %
100,007,840 148.3013 1.3558 0.91% 0.95% 0.88% 0.91%
10,020,160 13.4111 0.1179 0.88% 1.00% 0.72% 0.86%
1,024,160 1.4228 0.0146 1.03% 1.20% 0.84% 1.04%
110,720 0.1536 0.0017 1.10% 1.35% 0.96% 1.08%

Joiko écrasante! !! !! Pepe

Ce n'est pas au niveau de la maintenabilité. Terminer à peu près à environ 1% signifie qu'un calcul qui prend une heure se terminera en 36 secondes. Et un jour? Pour une semaine? ?? 1 mois? ?? ?? Pour la lisibilité, il n'y a absolument aucune option à utiliser. Veuillez écrire dans les commentaires.

Cependant, que ce calcul numpy soit rapide ou non est une autre affaire. Il semble que numpy soit implémenté en langage C et en Fortran, mais il est plus rapide d'imbriquer des boucles dans Fortran! Je pense qu'il y a quelque chose comme ça. Non vérifié.

c'est tout. Je pense qu'il y a quelque chose qui devrait être fait plus comme ça, mais une fois que c'est fait.

Recommended Posts

Comparaison des performances entre le calcul matriciel bidimensionnel et pour avec numpy
Différence entre le tableau Numpy 1D [x] et le tableau 2D [x, 1]
Concaténation de matrices avec Numpy
Différence entre les méthodes numpy et pandas pour trouver une distribution
[Python] Méthode de calcul avec numpy
Essayez l'opération matricielle avec NumPy
Je veux absorber la différence entre l'instruction for sur la matrice Python + numpy et l'instruction Julia for
Rechercher des chaînes de caractères dans les fichiers [Comparaison entre Bash et PowerShell]
Résolution avec Ruby, Python et numpy AtCoder ABC054 B Calcul de la matrice
Différence entre le randint de Numpy et le randint de Random
Comparaison de vitesse entre CPython et PyPy
Communiquez entre Elixir et Python avec gRPC
Effectuer un calcul DFT avec ASE et GPAW
sélénium: attendre l'élément avec ET / OU
Lire et écrire des fichiers csv avec numpy
Graphiques de fonctions triangulaires avec numpy et matplotlib
Comparaison de la vitesse de transposition de la matrice par Python
Simulation physique 2D avec Box2d et wxPython