Comment rendre le Python des débutants plus rapide [numpy]

En fait, je voulais mettre des chiffres 〇〇 et le faire ressembler à un livre d'entreprise, Je l'ai fait 〇〇 parce que je n'ai pas bien décidé le nombre et je l'ajouterai de temps en temps: innocent:.

Mise en garde

Ceci est pour les débutants qui commencent tout juste avec Python Pour ceux qui ont récemment découvert numpy ou scipy. Donc, si vous êtes familier avec Python, vous pouvez donner quelques conseils. Je vous serais reconnaissant si vous pouviez me dire un autre cas ou une meilleure façon: smiley:.

De plus, l'environnement d'exécution était ** Python 3.5.3 **, donc soyez prudent surtout si vous utilisez la ** série Python 2 **. (Parce que la valeur de retour de la carte ou du filtre est différente)

Aperçu

Avec le récent boom de l'apprentissage automatique, de nombreuses personnes ont peut-être commencé à apprendre Python. Vous remarquerez peut-être l'existence de bibliothèques telles que numpy, en particulier lorsqu'il s'agit de traitements numériques simples et de données réelles.

Cependant, je me rends compte que je gère des données d'une certaine taille, mais cela peut prendre du temps à s'exécuter si je ne conçois pas un moyen d'écrire (je pense personnellement que c'est un langage de typage statique lors de la programmation pour la première fois ou avant Python. Je pense que c'est facile de se lever si vous le faites).

Surtout quand j'apprends, je veux essayer différentes choses, donc si cela prend du temps à exécuter, je ne peux pas le faire. Je déteste la programmation: en colère:.

Alors ici, en utilisant ** numpy ** etc., dans le cas où il semble que cela puisse être accéléré "relativement facilement" Je vais vous en parler.

Politique approximative

Je fais personnellement attention. S'il est lent en raison de problèmes d'écriture, il est probable que vous soyez coincé avec l'un des éléments suivants:

L'exemple suivant n'est pas nécessaire pour ceux qui suivent les parties suivantes.

Exemple concret

Préparation

Les bibliothèques suivantes sont importées à l'avance.

import numpy as np
import pandas as pd
import scipy as sp

Cas 1: car je veux stocker le résultat de l'instruction dans une liste

Sample.py


def func1(n):
    a = []
    for i in range(n):
        a.append(i)
    return a

def func2(n):
    a = [0 for i in range(n)]  #Liste de longueur n initialisée à 0
    for i in range(n):
        a[i] = i
    return a

def func3(n):
    a = [i for i in range(n)]  #Initialisez d'abord avec la notation d'inclusion
    return a

def func4(n):
    return [i for i in range(n)]  #Définir et renvoyer directement

%time a = func1(10000000)
%time b = func2(10000000)
%time c = func3(10000000)
%time d = func4(10000000)

result


CPU times: user 660 ms, sys: 100 ms, total: 760 ms
Wall time: 762 ms
CPU times: user 690 ms, sys: 60 ms, total: 750 ms
Wall time: 760 ms
CPU times: user 290 ms, sys: 90 ms, total: 380 ms
Wall time: 388 ms
CPU times: user 320 ms, sys: 90 ms, total: 410 ms
Wall time: 413 ms

Si vous connaissez la longueur de la liste à renvoyer à l'avance, utilisez la notation d'inclusion Ce sera plus rapide. En fait, cela réduit de moitié le temps d'exécution. C'est une bonne idée d'en être conscient, en particulier lorsque vous transformez une déclaration for sur une longue liste.

Cas 2: je veux calculer la même valeur pour tous les éléments d'un vecteur.

Ici, on suppose que les vecteurs suivants sont prédéfinis.

a = np.array([i for i in range(10000000)])

Considérons une fonction qui double et renvoie tous les éléments du vecteur pour ce vecteur.

Sample.py


def func1(x):
    y = x.copy()
    for i in range(len(y)):
        y[i] *= 2
    return y

def func2(a):
    return a * 2

%time b = func1(a)
%time c = func2(a)

result


CPU times: user 2.33 s, sys: 0 ns, total: 2.33 s
Wall time: 2.33 s
CPU times: user 10 ms, sys: 10 ms, total: 20 ms
Wall time: 13 ms

De cette façon, numpy peut exécuter quatre règles pour chaque vecteur, donc pour Attention à ne pas circuler.

Cas 4: je souhaite extraire uniquement les éléments avec un vecteur

