ipynb - Scientific Computing & Ipython Notebook: ¿Cómo organizar el código?
jupyter r (3)
Hay muchas maneras 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 London:
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. Comience refactorizando 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 unas pocas 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 único al portátil son las células . Utilízalos bien. Cada celda debe ser un triplete "idea-ejecución-salida". Si la celda no produce nada, combine con la siguiente celda. La celda de importación no debería generar ningún resultado, este es un resultado esperado.
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 . Si bien "aburridas y obvias utils" - donde sea que veas encaja. 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 anidado".
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 anteriores es un antipatrón, IMO.
Después de que hayas terminado con la investigación, no has 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 analítica, 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 hace que esto sea 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.
Refactorizando el cuaderno en una clase o módulo, 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 la biblioteca compartida en cuadernos y ejecute con py.test
¡Hay un complemento para py.test que puede descubrir y ejecutar pruebas dentro de cuadernos!
Estoy usando el cuaderno Ipython 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
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 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()
Idealmente debería tener una jerarquía de bibliotecas. Lo organizaría de la siguiente manera:
Paquete wsautils
Fundamental, paquete de 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/
- Imponga 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 codificación 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 formas 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, pero flexible para realizar y compartir el trabajo de ciencia de datos.
Su análisis no tiene que 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 los 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, e.g.
│ `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, e.g.
│ 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