Filtrer data en utilisant ID == ‘string’ dans Pandas est quelque chose que vous devriez éviter car l'opérateur scalar_compare conduit à des goulots d'étranglement au niveau des performances. Il existe de nombreux moyens de contourner ce problème, par exemple en partitionnant votre Dataframe en un dictionnaire utilisant l'ID en question comme clé.
Introduction - Filtres de chaînes de caractères dans pandas
La simplification de la gestion du matériel, apportée par les solutions cloud, nous pousse de plus en plus à nous détourner des problèmes d'optimisation du code.

Mais le passage à l'échelle et la l'augmentation de la puissance de calcul n'est pas toujours la solution car elle entraîne une escalade des coûts et la puissance de calcul n'est pas infinie.
En me lançant le défi de faire tenir toute ma préparation data sur un simple conteneur, je me suis vite rendu compte qu'avec la connaissance de quelques astuces, L'optimisation de votre code peut parfois être aussi simple que l'instanciation d'une instance plus grande.
Dans cet article, j'aimerais revenir sur une simple modification de code qui m'a permis de réduire considérablement le temps consacré au calcul des caractéristiques pendant la phase de développement d'un modèle de propension. Cette modification est suffisamment courante pour être appliquée à de nombreuses autres situations.

Elle ne vise pas à être la solution la plus optimale, mais cherche à être une option rapide pour réduire le temps de calcul d'une manière efficace, dans l'esprit de l'initiative Principe de Pareto.
Contexte
Au cours de cette mission, j'ai été chargé d'automatiser le processus de préparation du data et la prédiction des modèles développés par notre équipe de scientifiques du Data. Pour simplifier le flux de data, le data transactionnel a été téléchargé tous les jours et a dû passer par une première étape de préparation de data. Prétraitement étape, suivie d'une seconde étape de Fonctionnalité Calcul avant d'atteindre la dernière étape de Modèle de prédiction en utilisant le modèle formé.

Au sein du Calcul des caractéristiques est celle dont l'exécution a pris le plus de temps : en effet, de nombreuses caractéristiques ont été calculées au niveau du client, ce qui a entraîné l'exécution récurrente d'une ligne de code étonnamment chronophage :

Cette simple ligne a été chronométrée à 18 ms, ce qui signifie qu'avec mes 33 717 clients à évaluer quotidiennement, je passais environ 10 minutes de temps de calcul brut par fonctionnalité au niveau du client, réduites à 1 minute et 16 secondes par fonctionnalité grâce à la parallélisation de l'opération sur mes 8 CPUs disponibles.
Comme nous travaillions avec B2B data, il était nécessaire de calculer les caractéristiques au niveau du client, étant donné qu'un client représentait en fait une entreprise avec parfois plusieurs commandes par jour.
Expérimentation des filtres de chaînes de caractères dans pandas
Après quelques recherches à l'aide de l'outil %%prun magique, j'ai pu identifier la source de ce goulot d'étranglement : le pandas._libs.ops.scalar_compare qui était sous-optimisé dans ma version de Pandas (1.3.1).

En remplaçant simplement ce “==”par “isin”, ce qui n'est pas très intuitif puisque je comparais une seule chaîne de caractères, j'ai déjà divisé le temps de calcul par 2,5 fois, passant de 18 ms par opération à 7,95 ms.

Toujours en quête d'optimisation, je suis tombé sur un Stackoverflow (en anglais) qui pousse à l'utilisation de Type catégorique pour améliorer encore l'opération.

Cette dernière implémentation m'a permis de diviser le temps de calcul plus que 36 fois. J'ai toutefois pu observer une nuance dans cette astuce, car le type de catégorie ne se comporte pas comme une catégorie classique pendant toutes les opérations (voir l'exemple ci-dessous lors de l'utilisation de .groupby() dans pandas), j'ai donc dû le reconvertir en str à un moment donné.

Hypothèse
Mais pourquoi ? Comment un simple == entre deux chaînes de caractères prend plus de temps qu'une opération isin() pour comparer des listes, ou une opération catégorique un ?
Pour répondre à la première question, il nous faut absolument trouver le code qui sous-tend l'exécution de la fonction scalaire_compare qui utilise principalement Cython et comparez-le au code qui se trouve derrière le isin() méthode.
Heureusement, la réponse à la deuxième partie semble plus intuitive : lorsque nous comparons deux valeurs de chaînes de caractères, nous comparons une chaîne de caractères. nombre infini des possibilités ensemble, alors que lorsqu'on compare deux catégories, la le nombre d'options est fixé par les différentes catégories uniques qui existent. Il semble beaucoup il est plus facile de comparer deux entités lorsque le nombre d'options est fixe.
Ma soif d'optimisation n'étant toujours pas étanchée, j'ai décidé de prendre du recul par rapport à la méthode actuelle. J'ai imaginé une nouvelle approche : partitionner mon Dataframe en un dictionnaire que j'utiliserai ensuite pour filtrer mes clients lors du calcul de mes caractéristiques.
En termes de code, cela se traduit simplement par les lignes suivantes :
La construction de ce dictionnaire m'a coûté 32 secondes de temps de calcul, mais en utilisant ce cadre Data partitionné, j'ai pu filtrer mon data en quelques nanosecondes.

Conclusion - Filtres de chaînes de caractères dans pandas
Après avoir passé quelques heures dans la phase d'expérimentation, j'étais satisfait du résultat :

Le temps de calcul initial pour le filtrage des clients est maintenant divisé en deux parties 348 000 fois, passant de 18ms à 51,7ns, ou de 10min à 2,65ms par caractéristique calculée dans mon cas, en tenant compte du temps passé sur le partitionnement.

Immédiatement, l'impact de ce petit changement m'a permis de réduire le temps de calcul de ma phase complète de calcul des caractéristiques de 90%, de 40’49” à 7’27”. En utilisant une méthode d'estimation du CO2eq que je détaillerai dans mon prochain article, cette modification a permis d'économiser au moins 170$/an + 22kgCO2/an et potentiellement beaucoup plus avec la liste croissante de clients et le déploiement du projet dans d'autres pays.

BLOG