Utilisez le même vecteur que ci-dessus. Par exemple, supposons que vous souhaitiez extraire uniquement les éléments qui sont des multiples de 3 à partir du vecteur ci-dessus. Alors vous pourriez penser: "Je n'ai pas d'autre choix que d'utiliser l'instruction if dans l'instruction for!" Vous pouvez également écrire comme suit.

Sample.py


def func1(a):
    ans  = []
    for i in range(len(a)):
        if a[i] % 3 == 0:
            ans.append(a[i])
    return np.array(ans)

def func2(a):
    return a[a % 3 == 0]

%time b = func1(a)
%time c = func2(a)

result


CPU times: user 3.44 s, sys: 10 ms, total: 3.45 s
Wall time: 3.45 s
CPU times: user 120 ms, sys: 10 ms, total: 130 ms
Wall time: 131 ms

Postscript

Si vous souhaitez récupérer à partir d'une liste au lieu d'un vecteur, vous pouvez utiliser la fonction ** filter **. Si vous ne pouvez pas ou ne voulez pas utiliser ** numpy **, pensez à ceci.

Vous pouvez considérer lambda x: y dans l'exemple comme une fonction sans nom qui prend x comme argument et renvoie y.

Sample.py


x = [i for i in range(10000000)]
%time y = list(filter(lambda x: x % 3 == 0, x))

result


CPU times: user 1.67 s, sys: 10 ms, total: 1.68 s
Wall time: 1.68 s

C'est plus lent que d'utiliser ** numpy **, mais plus rapide que d'utiliser append dans une instruction for!

Cas 5: je souhaite appliquer une fonction à chaque élément d'un vecteur

Ensuite, envisagez d'appliquer une fonction à chaque élément de la liste. Ici, nous allons introduire la fonction ** map **. Il s'agit d'une fonction qui renvoie le résultat de l'application de la fonction spécifiée à chaque élément de la liste (objet map en Python3).

De plus, la fonction ci-dessous est une fonction qui renvoie $ x ^ 2 + 2x + 1 $.

Sample.py


a = np.array([i for i in range(10000000)])
def func(x):
    return x**2 + 2*x + 1

def func1(a):
    return np.array([func(i) for i in a])

def func2(a):
    return np.array(list(map(func, a.tolist())))

%time b = func1(a)
%time c = func2(a)
%time d = a**2 + 2*a + 1

result


CPU times: user 5.14 s, sys: 90 ms, total: 5.23 s
Wall time: 5.23 s
CPU times: user 4.95 s, sys: 170 ms, total: 5.12 s
Wall time: 5.11 s
CPU times: user 20 ms, sys: 30 ms, total: 50 ms
Wall time: 51.2 ms

J'ai introduit la fonction map, mais ce n'était pas si différent de la notation d'inclusion: cry:. Si vous avez lu jusqu'ici, vous avez peut-être remarqué au milieu, mais dans le cas de l'exemple ci-dessus, c'était une fonction simple, donc le calcul vectoriel direct est extrêmement plus rapide!

Cas 6: Je souhaite convertir chaque élément (valeur numérique) de la matrice en un score arbitraire (valeur discrète)

Jusqu'à présent, nous avons traité des tableaux unidimensionnels (vecteurs). Dans l'exemple suivant, je voudrais traiter d'un tableau à deux dimensions (matrice).

Dans les cas suivants, il est supposé que vous souhaitez convertir chaque valeur numérique en score par prétraitement tel que l'apprentissage automatique. Tout d'abord, définissez la matrice suivante.

a = np.array([[i % 100 for i in range(1000)] for j in range(10000)])

Ensuite, préparez une liste à convertir en partition. Dans la liste ci-dessous, 0 si le nombre d'origine est inférieur à 20, 1 s'il est égal ou supérieur à 20 et inférieur à 50, 4 s'il est supérieur ou égal à 90. Supposons que vous souhaitiez convertir les nombres de la matrice, tels que.

scores = [20, 50, 70, 90]

Tout d'abord, je voudrais vider ma tête et l'appliquer docilement.

Sample.py


def func1(x):
    y = np.zeros(x.shape)
    for s in scores:
        for i in range(x.shape[0]):
            for j in range(x.shape[1]):
                if x[i, j] >= s:
                    y[i, j] += 1
    return y

%time b = func1(a)

Le résultat est une belle triple boucle: innocent:. (Les boucles profondes sont non seulement plus lentes, mais aussi plus difficiles à lire et à suivre les variables de boucle. Ne faites pas trop de boucles profondes pour les humains)

Le contenu de la fonction est incrémenté de 1 pour chaque élément de la matrice s'il est supérieur au score spécifié.

