Scientific Computing & Ipython Notebook: ¿Cómo organizar el código?

Estoy usando Ipython Notebook para mi investigación. A medida que mi archivo crece, constantemente extraigo código, cosas como el método de trazado, el método de ajuste, etc.

Creo que necesito una forma de organizar esto. ¿Hay alguna buena manera de hacerlo?


Actualmente, hago esto por:

data/ helpers/ my_notebook.ipynb import_file.py 

Almaceno datos en data/ , y helper method en helpers/ , y los plot_helper.py en archivos como plot_helper.py , app_helper.py , etc.

import_file.py las importaciones en import_file.py ,

 from IPython.display import display import numpy as np import scipy as sp import pandas as pd import matplotlib as mpl from matplotlib import pyplot as plt import sklearn import re 

Y luego puedo importar todo lo que necesito en .ipynb en la celda superior como

introduzca la descripción de la imagen aquí

La estructura se puede ver en https://github.com/cqcn1991/Wind-Speed-Analysis

Un problema que tengo ahora es que tengo demasiados submódulos en los helpers/ y es difícil pensar qué método se debe poner en qué archivo.

Creo que una forma posible es organizar en pre-processing , processing , post-processing .

ACTUALIZAR:

Mi gran cuaderno de investigación de jupyter: https://cdn.rawgit.com/cqcn1991/Wind-Speed-Analysis/master/output_HTML/marham.html

La celda superior es standard import + magic + extentions

 %matplotlib inline %load_ext autoreload %autoreload 2 from __future__ import division from import_file import * load_libs() 

Hay muchas formas de organizar el proyecto de investigación ipython. Estoy administrando un equipo de 5 científicos de datos y 3 ingenieros de datos, y encontré que estos consejos están funcionando bien para nuestro caso de uso:

Este es un resumen de mi charla sobre PyData Londres:

http://www.slideshare.net/vladimirkazantsev/clean-code-in-jupyter-notebook

1. Crea una biblioteca de utils compartida (multiproyecto)

Es muy probable que tenga que reutilizar / repetir algún código en diferentes proyectos de investigación. Comienza a refactorizar esas cosas en el paquete “utils comunes”. Haga el archivo setup.py, inserte el módulo en github (o similar), para que los miembros del equipo puedan “instalarlo” desde VCS.

Ejemplos de funcionalidad para poner allí son:

  • Funciones de almacenamiento de datos o acceso a almacenamiento
  • funciones de trazado comunes
  • Métodos matemáticos / estadísticas reutilizables

2. Divide tu cuaderno maestro gordo en cuadernos más pequeños

En mi experiencia, la buena longitud del archivo con código (cualquier idioma) es solo de algunas pantallas (100-400 líneas). Jupyter Notebook sigue siendo el archivo de origen, pero con salida! Leer un cuaderno con más de 20 celdas es muy difícil. Me gusta que mis cuadernos tengan un máximo de 4 a 10 celdas.

Idealmente, cada cuaderno debería tener un triplete de “hipótesis-datos-conclusiones”.

Ejemplo de división del cuaderno:

1_data_preparation.ipynb

2_data_validation.ipynb

3_exploratory_plotting.ipynb

4_simple_linear_model.ipynb

5_hierarchical_model.ipynb

playground.ipynb

Guarde la salida de 1_data_preparation.ipynb en pickle df.to_pickle('clean_data.pkl') , csv o fast DB y use pd.read_pickle("clean_data.pkl") en la parte superior de cada cuaderno.

3. No es Python, es IPython Notebook

Lo que hace que el portátil sea único son las células . Utilízalos bien. Cada celda debe ser el triplete “idea-ejecución-salida”. Si la celda no produce nada, combine con la siguiente celda. La celda de importación no debe generar nada; esta es una salida esperada para ella.

Si la celda tiene pocas salidas, puede valer la pena dividirla.

Ocultar las importaciones puede o no ser una buena idea:

 from myimports import * 

Su lector puede querer averiguar qué es exactamente lo que está importando para usar las mismas cosas para su investigación. Así que use con precaución. Lo usamos para pandas, numpy, matplotlib, sql sin embargo.

Ocultar “salsa secreta” en /helpers/model.py es malo:

 myutil.fit_model_and_calculate(df) 

Esto puede ahorrarle la escritura y eliminará el código duplicado, pero su colaborador tendrá que abrir otro archivo para averiguar qué está pasando. Desafortunadamente, notebook (jupyter) es un entorno bastante inflexible y básico, pero aún así no quiere forzar a su lector a dejarlo para cada pieza de código. Espero que en el futuro IDE mejore, pero por ahora, mantenga la “salsa secreta” dentro de un cuaderno . Mientras que “utils aburridos y obvios” – donde quiera que veas ajuste. Seco todavía se aplica – tienes que encontrar el equilibrio.

