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:.
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)
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.
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.
Les bibliothèques suivantes sont importées à l'avance.
import numpy as np
import pandas as pd
import scipy as sp
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.
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.
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
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!
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!
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:
0`` y
avec la même forme (nombre de matrices) que x
(x> = s)
à y
x> = s
est ** True ** if element> = s
, ** False ** sinon ** matrice ** pour chaque élément de la matrice x
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
À 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.
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
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
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