result1


CPU times: user 14 s, sys: 10 ms, total: 14 s
Wall time: 14 s

Comme prévu, le temps d'exécution a également dépassé ** 10 secondes **: cry:.

Ensuite, je présenterai une fonction qui a été conçue.

Sample2.py


def func2(x):
    y = np.zeros(x.shape)
    for s in scores:
        y += (x >= s)
    return y

%time c = func2(a)

Voici ce que nous faisons:

Comme mentionné ci-dessus, le code est court mais contient divers éléments. Cependant, il est ** 100 fois plus rapide ** d'autant plus rapide que l'instruction for n'est plus retournée: smile:.

result


CPU times: user 90 ms, sys: 20 ms, total: 110 ms
Wall time: 111 ms

Postscript (30/08/2017)

À ce stade, vous pouvez vous sentir comme "Je veux effacer toutes les ** pour ** phrases avant leur naissance: en colère:". Alors je l'ai écrit comme un essai.

Sample3.py


def func3(x):
    len_score = len(scores)
    y = x * np.array([[np.ones(len_score)]]).T
    s = np.array(scores).reshape(len_score, 1, 1)
    z = (y >= s)
    return z.sum(axis=0)

result


CPU times: user 200 ms, sys: 30 ms, total: 230 ms
Wall time: 235 ms

... tard: pleurer: (peut-être à cause d'une mauvaise écriture) Ceci est lent, nécessite beaucoup de mémoire (car tout est développé en premier), et surtout, cela devient difficile à comprendre, donc j'ai trouvé que ce n'est pas une bonne idée de supprimer l'instruction for par la force.

Cas 7: Vérification d'existence sur l'élément de liste (Ajouté 2018/04/20)

Je m'en suis souvenu quand j'ai vu un article récent, alors j'ai pris une note.

En Python, vous pouvez utiliser ʻin` pour vérifier si un élément est dans la liste.

Mais si vous appliquez cela à une liste, c'est $ O (n) $ pour une longueur de liste de $ n $, donc si vous faites une erreur, vous aurez un accident.

Si vous voulez vérifier l'existence à plusieurs reprises, il est préférable de le remplacer par set etc. comme indiqué ci-dessous.

JupyterNotebook(GoogleColaboratory)Confirmé dans


L = 100000
x = list(range(L))

def sample1(list_tmp):
    j = 0
    for i in list_tmp:
        if i in list_tmp:
            j += 1
    print("sample1 j: ", j)


def sample2(list_tmp):
    j = 0
    set_tmp = set(list_tmp)  #Convertir en ensemble
    for i in list_tmp:
        if i in set_tmp:     #Vérifiez s'il est en jeu
            j += 1
    print("sample2 j: ", j)
    
%time sample1(x)
print("----------------------------------------")
%time sample2(x)

résultat


sample1 j:  100000
CPU times: user 1min 7s, sys: 16 ms, total: 1min 7s
Wall time: 1min 7s
----------------------------------------
sample2 j:  100000
CPU times: user 8 ms, sys: 6 ms, total: 14 ms
Wall time: 14 ms

Extra 1 "Je souhaite toujours utiliser l'instruction for"

J'ai dit plus haut que je ne devrais pas en utiliser autant pour la déclaration, Même ainsi, je pense qu'il y a des situations où il faut l'utiliser ou c'est plus facile à comprendre.

Dans ce cas, rouvrez-le et utilisez * numba *. * numba * est un petit compilateur.

"Eh bien, est-ce que le compilateur spécifie toutes les variables? Dois-je taper une commande de compilation?"

Vous pourriez penser, mais ne vous inquiétez pas. Ajoutez simplement une ligne (deux lignes si vous incluez ʻimport`).

Voyons un exemple d'utilisation réel.


import numba

def sample1(n):
    ans = 0
    for i in range(n):
        ans += i
    return ans

@numba.jit
def sample2(n):
    ans = 0
    for i in range(n):
        ans += i
    return ans

@numba.jit('i8(i8)', nopython=True)
def sample3(n):
    ans = 0
    for i in range(n):
        ans += i
    return ans

%time a = sample1(100000000)  #Si tu ne fais rien
%time b = sample2(100000000)  #Lors de l'utilisation de jit
%time c = sample3(100000000)  # jit(Spécification de type)Lors de l'utilisation

De haut en bas, «je n'ai rien fait», «j'ai utilisé numba» et «j'ai utilisé numba (spécification de type)» C'est une fonction. À l'intérieur de la fonction se trouve une fonction qui ajoute et renvoie de 0 à $ n -1 $.