Esto no debería impedirle empaquetar código reutilizable en funciones o incluso en clases pequeñas. Pero “plano es mejor que nested”.

4. Mantenga los cuadernos limpios

Debería poder “reiniciar y ejecutar todo” en cualquier momento.

¡Cada repetición debe ser rápida! Lo que significa que puede tener que invertir en escribir algunas funciones de almacenamiento en caché. Puede ser que incluso quieras ponerlos en tu módulo de “utils comunes”.

Cada celda debe ser ejecutable varias veces, sin la necesidad de reinicializar la notebook. Esto le ahorra tiempo y mantiene el código más robusto. Pero puede depender del estado creado por las células anteriores. Hacer que cada celda sea completamente independiente de las celdas de arriba es un anti-patrón, OMI.

Una vez que haya terminado con la investigación, no ha terminado con el cuaderno. Refactor

5. Crea un módulo de proyecto, pero sé muy selectivo.

Si continúa reutilizando la función de trazado o análisis, refactorice en este módulo. Pero en mi experiencia, la gente espera leer y entender un cuaderno, sin abrir varios submódulos de utilidad. Por lo tanto, nombrar bien las subrutinas es aún más importante aquí, en comparación con Python normal.

“El código limpio se lee como una prosa bien escrita” Grady Booch (desarrollador de UML)

6. Alojar el servidor Jupyter en la nube para todo el equipo.

Tendrá un entorno, por lo que todos pueden revisar y validar la investigación rápidamente sin la necesidad de emparejar el entorno (aunque Conda lo hace bastante fácil).

Y puede configurar los valores predeterminados, como mpl style / colors y hacer matplot lib inline, de forma predeterminada:

En ~/.ipython/profile_default/ipython_config.py

Agregue la línea c.InteractiveShellApp.matplotlib = 'inline'

7. (idea experimental) Ejecutar un cuaderno desde otro cuaderno, con diferentes parámetros

Muy a menudo es posible que desee volver a ejecutar el cuaderno completo, pero con diferentes parámetros de entrada.

Para hacer esto, puede estructurar su cuaderno de investigación de la siguiente manera: Coloque el diccionario de parámetros en la primera celda del “cuaderno de origen”.

 params = dict(platform='iOS', start_date='2016-05-01', retention=7) df = get_data(params ..) do_analysis(params ..) 

Y en otro cuaderno (nivel lógico superior), ejecútelo usando esta función:

 def run_notebook(nbfile, **kwargs): """ example: run_notebook('report.ipynb', platform='google_play', start_date='2016-06-10') """ def read_notebook(nbfile): if not nbfile.endswith('.ipynb'): nbfile += '.ipynb' with io.open(nbfile) as f: nb = nbformat.read(f, as_version=4) return nb ip = get_ipython() gl = ip.ns_table['user_global'] gl['params'] = None arguments_in_original_state = True for cell in read_notebook(nbfile).cells: if cell.cell_type != 'code': continue ip.run_cell(cell.source) if arguments_in_original_state and type(gl['params']) == dict: gl['params'].update(kwargs) arguments_in_original_state = False 

Aún está por verse si este “patrón de diseño” resulta ser útil. Tuvimos algo de éxito, al menos dejamos de duplicar los portátiles solo para cambiar algunas entradas.

Refactorización del notebook en una clase o módulo rompe el bucle de retroalimentación rápida de “idea-ejecución-salida” que proporcionan las celdas. Y, IMHO, no es “ipythonic” ..

8. Escriba (unidad) las pruebas para bibliotecas compartidas en cuadernos y ejecute con py.test

¡Hay un complemento para py.test que puede descubrir y ejecutar pruebas dentro de cuadernos!

https://pypi.python.org/pypi/pytest-ipynb

Idealmente debería tener una jerarquía de bibliotecas. Lo organizaría de la siguiente manera:

Paquete wsautils

Paquete fundamental, nivel más bajo [Sin dependencias]

stringutils.py: contiene los archivos más básicos, como la manipulación de cadenas dateutils.py: métodos de manipulación de fechas

Paquete wsadata

  • Análisis de datos, manipulaciones de marcos de datos, métodos de ayuda para Pandas, etc.
  • Depende de [wsautils]
    • pandasutils.py
    • parseutils.py
    • jsonutils.py [esto también podría ir en wsautils]
    • etc.

