Accélérez vos compétences Python en 2023
Python est le langage de programmation le plus utilisé dans le domaine de la science des données, et sa popularité ne cesse de croître. L'ensemble du domaine de la science des données s'est énormément développé ces dernières années.
Dans cet article, nous vous montrerons sept conseils pour améliorer vos compétences en Python. Ce sont souvent les petites choses qui font une grande différence. Les conseils enrichiront votre vie en tant que Data Scientist. C'est pourquoi nous vous donnons sept conseils que vous pouvez mettre en pratique dès maintenant. Être curieux!
En tant que Data Scientist, vous devez souvent traiter de grandes quantités de données. Pour cette raison, vous devez coder efficacement en termes de temps d'exécution et de mémoire. Votre code Python doit également être bien structuré et facile à lire. Les conseils vous aideront à écrire du code Python efficace et lisible.
Astuce 1 : Accélérez NumPy
NumPy est une bibliothèque Python pour travailler efficacement avec des tableaux. Il offre également des opérations vectorisées rapides et optimisées. Mais! Il ne prend pas en charge le traitement parallèle. Comme alternative à NumPy, vous pouvez utiliser NumExpr .
NumExpr atteint des performances nettement meilleures que NumPy car il prend en charge le multi-threading. De plus, cela évite d'allouer de la mémoire pour des résultats intermédiaires.
Tout d'abord, vous devez installer les packages NumPy et NumExpr. Par exemple:
$ pip install numpy numexpr
import numpy as np
import numexpr as ne
import timeit
var1 = np.random.random(2**27)
var2 = np.random.random(2**27)
%timeit np.sin(var1) / np.cos(var2)
# 2.73 s
%timeit ne.evaluate("sin(var1) / cos(var2)")
# 566 ms
NumExpr fonctionne mieux lorsque vous avez de grands tableaux. Il développe également ses performances maximales si vous disposez d'un ordinateur puissant avec de nombreux cœurs. Pour cette raison, nous recommandons NumExpr lorsque ces deux conditions sont présentes. Pour les petites opérations sur les tableaux, vous pouvez également utiliser NumPy, car les différences de performances sont très minimes. La raison en est que NumExpr divise les opérandes du tableau en petits morceaux. Ces morceaux s'intègrent facilement dans le cache du processeur. Les morceaux sont répartis entre les cœurs disponibles du CPU, permettant une exécution parallèle.
Si vous souhaitez en savoir plus sur NumExpr, consultez le référentiel GitHub de NumExpr .
Astuce 2 : Alternative rapide aux pandas apply()
La fonction pandas apply() peut exécuter des fonctions le long d'un axe d'une trame de données. De nombreux programmeurs utilisent la fonction apply() en combinaison avec les fonctions lambda. Mais comment augmenter les performances d'une fonction apply() ?
Vous pouvez utiliser le package plus rapidement. Ce package applique très rapidement des fonctions aux blocs de données ou aux séries. La fonction pandas apply() s'exécute sur un seul cœur, et la plus rapide fournit une prise en charge de plusieurs cœurs.
Tout d'abord, vous devez installer le package plus rapide.
$ pip install swifter
import pandas as pd
import numpy as np
import swifter
import timeit
df = pd.DataFrame({'a': np.random.randint(7, 10, 10**7)})
# pandas apply()
%timeit df.apply(lambda x: x**7)
# 54 ms
# swifter.apply()
%timeit df.swifter.apply(lambda x: x**7)
# 37.5 ms
Astuce 3 : Utiliser les fonctions Python intégrées
Souvent, vous implémentez une fonction et ne savez pas qu'elle existe déjà en Python. Surtout si vous venez d'autres langages de programmation tels que C ou C++. Tout d'abord, vous devez toujours vérifier si une fonction intégrée Python existe déjà. Les fonctions intégrées de Python sont beaucoup plus rapides que les implémentations personnalisées, vous devez donc toujours les utiliser. L'exemple suivant le démontre.
import numpy as np
from time import perf_counter
result_list = []
company_list = ["Tesla", "Block", "Palantir", "Apple"]
company_list_sample = np.repeat(company_list, 10**7)
start = perf_counter()
for company in company_list_sample:
result_list.append(company.lower())
print(perf_counter()-start)
# 17.13 s
start = perf_counter()
result_list = map(str.lower, company_list_sample)
print(perf_counter()-start)
# 0.97 s
Il existe de nombreuses autres fonctions intégrées, telles que min(), max(), all(), etc. Faites vos propres recherches si vous avez besoin d'une fonction Python spécifique. Ça en vaut la peine!
Astuce 4 : Utilisez la compréhension de liste au lieu de boucles
Les programmeurs utilisent souvent des listes en combinaison avec des boucles pour stocker les résultats calculés. Cependant, cette approche n'est pas efficace en termes de temps d'exécution. Pour cette raison, il est préférable d'utiliser la compréhension de liste, qui offre de meilleures performances. L'exemple suivant montre la différence de performances.
import numpy as np
from time import perf_counter
result_list_loop = []
result_list_com = []
number_round = 10000000
start = perf_counter()
for i in range(number_round):
result_list_loop.append(i*i)
print(perf_counter()-start)
# 1.47 s
start = perf_counter()
result_list_com = [i*i for i in range(number_round)]
print(perf_counter()-start)
# 0.69 s
print(result_list_com[10])
# 100
Une compréhension de liste commence par une parenthèse ouvrante [. Ensuite, il y a le calcul de la boucle for. Vient ensuite l'en-tête de la boucle avec trois éléments (mot-clé pour, variable d'exécution, longueur de la boucle). La compréhension de la liste est fermée par une parenthèse fermante ]. Une fois que vous avez compris la syntaxe, vous pouvez écrire des boucles for de manière beaucoup plus compacte.
Mais qu'en est-il en termes d'utilisation de la mémoire ? Comment réduire l'espace mémoire ? Il est particulièrement conseillé avec de grandes listes si nous voulons effectuer d'autres opérations sur celles-ci. Dans notre exemple, nous stockons 1 000 000 valeurs dans la liste. Mais devons-nous enregistrer directement toutes les entrées ou n'en avons-nous besoin qu'en cas de besoin ?
Dans ces cas, nous pouvons utiliser des générateurs. Un générateur crée un élément de liste lorsque cela est nécessaire. En conséquence, un générateur nécessite moins de mémoire et a un meilleur temps d'exécution. Jetez un oeil à l'exemple suivant.
import sys
from time import perf_counter
print(sys.getsizeof(result_list_com), 'bytes')
# 89095160 bytes
start = perf_counter()
result_gen = (i*i for i in range(number_round))
print(perf_counter()-start)
# 0.22 ms
print(sys.getsizeof(result_gen), 'bytes')
# 112 bytes
print(list(result_gen)[10])
# 100
Astuce 5 : Fusionner les dicts avec une syntaxe à double astérisque **
Comment fusionner des dictionnaires ? Vous pouvez le faire avec un one-liner. Nous utilisons la syntaxe astérisque **. Dans l'exemple suivant, vous pouvez voir comment cela fonctionne.
dict_1 = {'company': 'Tesla', 'founding': 2002}
dict_2 = {'company': 'Tesla', 'founding': 2003, 'CEO': 'Elon Musk'}
dict_merged = {**dict_1, **dict_2}
print(dict_merged)
# {'company': 'Tesla', 'Founding': 2003, 'CEO': 'Elon Musk'}
Une autre méthode est la méthode de mise à jour. Cette méthode met à jour le premier dictionnaire et ne crée pas de copie. Jetez un oeil à l'exemple suivant.
dict_1 = {'company': 'Tesla', 'founding': 2002}
dict_2 = {'company': 'Tesla', 'founding': 2003, 'CEO': 'Elon Musk'}
dict_1.update(dict_2)
print(dict_1)
# {'company': 'Tesla', 'Founding': 2003, 'CEO': 'Elon Musk'}
Astuce 6 : N'importez pas de modules inutiles
Vous avez peut-être entendu cette astuce plusieurs fois, mais elle peut améliorer considérablement les performances de votre code. Il n'est pas nécessaire d'importer des bibliothèques entières. Vous n'avez généralement besoin que de certaines fonctions de celui-ci. De plus, votre code met beaucoup de temps à démarrer car toute la bibliothèque doit d'abord être importée. Cela ne devrait pas être le cas. De plus, vous devez ensuite accéder aux fonctions individuelles via la notation par points. C'est très inefficace et vous devriez éviter la notation par points. Les exemples suivants le démontrent.
import math
from time import perf_counter
start = perf_counter()
variable = math.exp(7)
print(perf_counter()-start)
# 8.47-05 s
from math import exp
from time import perf_counter
start = perf_counter()
variable = exp(7)
print(perf_counter()-start)
# 4.51-05 s
Astuce 7 : Utilisez le compilateur juste-à-temps
Numba est un compilateur juste-à-temps (jit) qui fonctionne bien avec les boucles, les tableaux et les fonctions NumPy. Les décorateurs sont utilisés pour demander à Numba de compiler certaines fonctions avec Numba. Numba compile les fonctions décorées juste-à-temps dans le code machine afin que tout ou partie du code s'exécute à la vitesse du code machine natif.
Nous devons d'abord installer Numba via pip.
pip install numba
import numpy as np
from numba import jit
import timeit
var = np.random.random(10**7)
num_loop = 10000
def foo(var):
result = 0
for i in range(num_loop):
result += 1
result = np.sin(var) + np.cos(var)
return result
%timeit foo(var)
# 154 ms
@jit(nopython=True)
def foo_numba(var):
result = 0
for i in range(num_loop):
result += 1
result = np.sin(var) + np.cos(var)
return result
%timeit foo_numba(var)
# 76.3 ms
Les inconvénients:
- Numba ne prend pas en charge les pandas.
- Le code non pris en charge est exécuté via l'interpréteur et a la surcharge Numba supplémentaire.
- Seul support non officiel sur M1/Arm64.
- Très bon support pour les tableaux et fonctions NumPy, et les boucles.
- Prise en charge de Nvidia CUDA. Il peut être bien utilisé pour le développement de réseaux de neurones basés sur NumPy.
Conclusion
Dans cet article, nous avons appris comment augmenter l'efficacité de votre code en termes de temps d'exécution et de mémoire. Leçons apprises:
- NumPy ne prend pas en charge le traitement parallèle. Vous pouvez utiliser NumExpr pour cela.
- La fonction pandas apply() peut être accélérée en étant plus rapide.
- Vérifiez s'il existe des fonctions intégrées.
- Utilisez la compréhension de liste au lieu de boucles. Vérifiez si les générateurs conviennent à votre projet.
- Fusionner les dicts avec une syntaxe à double astérisque **.
- N'importez pas de modules inutiles.
- Si vous avez des problèmes d'exécution, vous pouvez utiliser des compilateurs juste-à-temps. Les compilateurs juste-à-temps accélèrent votre code.
Merci beaucoup d'avoir lu. Si cet article vous a plu, n'hésitez pas à le partager. Suivez-moi pour plus de contenu. Passe une bonne journée!
![Qu'est-ce qu'une liste liée, de toute façon? [Partie 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































