Meilleures pratiques pour transformer les carnets jupyter en scripts python

Jupyter (iPython) notebook est à juste titre connu comme un bon outil pour prototyper le code et faire toutes sortes de choses machine d'apprentissage interactivement. Mais quand je l'utilise, je tombe inévitablement sur ce qui suit:

  • le notebook devient rapidement trop complexe et confus pour être maintenu et amélioré en tant que notebook, et je dois en faire des scripts python;
  • en ce qui concerne le code de production (par exemple un code qui doit être relancé chaque jour), l'ordinateur portable n'est pas le meilleur format.

supposez que j'ai développé un pipeline entier d'apprentissage machine à jupyter qui comprend la récupération de données brutes provenant de diverses sources, le nettoyage des données, l'ingénierie des fonctionnalités, et les modèles d'entraînement après tout. Maintenant, quelle est la meilleure logique pour en faire des scripts avec du code efficace et lisible? Je m'y attaquais de plusieurs façons jusqu'à présent:

  1. convertissez simplement .ipynb .py et, avec seulement de légers changements, codez dur tout le pipeline à partir du bloc-notes en un seul script python.

    • '+': rapide
    • ' -': sale, non flexible, ne convient pas à l'entretien
  2. faire un script unique avec de nombreuses fonctions (environ, 1 Fonction pour chaque une ou deux cellules), en essayant de comprendre les étapes du pipeline avec des fonctions séparées, et les nommer en conséquence. Puis spécifiez tous les paramètres et les constantes globales via argparse .

    • '+': utilisation plus souple; code plus lisible (si vous avez correctement transformé la logique du pipeline en fonctions)
    • ' -': souvent, le pipeline n'est pas divisible en morceaux finis logiquement qui pourraient devenir des fonctions sans aucune bizarrerie dans le code. Toutes ces fonctions sont typiquement nécessaires pour être appelé seulement une fois dans le script plutôt que d'être appelé plusieurs fois à l'intérieur des boucles, des cartes etc. En outre, chaque fonction prend typiquement la sortie de toutes les fonctions appelées auparavant, donc on doit passer beaucoup d'arguments à chaque fonction.
  3. la même chose que le point (2), mais maintenant envelopper toutes les fonctions à l'intérieur de la classe. Maintenant toutes les constantes globales, ainsi que les sorties de chaque méthode peuvent être stockées sous forme d'attributs de classe.

    • '+': vous n'avez pas besoin de passer beaucoup d'arguments à chaque méthode -- toutes les sorties précédentes déjà stockées comme attributs
    • ' -': la logique générale d'une tâche n'est toujours pas saisie -- il s'agit d'un pipeline d'apprentissage de données et de machines, pas seulement de la classe. Le seul but pour la classe est d'être créé, appeler toutes les méthodes séquentiellement un par un et ensuite être supprimé. En plus de cela, les classes sont assez longues à mettre en œuvre.
  4. convertissez un bloc-notes en module python avec plusieurs scripts. Je n'ai pas essayez ça, mais je pense que c'est le moyen le plus long pour régler le problème.

je suppose que ce cadre général est très commun parmi les scientifiques de données, mais étonnamment Je ne trouve pas de conseils utiles autour.

les amis, s'il vous plaît, partagez vos idées et votre expérience. Avez-vous déjà rencontré ce problème? Comment avez-vous abordé?

31
demandé sur kurtosis 2015-08-24 16:09:12

2 réponses

Nous avons le même problème. Cependant, nous utilisons plusieurs notebooks pour prototyper les résultats qui devraient aussi devenir plusieurs scripts python après tout.

notre approche est que nous avons mis de côté le code, qui coutures à répéter à travers ces carnets. Nous l'avons mis dans le module python, qui est importé par chaque ordinateur portable et également utilisé dans la production. Nous améliorons ce module de façon itérative de façon continue et ajoutons des tests de ce que nous trouvons lors du prototypage.

Les Notebooks

deviennent alors un peu comme les scripts de configuration (que nous copions simplement dans les fichiers Python résultants) et plusieurs vérifications de prototypage et validations, dont nous n'avons pas besoin dans la production.

nous n'avons surtout pas peur du remaniement:)

9
répondu Radek 2015-12-30 11:23:29

Life saver : pendant que vous écrivez vos notebooks, remaniez progressivement votre code en fonctions, en écrivant quelques tests et docstrings minimaux assert .

après cela, le remaniement de bloc-notes en écriture est naturel. Non seulement cela, mais il rend votre vie plus facile en écrivant de longs carnets, même si vous n'avez pas l'intention de les transformer en autre chose.

exemple de Base d'un le contenu de la cellule avec des tests et des docstrings" minimes":

def zip_count(f):
    """Given zip filename, returns number of files inside.

    str -> int"""
    from contextlib import closing
    with closing(zipfile.ZipFile(f)) as archive:
        num_files = len(archive.infolist())
    return num_files

zip_filename = 'data/myfile.zip'

# Make sure `myfile` always has three files
assert zip_count(zip_filename) == 3
# And total zip size is under 2 MB
assert os.path.getsize(zip_filename) / 1024**2 < 2

print(zip_count(zip_filename))

une fois que vous l'aurez exporté vers des fichiers .py , votre code ne sera probablement pas encore structuré en classes. Mais il vaut la peine de l'effort d'avoir remanié votre ordinateur portable au point où il a un ensemble de fonctions documentées, chacune avec un ensemble de simples assert déclarations qui peuvent facilement être déplacés dans tests.py pour les tests avec pytest , unittest , ou ce que vous avez. Si elle fait sens, regrouper ces fonctions dans des méthodes pour vos classes est mort-facile après cela.

si tout va bien, tout ce que vous devez faire après cela est d'écrire votre if __name__ == '__main__': et ses" hooks": si vous écrivez un script qui sera appelé par le terminal , vous voudrez Gérer les arguments en ligne de commande , si vous écrivez un module, vous voudrez penser à son API avec le __init__.py fichier , etc.

tout dépend de ce que le cas d'utilisation prévue est, bien sûr: il ya une grande différence entre la conversion d'un carnet à un petit script par rapport à le transformer en un module ou un paquet à part entière.

voici quelques idées pour un workflow de bloc-notes à script :

  1. Exportation de Jupyter Portable fichier Python (.py) par le biais de l'interface graphique.
  2. supprimer les lignes" helper " qui ne pas faire le travail réel: print déclarations, parcelles,etc.
  3. si nécessaire, Regroupez votre logique en classes. Le seul travail de remaniement supplémentaire requis devrait être d'écrire vos docstrings et attributs de classe.
  4. écrivez les entrées de votre script avec if __name__ == '__main__' .
  5. séparez vos énoncés assert pour chacune de vos fonctions/méthodes, et étoffez une suite de test minimale dans tests.py .
6
répondu François Leblanc 2018-02-06 13:45:18