Paquete wsamath (o wsastats)

Utilidades, modelos, PDF, CDF relacionados con matemáticas [Depende de wsautils, wsadata] Contiene: – percentutut.py – statutils.py etc.

Paquete wsacharts [o wsaplot]

  • GUI, Plotting, Matplotlib, GGplot, etc.
  • Depende de [wsautils, wsamath]
    • histogram.py
    • pichart.py
    • Solo una idea, también podría tener un solo archivo aquí llamado chartutils o algo así

Tienes la idea Cree más bibliotecas según sea necesario sin hacer demasiadas.

Algunos otros consejos:

  • Siga los principios de una buena gestión de paquetes python a fondo. Lea este http://python-packaging-user-guide.readthedocs.org/en/latest/installing/
  • Implemente una administración de dependencias estricta a través de un script o una herramienta de manera que no haya dependencias circulares entre paquetes
  • Defina bien el nombre y el propósito de cada biblioteca / módulo para que otros usuarios también puedan decir de manera intuitiva dónde debe ir un método / utilidad
  • Siga los buenos estándares de encoding de Python (vea PEP-8)
  • Escribir casos de prueba para cada biblioteca / paquete
  • Use un buen editor (PyCharm es bueno para Python / iPython)
  • Documentar tus APIs, métodos

Finalmente, recuerde que hay muchas maneras de despellejar a un gato y lo anterior es solo uno que me gusta. HTH.

Si bien las respuestas proporcionadas cubren el tema a fondo, todavía vale la pena mencionar a Cookiecutter, que proporciona una estructura de proyecto de ciencia de datos.

Cookiecutter Data Sciencee

proporciona una plantilla de ciencia de datos para proyectos en Python con una estructura de proyecto lógica, razonablemente estandarizada y flexible para realizar y compartir el trabajo de ciencia de datos

Su análisis no tiene por qué estar en Python, pero la plantilla sí proporciona una plantilla de Python (en la carpeta src, por ejemplo, y el esqueleto de documentación de Sphinx en documentos). Sin embargo, nada es vinculante.

La siguiente cita de la descripción del proyecto lo resume bastante bien:

Nadie se sienta antes de crear un nuevo proyecto de Rails para averiguar dónde quieren poner sus puntos de vista; simplemente ejecutan rails new para obtener un esqueleto de proyecto estándar como todos los demás.

Requisitos:

  • Python 2.7 o 3.5
  • Paquete Python de cookiecutter> = 1.4.0: pip install cookiecutter

Empezando

Iniciar un nuevo proyecto es tan fácil como ejecutar este comando en la línea de comandos. No es necesario crear un directorio primero, el cocinero lo hará por usted.

 cookiecutter https://github.com/drivendata/cookiecutter-data-science 

Estructura de directorios

 ├── LICENSE ├── Makefile <- Makefile with commands like `make data` or `make train` ├── README.md <- The top-level README for developers using this project. ├── data │ ├── external <- Data from third party sources. │ ├── interim <- Intermediate data that has been transformed. │ ├── processed <- The final, canonical data sets for modeling. │ └── raw <- The original, immutable data dump. │ ├── docs <- A default Sphinx project; see sphinx-doc.org for details │ ├── models <- Trained and serialized models, model predictions, or model summaries │ ├── notebooks <- Jupyter notebooks. Naming convention is a number (for ordering), │ the creator's initials, and a short `-` delimited description, eg │ `1.0-jqp-initial-data-exploration`. │ ├── references <- Data dictionaries, manuals, and all other explanatory materials. │ ├── reports <- Generated analysis as HTML, PDF, LaTeX, etc. │ └── figures <- Generated graphics and figures to be used in reporting │ ├── requirements.txt <- The requirements file for reproducing the analysis environment, eg │ generated with `pip freeze > requirements.txt` │ ├── src <- Source code for use in this project. │ ├── __init__.py <- Makes src a Python module │ │ │ ├── data <- Scripts to download or generate data │ │ └── make_dataset.py │ │ │ ├── features <- Scripts to turn raw data into features for modeling │ │ └── build_features.py │ │ │ ├── models <- Scripts to train models and then use trained models to make │ │ │ predictions │ │ ├── predict_model.py │ │ └── train_model.py │ │ │ └── visualization <- Scripts to create exploratory and results-oriented visualizations │ └── visualize.py │ └── tox.ini <- tox file with settings for running tox; see tox.testrun.org 

Relacionado:

ProjectTemplate : proporciona un sistema similar para el análisis de datos R