J'effectue régulièrement des opérations de pandas sur des trames de données de plus de 15 millions de lignes et j'aimerais avoir accès à un indicateur de progression pour des opérations particulières.
Existe-t-il un indicateur de progression basé sur du texte pour les opérations de fractionnement-appliquer-combiner pandas?
Par exemple, dans quelque chose comme:
df_users.groupby(['userID', 'requestDate']).apply(feature_rollup)
où feature_rollup
est une fonction quelque peu impliquée qui prend de nombreuses colonnes DF et crée de nouvelles colonnes utilisateur par diverses méthodes. Ces opérations peuvent prendre un certain temps pour les grandes trames de données, j'aimerais donc savoir s'il est possible d'avoir une sortie texte dans un bloc-notes iPython qui me met à jour sur la progression.
Jusqu'à présent, j'ai essayé des indicateurs de progression de boucle canoniques pour Python, mais ils n'interagissent pas avec les pandas de manière significative.
J'espère qu'il y a quelque chose que j'ai négligé dans la bibliothèque / documentation de pandas qui permet de connaître la progression d'un split-apply-combine. Une implémentation simple pourrait peut-être examiner le nombre total de sous-ensembles de trames de données sur lesquels la apply
fonction travaille et rapporter la progression comme la fraction terminée de ces sous-ensembles.
Est-ce peut-être quelque chose qui doit être ajouté à la bibliothèque?
Réponses:
En raison de la demande populaire,
tqdm
a ajouté un support pourpandas
. Contrairement aux autres réponses, cela ne ralentira pas sensiblement les pandas - voici un exemple pourDataFrameGroupBy.progress_apply
:Si vous souhaitez savoir comment cela fonctionne (et comment le modifier pour vos propres rappels), consultez les exemples sur github , la documentation complète sur pypi , ou importez le module et exécutez
help(tqdm)
.ÉDITER
Pour répondre directement à la question d'origine, remplacez:
avec:
Remarque: tqdm <= v4.8 : Pour les versions de tqdm inférieures à 4.8, au lieu de cela,
tqdm.pandas()
vous deviez faire:la source
tqdm
a été en fait créé pour des itérables simples à l'origine:from tqdm import tqdm; for i in tqdm( range(int(1e8)) ): pass
Le support pandas était un hack récent que j'ai fait :)from tqdm import tqdm_notebook; tqdm_notebook().pandas(*args, **kwargs)
voir icitqdm
v5 qui rend les choses plus modulaires.Pour modifier la réponse de Jeff (et avoir ceci comme fonction réutilisable).
Note: le pourcentage appliquent progrès mises à jour en ligne . Si votre fonction stdouts, cela ne fonctionnera pas.
Comme d'habitude, vous pouvez ajouter ceci à vos objets groupby en tant que méthode:
Comme mentionné dans les commentaires, ce n'est pas une fonctionnalité que les pandas de base seraient intéressés à implémenter. Mais python vous permet de les créer pour de nombreux objets / méthodes pandas (cela serait un peu de travail ... bien que vous devriez être en mesure de généraliser cette approche).
la source
Au cas où vous auriez besoin d'aide pour savoir comment l'utiliser dans un notebook Jupyter / ipython, comme je l'ai fait, voici un guide utile et une source vers l' article pertinent :
Notez le trait de soulignement dans l'instruction d'importation pour
_tqdm_notebook
. Comme le mentionne l'article référencé, le développement est en phase bêta tardive.la source
Pour tous ceux qui cherchent à appliquer tqdm sur leur code d'application de pandas parallèle personnalisé.
(J'ai essayé certaines des bibliothèques de parallélisation au fil des ans, mais je n'ai jamais trouvé de solution de parallélisation à 100%, principalement pour la fonction apply, et je devais toujours revenir pour mon code "manuel".)
df_multi_core - c'est celui que vous appelez. Il accepte:
_df_split - il s'agit d'une fonction d'assistance interne qui doit être positionnée globalement sur le module en cours d'exécution (Pool.map est "dépendant du placement"), sinon je la localiserais en interne ..
voici le code de mon résumé (j'ajouterai plus de tests de fonction pandas ici):
Ci-dessous est un code de test pour une application parallélisée avec tqdm "progress_apply".
Dans la sortie, vous pouvez voir 1 barre de progression pour l'exécution sans parallélisation et des barres de progression par cœur lors de l'exécution avec parallélisation. Il y a un léger accrochage et parfois le reste des cœurs apparaît à la fois, mais même dans ce cas, je pense que c'est utile car vous obtenez les statistiques de progression par cœur (it / sec et total des enregistrements, par exemple)
Merci @abcdaa pour cette superbe bibliothèque!
la source
try: splits = np.array_split(df[subset], njobs) except ValueError: splits = np.array_split(df, njobs)
j'ai dû changer ces parties: à cause de l'exception KeyError au lieu de ValueError, passez à Exception pour gérer tous les cas.Vous pouvez facilement le faire avec un décorateur
puis utilisez simplement la fonction_modifiée (et changez quand vous voulez qu'elle s'imprime)
la source
logged_apply(g, func)
fonction, où vous auriez accès à la commande et pourriez vous connecter depuis le début.J'ai changé la réponse de Jeff , pour inclure un total, afin que vous puissiez suivre la progression et une variable pour simplement imprimer toutes les itérations X (cela améliore en fait beaucoup les performances, si le "print_at" est raisonnablement élevé)
la fonction clear_output () est de
sinon sur IPython La réponse d'Andy Hayden le fait sans elle
la source