Pour la spécification de type, reportez-vous à Python Acceleration Numba Introduction Part 2-tkm2261's blog.

Le temps d'exécution est le suivant. Si vous ne faites rien, cela prendra 5 secondes, mais si vous utilisez "numba (spécification de type)", cela prendra environ 5,5 microsecondes. C'est juste un chiffre différent (dans cet exemple, c'est ** environ 940 000 fois plus rapide **: innocent :).

CPU times: user 5.16 s, sys: 0 ns, total: 5.16 s
Wall time: 5.16 s
CPU times: user 30 ms, sys: 0 ns, total: 30 ms
Wall time: 25.9 ms
CPU times: user 0 ns, sys: 0 ns, total: 0 ns
Wall time: 5.48 µs

en conclusion

J'ai l'impression d'avoir beaucoup écrit, mais dans le cas ci-dessus, je pense que cela s'est terminé par "Ne pas utiliser pour déclaration". À l'avenir, j'aimerais rassembler diverses choses telles que ** scipy ** et ** pandas **.

Recommended Posts

Comment rendre le Python des débutants plus rapide [numpy]
Comment créer un plug-in Spigot (pour les débutants Java)
~ Conseils pour les débutants de Python présentés avec amour par Pythonista ③ ~
[Pour les débutants] Comment utiliser la commande say avec python!
[Pour les débutants] Comment étudier le test d'analyse de données Python3
Python # Comment vérifier le type et le type pour les super débutants
Méthode d'apprentissage TensorFlow pour les professionnels des arts libéraux et les débutants en Python
Comment créer un package Python (écrit pour un stagiaire)
Comment convertir le type Python # pour les super débutants de Python: int, float
Conseils aux débutants en Python pour utiliser l'exemple Scikit-image pour eux-mêmes 7 Comment créer un module
[Python] Comment rendre une classe itérable
[Python] Organisation de l'utilisation des instructions
Comment utiliser "deque" pour les données Python
Mémo n ° 4 que les débutants Python lisent "Explication détaillée de la grammaire Python"
Comment créer un système de dialogue dédié aux débutants
Comment installer Python
Python pour les super débutants Super débutants Python # Facile à éliminer
Mémo n ° 3 que les débutants Python lisent "Explication détaillée de la grammaire Python"
Comment installer python
Mémo n ° 1 que les débutants Python lisent "Explication détaillée de la grammaire Python"
Comment utiliser les outils d'analyse de données pour les débutants
Manuel python pour les débutants
Essayez de calculer RPN avec Python (pour les débutants)
Mémo n ° 2 que les débutants Python lisent "Explication détaillée de la grammaire Python"
Comment utiliser numpy
Comment créer le plugin Python de Substance Painter (Introduction)
Mémo n ° 7 que les débutants Python lisent "Explication détaillée de la grammaire Python"
Mémo n ° 6 pour les débutants Python à lire "Explication détaillée de la grammaire Python"
Comment utiliser NumPy
Comment apporter des modifications à l'interpréteur Python dans Pycharm
[Pour les débutants] Comment étudier la programmation Mémo privé
OpenCV pour les débutants en Python
Mémo n ° 5 que les débutants Python lisent "Explication détaillée de la grammaire Python"
Un outil pour créer des images de masque pour ETC en Python
[BigQuery] Comment utiliser l'API de BigQuery pour Python -Création de table-
Expliquez en détail comment créer un son avec python
Comment exécuter python dans l'espace virtuel (pour MacOS)
Comment faire un test unitaire Part.2 Conception de classe pour les tests
Un débutant en Python dit qu'il est bon de s'en souvenir
Comment créer un package Python à l'aide de VS Code
Comment écrire plus rapidement en utilisant numpy comme deque
[Introduction à Python] Comment écrire des instructions répétitives à l'aide d'instructions for
[2020.8 dernière] Comment installer Python
Convertir numpy int64 en python int
python3: Comment utiliser la bouteille (2)
Flux d'apprentissage pour les débutants en Python
[Python] Comment utiliser la liste 1
Comment mettre à jour Tkinter de Python vers la version 8.6
Comment utiliser Python Argparse
Construction de l'environnement Python3 (pour les débutants)
3 raisons pour lesquelles les débutants en programmation devraient commencer avec Python
Comment installer mkl numpy
Python: comment utiliser pydub
[Python] Comment utiliser checkio
Python #function 2 pour les super débutants
Comment exécuter Notepad ++ Python
Grammaire de base Python pour les débutants
Comment changer la version de Python