Contribuyendo¶
Este proyecto es un esfuerzo comunitario, y todos son bienvenidos a contribuir.
El proyecto está alojado en https://github.com/scikit-learn/scikit-learn
El proceso de toma de decisiones y la estructura de gobernanza de scikit-learn se exponen en el documento de gobernanza: La gestión y toma de decisiones en el ámbito de la ciencia.
Scikit-learn es un poco selective cuando se trata de añadir nuevos algoritmos, y la mejor manera de contribuir y ayudar al proyecto es empezar a trabajar en las incidencias(issues) conocidas. Ver Incidencias para los nuevos colaboradores para empezar.
Nuestra comunidad, nuestros valores
Somos una comunidad basada en la apertura y los debates amistosos y didácticos.
Aspiramos a tratar a todos por igual y a valorar sus contribuciones. Buscamos especialmente a personas con poca representación en el software de código abierto y en scikit-learn en particular para que participen y aporten sus conocimientos y experiencia.
Las decisiones se toman basándose en el mérito técnico y el consenso.
El código no es la única forma de ayudar al proyecto. Revisar pull requests, responder a preguntas para ayudar a otros en las listas de correo o en las incidencias, organizar y enseñar tutoriales, trabajar en el sitio web, mejorar la documentación, son todas contribuciones que no tienen precio.
Nos atenemos a los principios de apertura, respeto y consideración de los demás de la Python Software Foundation: https://www.python.org/psf/codeofconduct/
En caso de que experimentes alguna incidencia al utilizar este paquete, no dudes en enviar un ticket al Rastreador de problemas de GitHub. También puedes enviar solicitudes de funcionalidad o pull requests.
Formas de contribuir¶
Hay muchas maneras de contribuir a scikit-learn, siendo las más comunes la contribución de código o a la documentación del proyecto. Mejorar la documentación no es menos importante que mejorar la propia biblioteca. Si encuentras un error en la documentación, o has hecho mejoras, no dudes en enviar un correo electrónico a la lista de correo o, preferiblemente, envía una solicitud de extracción de GitHub. La documentación completa se encuentra en el directorio doc/.
Pero hay muchas otras formas de ayudar. En particular, ayudar a improve, triage, and investigate issues y reviewing other developers” pull requests son contribuciones muy valiosas que disminuyen la carga de los mantenedores del proyecto.
Otra forma de contribuir es informar de las incidencias a las que te enfrentas, y dar un «pulgar arriba» a las incidencias que otros informaron y que son relevantes para ti. También nos ayuda que corras la voz: haz referencia al proyecto desde tu blog y artículos, enlaza con él desde tu sitio web, o simplemente destaca para decir «yo lo uso»:
En el caso de que una contribución/incidencia implique cambios en los principios de la API o cambios en las dependencias o en las versiones soportadas, debe estar respaldada por un Propuestas de mejora (SLEPs), donde un SLEP debe ser enviado como un pull request a propuestas de mejora utilizando la plantilla SLEP y sigue el proceso de toma de decisiones descrito en La gestión y toma de decisiones en el ámbito de la ciencia.
StarContribuyendo a proyectos relacionados
Scikit-learn prospera en un ecosistema de varios proyectos relacionados, que también pueden tener incidencias relevantes en los que trabajar, incluyendo proyectos más pequeños como:
y proyectos más grandes:
y así sucesivamente.
Busca incidencias marcadas como «se necesita ayuda»(«help wanted») o similares. Ayudar a estos proyectos puede ayudar a Scikit-learn también. Ver también Proyectos Relacionados.
Enviar un informe de errores o una solicitud de funcionalidad(feature request)¶
Utilizamos las incidencias(issues) de GitHub para hacer un seguimiento de todos los errores y solicitudes de funcionalidades; no dudes en abrir una incidencia si has encontrado un error o deseas que se implemente una funcionalidad.
En caso de que experimentes incidencias al utilizar este paquete, no dudes en enviar un ticket al Rastreador de errores. También puedes enviar solicitudes de funcionalidad o pull requests.
Se recomienda comprobar que tu incidencia se ajusta a las siguientes normas antes de presentarlo:
Comprueba que tu incidencia(issue) no está siendo tratada por otros issues o pull requests.
Si estás enviando una solicitud de algoritmo o funcionalidad, por favor verifica que el algoritmo cumple con nuestros nuevos requisitos del algoritmo.
Si estás enviando un informe de errores, te recomendamos encarecidamente que sigas las directrices de Cómo hacer un buen informe de errores.
Cómo hacer un buen informe de errores¶
Cuando envíes una incidencia a Github, ¡haz lo posible por seguir estas directrices! Esto hará que sea mucho más fácil proporcionarte una buena retroalimentación:
El informe de error ideal contiene un corto fragmento de código reproducible, de esta manera cualquiera puede intentar reproducir el error fácilmente (ver esto para más detalles). Si tu fragmento es más largo que unas 50 líneas, por favor, enlaza con un gist o un repo de github.
Si no es posible incluir un fragmento reproducible, por favor, especifica qué estimadores y/o funciones están involucrados y la forma de los datos.
Si se lanza una excepción, por favor proporciona el rastreo(traceback) completo.
Por favor, incluye tu tipo de sistema operativo y número de versión, así como tus versiones de Python, scikit-learn, numpy y scipy. Esta información se puede encontrar ejecutando el siguiente fragmento de código:
>>> import sklearn >>> sklearn.show_versions()
Nota
Esta función de utilidad sólo está disponible en scikit-learn v0.20+. Para versiones anteriores, hay que ejecutar explícitamente:
import platform; print(platform.platform()) import sys; print("Python", sys.version) import numpy; print("NumPy", numpy.__version__) import scipy; print("SciPy", scipy.__version__) import sklearn; print("Scikit-Learn", sklearn.__version__)
Por favor, asegúrate de que todos los fragmentos de código y mensajes de error están formateados en bloques de código apropiados. Consulta Creación y resaltado de bloques de código para obtener más detalles.
Si quieres ayudar a solucionar las incidencias, lee lo siguiente.
Contribución de código¶
Nota
To avoid duplicating work, it is highly advised that you search through the issue tracker and the PR list. If in doubt about duplicated work, or if you want to work on a non-trivial feature, it’s recommended to first open an issue in the issue tracker to get some feedbacks from core developers.
Una forma fácil de encontrar una incidencia en la que trabajar es aplicar la etiqueta «se busca ayuda»(«help wanted») en tu búsqueda. En ella se enumeran todas las incidencias que no han sido reclamadas hasta el momento. Para reclamar un incidencia para ti, comenta exactamente take
en ella para que el CI te asigne automáticamente la incidencia.
Recursos de video¶
Estos videos son introducciones paso a paso sobre cómo contribuir a scikit-learn, y son un gran complemento a las siguientes pautas de texto. Por favor, asegúrate de seguir revisando nuestras directrices a continuación, ya que describen nuestro último flujo de trabajo actualizado.
Curso intensivo de contribución a proyectos de Scikit-Learn y de código abierto: Video, Traducción
Ejemplo de envío de un Pull Request a scikit-learn: Video, Traducción
Instrucciones específicas para el sprint y consejos prácticos: Video, Traducción
Cómo contribuir¶
La forma preferida de contribuir a scikit-learn es hacer un fork del repositorio principal en GitHub, y luego enviar un «pull request» (PR).
En los primeros pasos, explicamos cómo instalar localmente scikit-learn, y cómo configurar tu repositorio git:
Crea una cuenta en GitHub si aún no tienes una.
Haz un fork del repositorio del proyecto: haz clic en el botón “Fork” cerca de la parte superior de la página. Esto crea una copia del código bajo tu cuenta en la cuenta de usuario de GitHub. Para más detalles sobre cómo bifurcar(fork) un repositorio ver esta guía.
Clona tu fork del repo de scikit-learn desde tu cuenta de GitHub a tu disco local:
git clone git@github.com:YourLogin/scikit-learn.git # add --depth 1 if your connection is slow cd scikit-learn
Instala las dependencias de desarrollo:
pip install cython pytest pytest-cov flake8 mypy
Instala scikit-learn en modo editable:
pip install --no-build-isolation --editable .
Si recibes errores en la construcción de scikit-learn, consulta la sección Compilando desde la fuente.
Añade el remoto
upstream
. Esto guarda una referencia al repositorio principal de scikit-learn, que puedes utilizar para mantener tu repositorio sincronizado con los últimos cambios:git remote add upstream https://github.com/scikit-learn/scikit-learn.git
Ahora deberías tener una instalación de scikit-learn que funcione, y tu repositorio git correctamente configurado. Los siguientes pasos describen el proceso de modificación del código y el envío de un PR:
Sincroniza tu rama principal con la rama principal ascendente(upstream):
git checkout main git pull upstream main
Crea una rama de funcionalidad(feature) para mantener tus cambios de desarrollo:
git checkout -b my_feature
y empieza a hacer cambios. Utiliza siempre una rama de funcionalidad. ¡Es una buena práctica no trabajar nunca en la rama
main
!(Opcional) Instala pre-commit para ejecutar comprobaciones de estilo de código antes de cada confirmación:
pip install pre-commit pre-commit install
Las comprobaciones pre-commit pueden desactivarse para un commit particular con
git commit -n
.Desarrolla la funcionalidad en tu rama de funcionalidad (feature) en tu computadora, utilizando Git para hacer el control de versiones. Cuando termines de editar, añade los archivos modificados utilizando
git add
y luegogit commit
:git add modified_files git commit
para registrar tus cambios en Git, y luego subir(push) los cambios a tu cuenta de GitHub con:
git push -u origin my_feature
Sigue estas instrucciones para crear un pull request desde tu fork. Esto enviará un correo electrónico a los confirmantes. Puedes considerar enviar un correo electrónico a la lista de correo para tener más visibilidad.
Nota
Si estás modificando un módulo de Cython, tienes que volver a compilar después de las modificaciones y antes de probarlas:
pip install --no-build-isolation -e .
Utiliza la opción --no-build-isolation
para evitar compilar todo el proyecto cada vez, sólo los archivos que has modificado.
A menudo es útil mantener su rama local de funcionalidad sincronizada con los últimos cambios del repositorio principal de scikit-learn:
git fetch upstream
git merge upstream/main
Posteriormente, es posible que tengas que resolver los conflictos. Puedes consultar la documentación de Git relacionada con la resolución de conflictos de fusión utilizando la línea de comandos.
Aprendiendo git:
La Documentación de Git y http://try.github.io son excelentes recursos para iniciarse en git, y entender todos los comandos que se muestran aquí.
Lista de comprobación de pull request¶
Antes de fusionar un PR, debe ser aprobado por dos desarrolladores centrales. Por favor, anteponga al título de su pull request el prefijo [MRG]
si la contribución está completa y debe ser sometida a una revisión detallada. Una contribución incompleta -en la que se espera hacer más trabajo antes de recibir una revisión completa- debe llevar el prefijo [WIP]
(para indicar que es un trabajo en curso) y cambiarlo por [MRG]
cuando madure. Los WIPs pueden ser útiles para: indicar que se está trabajando en algo para evitar la duplicación de trabajo, solicitar una revisión amplia de la funcionalidad o la API, o buscar colaboradores. Los WIPs suelen beneficiarse de la inclusión de una lista de tareas en la descripción del PR.
Para facilitar el proceso de revisión, recomendamos que tu contribución cumpla con las siguientes reglas antes de marcar un PR como [MRG]
. Las en negrita son especialmente importantes:
Ponle a tu pull request un título útil que resuma lo que hace tu contribución. Este título a menudo se convertirá en el mensaje de confirmación una vez fusionado, por lo que debe resumir tu contribución para la posteridad. En algunos casos, «Fix <ISSUE TITLE>» es suficiente. «Fix #<ISSUE NUMBER>» nunca es un buen título.
Asegúrate de que tu código pasa las pruebas. Se puede ejecutar toda la suite de pruebas con
pytest
, pero normalmente no se recomienda porque lleva mucho tiempo. A menudo es suficiente con ejecutar sólo las pruebas relacionadas con tus cambios: por ejemplo, si has cambiado algo ensklearn/linear_model/logistic.py
, ejecutar los siguientes comandos suele ser suficiente:pytest sklearn/linear_model/logistic.py
para asegurarte de que los ejemplos de doctest son correctospytest sklearn/linear_model/tests/test_logistic.py
para ejecutar las pruebas específicas del archivopytest sklearn/linear_model
para probar todo el módulolinear_model
pytest doc/modules/linear_model.rst
para asegurarte de que los ejemplos de la guía del usuario son correctos.pytest sklearn/tests/test_common.py -k LogisticRegression
para ejecutar todas las comprobaciones de nuestros estimadores (específicamente paraLogisticRegression
, si es el estimador que has cambiado).
Puede haber otras pruebas que fallen, pero serán capturadas por el CI, por lo que no es necesario ejecutar toda la suite de pruebas localmente. Para obtener directrices sobre cómo utilizar
pytest
de manera eficiente, consulta la Alias e indicadores útiles de pytest.Asegúrate de que tu código está correctamente comentado y documentado, y asegúrate de que la documentación se muestra correctamente. Para construir la documentación, por favor consulta nuestra guía Documentación. El CI también construirá la documentación: por favor, consulta Documentación generada sobre CircleCI.
Las pruebas son necesarias para que se acepten las mejoras. Las correcciones de errores o nuevas funcionalidades deben proporcionarse con las pruebas de no regresión. Estas pruebas verifican el comportamiento correcto de la corrección o funcionalidad. De esta manera, se otorgan modificaciones adicionales en el código base para que sean coherentes con el comportamiento deseado. En el caso de las correcciones de errores, en el momento del PR, las pruebas de no regresión deben fallar para el código base en la rama principal y pasar para el código PR.
Asegúrate de que tu PR no añade violaciones de PEP8. Para comprobar el código que has cambiado, puedes ejecutar el siguiente comando (ver above para configurar el remoto upstream):
git diff upstream/main -u -- "*.py" | flake8 --diff
o
make flake8-diff
que debería funcionar en sistemas tipo unix.Sigue las Directrices de codificación.
Cuando sea aplicable, utiliza las herramientas y scripts de validación del submódulo
sklearn.utils
. En la página Utilidades para Desarrolladores se puede encontrar una lista de rutinas de utilidad disponibles para los desarrolladores.A menudo los pull requests resuelven una o más incidencias (o pull requests). Si la fusión de tu pull request significa que algunas otras incidencias/PRs deben ser cerradas, debes utilizar palabras clave para crear un enlace a ellas (por ejemplo,
Fixes #1234
; se permiten múltiples incidencias/PRs siempre que cada una esté precedida por una palabra clave). Una vez fusionadas, esas incidencias/PRs serán cerradas automáticamente por GitHub. Si tu pull request está simplemente relacionada con otras incidencias/PRs, crea un enlace a ellas sin utilizar las palabras clave (por ejemplo,See also #1234
).Los PRs deben justificar a menudo el cambio, a través de pruebas de rendimiento y eficiencia (ver Monitorización del rendimiento) o a través de ejemplos de uso. Los ejemplos también ilustran las características y complejidades de la biblioteca a los usuarios. Echa un vistazo a otros ejemplos en el directorio examples/ como referencia. Los ejemplos deben demostrar por qué la nueva funcionalidad es útil en la práctica y, si es posible, compararla con otros métodos disponibles en scikit-learn.
A menudo, las nuevas funcionalidades deben ilustrarse con documentación narrativa en el manual de usuario, con pequeños fragmentos de código. Si es pertinente, añade también referencias en la literatura, con enlaces a PDF cuando sea posible.
El manual de usuario también debería incluir la complejidad temporal y espacial esperada del algoritmo y la escalabilidad, por ejemplo, «este algoritmo puede escalar a un gran número de muestras > 100000, pero no escala en dimensionalidad: se espera que n_features sea inferior a 100».
También puedes consultar nuestra Pautas para la revisión del código para hacerte una idea de lo que esperan los revisores.
Puedes comprobar los errores de programación más comunes con las siguientes herramientas:
Código con una buena cobertura de pruebas unitarias(unitest) (al menos el 80%, mejor el 100%), comprobar con:
pip install pytest pytest-cov pytest --cov sklearn path/to/tests_for_package
ver también Pruebas y mejora de la cobertura de las pruebas
Ejecuta el análisis estático con
mypy
:mypy sklearn
no debe producir nuevos errores en tu pull request. El uso de la anotación
# type: ignore
puede ser una solución para algunos casos que no son soportados por mypy, en particular,al importar módulos C o Cython
en propiedades con decoradores
Puntos extra para las contribuciones que incluyan un análisis de rendimiento con un script de pruebas de rendimiento y la salida de perfiles (ver Monitorización del rendimiento).
Consulta también la guía Cómo optimizar para velocidad para obtener más detalles sobre la creación de perfiles y las optimizaciones de Cython.
Nota
El estado actual de la base de código de scikit-learn no cumple con todas esas directrices, pero esperamos que la aplicación de esas restricciones en todas las nuevas contribuciones hará que la calidad general de la base de código vaya en la dirección correcta.
Nota
Para dos guías muy bien documentadas y más detalladas sobre el flujo de trabajo de desarrollo, por favor visita las secciones Flujo de trabajo de desarrollo de Scipy y Flujo de trabajo de Astropy para desarrolladores.
Integración continua (CI)¶
Los pipelines de Azure se utilizan para probar scikit-learn en Linux, Mac y Windows, con diferentes dependencias y configuraciones.
CircleCI se utiliza para construir los documentos para su visualización, para linting con flake8, y para las pruebas con PyPy en Linux
Ten en cuenta que si uno de los siguientes marcadores aparece en el último mensaje de confirmación, se toman las siguientes acciones.
Marcador de mensaje de confirmación
Medidas adoptadas por CI
[ci skip]
La CI se salta por completo
[cd build]
Se ejecuta el CD (se construyen los wheels y la distribución fuente)
[lint skip]
Azure pipeline se salta el linting
[scipy-dev]
Agrega una compilación de Travis con nuestras compilaciones de dependencias desarrollo (numpy, scipy, etc.)
[icc-build]
Añade una compilación Travis con el compilador Intel C (ICC)
[arm64]
Añade una compilación Travis para la arquitectura ARM64 / aarch64 little endian
[doc skip]
Los documentos no se compilan
[doc quick]
Se compilan los documentos, pero se excluyen los gráficos de la galería de ejemplo
[doc build]
Documentos compilados que incluyen gráficos de galería de ejemplo (muy largos)
Ten en cuenta que, por defecto, se construye la documentación, pero sólo se ejecutan los ejemplos que son modificados directamente por el pull request.
Pull requests estancados(stalled)¶
Como contribuir con una funcionalidad puede ser un proceso largo, algunos pull requests aparecen inactivos pero sin terminar. En tal caso, hacerse cargo de ellos es un gran servicio para el proyecto.
Una buena etiqueta para hacerse cargo es:
Determina si un PR está estancado
Un pull request puede tener la etiqueta «stalled» o «help wanted» si ya lo hemos identificado como candidato para otros colaboradores.
Para decidir si un PR inactivo está estancado, pregunta al colaborador si tiene previsto seguir trabajando en el PR en un futuro próximo. Si no se responde en un plazo de 2 semanas con una actividad que haga avanzar el PR, se sugiere que el PR está estancado y se etiquetará ese PR con «help wanted».
Ten en cuenta que si un PR ha recibido comentarios anteriores sobre la contribución que no han tenido respuesta en un mes, es seguro asumir que el PR está estancado y acortar el tiempo de espera a un día.
Después de un sprint, el seguimiento de los PRs no fusionados abiertos durante el sprint se comunicará a los participantes en el sprint, y esos PRs serán etiquetados como «sprint». Los PRs etiquetados con «sprint» pueden ser reasignados o declarados estancados por los líderes del sprint.
Toma el control de un PR estancado: Para tomar un PR, es importante comentar el PR estancado que se está tomando y enlazar desde el nuevo PR al antiguo. El nuevo PR debe crearse a partir del anterior.
Incidencias estancadas y no reclamadas¶
Por lo general, las incidencias(issues) que están disponibles tendrán una etiqueta de «help wanted». Sin embargo, no todas las incidencias que necesitan colaboradores tendrán esta etiqueta, ya que la etiqueta «help wanted» no siempre está actualizada con el estado de la incidencia. Los colaboradores pueden encontrar las incidencias que aún están disponibles siguiendo las siguientes directrices:
En primer lugar, determinar si se reclama una incidencia:
Comprueba los pull requests vinculados
Comprueba la conversación para ver si alguien ha dicho que está trabajando en la creación de un pull request
Si un colaborador comenta una incidencia para decir que está trabajando en ella, se espera un pull request en un plazo de 2 semanas (nuevo colaborador) o 4 semanas (colaborador o desarrollador central), a menos que se indique explícitamente un plazo mayor. Más allá de ese plazo, otro colaborador puede tomar la incidencia y hacer un pull request para ella. Animamos a los colaboradores a que comenten directamente la incidencia estancada o no reclamada para que los miembros de la comunidad sepan que van a trabajar en ella.
Si la incidencia está vinculada a una stalled pull request, recomendamos que los colaboradores sigan el procedimiento descrito en la sección Pull requests estancados(stalled) en lugar de trabajar directamente en la incidencia.
Incidencias para los nuevos colaboradores¶
Los nuevos colaboradores deben buscar las siguientes etiquetas cuando busquen incidencias. Recomendamos encarecidamente que los nuevos colaboradores se ocupen primero de las incidencias «fáciles»(«easy»): esto ayuda a que el colaborador se familiarice con el flujo de trabajo de las contribuciones, y a que los desarrolladores centrales se familiaricen con el colaborador; además, ¡a menudo subestimamos lo fácil que es resolver una incidencia!
etiqueta good first issue
Una gran manera de empezar a contribuir a scikit-learn es elegir un elemento de la lista de buenas primeras incidencias(good first issues) en el rastreador de incidencias. La resolución de estas incidencias te permite comenzar a contribuir al proyecto sin mucho conocimiento previo. Si ya has contribuido a scikit-learn, debes mirar las incidencias fáciles en su lugar.
Etiqueta easy
Si ya has contribuido a scikit-learn, otra gran manera de contribuir a scikit-learn es elegir un elemento de la lista de Incidencias fáciles en el rastreador de incidencias. Tu ayuda en esta área será muy apreciada por los desarrolladores más experimentados, ya que ayuda a liberar su tiempo para concentrarse en otras cuestiones.
Etiqueta help wanted
A menudo utilizamos la etiqueta help wanted(se necesita ayuda) para marcar incidencias independientemente de su dificultad. Además, utilizamos la etiqueta help wanted para marcar los Pull Requests que han sido abandonados por su colaborador original y están disponibles para que alguien las retome donde el colaborador original las dejó. La lista de incidencias con la etiqueta help wanted se puede encontrar aquí.
Ten en cuenta que no todas las incidencias que necesitan colaboradores tendrán esta etiqueta.
Documentación¶
Estamos encantados de aceptar cualquier tipo de documentación: cadenas de documentación de funciones, documentos reStructuredText (como éste), tutoriales, etc. Los documentos reStructuredText se encuentran en el repositorio de código fuente bajo el directorio doc/
.
Puedes editar la documentación usando cualquier editor de texto, y luego generar la salida HTML escribiendo make
desde el directorio doc/
. Alternativamente, se puede utilizar make html
para generar la documentación con la galería de ejemplos (lo que lleva bastante tiempo). Los archivos HTML resultantes se colocarán en build/html/stable
y se podrán ver en un navegador web.
Construyendo la documentación¶
En primer lugar, asegúrate de tener properly installed la versión de desarrollo.
La construcción de la documentación requiere la instalación de algunos paquetes adicionales:
pip install sphinx sphinx-gallery numpydoc matplotlib Pillow pandas \
scikit-image packaging seaborn sphinx-prompt
Para construir la documentación, es necesario estar en la carpeta doc
:
cd doc
En la gran mayoría de los casos, sólo es necesario generar el sitio web completo, sin la galería de ejemplos:
make
La documentación se generará en el directorio build/html/stable
. Para generar también la galería de ejemplos puedes utilizar:
make html
Esto ejecutará todos los ejemplos, lo que lleva algo de tiempo. Si sólo quieres generar unos pocos ejemplos, puedes utilizar:
EXAMPLES_PATTERN=your_regex_goes_here make html
Esto es especialmente útil si se modifican algunos ejemplos.
Establece la variable de entorno NO_MATHJAX=1
si pretendes ver la documentación en un entorno sin conexión.
Para construir el manual en PDF, ejecuta:
make latexpdf
Advertencia
Versión de Sphinx
Aunque hacemos todo lo posible para que la documentación se construya bajo tantas versiones de Sphinx como sea posible, las diferentes versiones tienden a comportarse de forma ligeramente diferente. Para obtener los mejores resultados, debes utilizar la misma versión que la que utilizamos en CircleCI. Mira esta búsqueda en github para conocer la versión exacta.
Pautas para la redacción de la documentación¶
Es importante mantener un buen compromiso entre los detalles matemáticos y los algorítmicos, y dar la intuición al lector sobre lo que hace el algoritmo.
Básicamente, para desarrollar lo anterior, lo mejor es empezar siempre con un pequeño párrafo con una explicación a mano de lo que el método hace con los datos. A continuación, es muy útil señalar por qué la característica es útil y cuándo debe utilizarse - esto último también incluye las complejidades «big O» (\(O\left(g\left(n\right)\right)\)) del algoritmo, en lugar de sólo reglas empíricas, ya que estas últimas pueden ser muy dependientes de la máquina. Si esas complejidades no están disponibles, entonces se pueden proporcionar reglas empíricas en su lugar.
En segundo lugar, debería incluirse una figura generada a partir de un ejemplo (como se menciona en el párrafo anterior) para proporcionar una mayor intuición.
A continuación, se pueden añadir uno o dos pequeños ejemplos de código para mostrar su uso.
Luego, se pueden añadir cualquier matemática y ecuaciones, seguidas de las referencias, para ampliar la documentación. El hecho de no empezar la documentación con las matemáticas hace que sea más fácil para los usuarios que sólo se interesan por lo que hace la función, en lugar de cómo funciona «bajo el capó».
Por último, sigue las reglas de formato que se indican a continuación para que sea consistente:
Añade «Ver también»(See Also) en las cadenas de documentación para las clases/funciones relacionadas.
Los «See Also» en las cadenas de documentación deben ser de una línea por referencia, con dos puntos y una explicación, por ejemplo:
See Also -------- SelectKBest : Select features based on the k highest scores. SelectFpr : Select features based on a false positive rate test.
A la hora de documentar los parámetros y atributos, he aquí una lista de algunos ejemplos bien formateados:
n_clusters : int, default=3 The number of clusters detected by the algorithm. some_param : {'hello', 'goodbye'}, bool or int, default=True The parameter description goes here, which can be either a string literal (either `hello` or `goodbye`), a bool, or an int. The default value is True. array_parameter : {array-like, sparse matrix} of shape (n_samples, n_features) or (n_samples,) This parameter accepts data in either of the mentioned forms, with one of the mentioned shapes. The default value is `np.ones(shape=(n_samples,))`. list_param : list of int typed_ndarray : ndarray of shape (n_samples,), dtype=np.int32 sample_weight : array-like of shape (n_samples,), default=None multioutput_array : ndarray of shape (n_samples, n_classes) or list of such arrays
En general, ten en cuenta lo siguiente:
Utiliza los tipos básicos de Python. (
bool
en lugar deboolean
)Utiliza paréntesis para definir las formas:
array-like de forma (n_samples,)
oarray-like de forma (n_samples, n_features)
Para cadenas con múltiples opciones, utiliza llaves:
input: {'log', 'squared', 'multinomial'}
Los datos 1D o 2D pueden ser un subconjunto de
{array-like, ndarray, sparse matrix, dataframe}
. Ten en cuenta quearray-like
también puede ser unalist
, mientras quendarray
es explícitamente sólo unnumpy.ndarray
.Especifica
dataframe
cuando se utilicen características «frame-like», como los nombres de las columnas.Cuando se especifica el tipo de datos de una lista, se utiliza
de
como delimitador:list de int
. Cuando el parámetro admite arreglos que dan detalles sobre la forma y/o el tipo de datos y una lista de dichos arreglos, puedes utilizar uno de los siguientes:array-like de forma (n_samples,) o lista de tales arreglos
.Al especificar el dtype de un ndarray, utiliza, por ejemplo,
dtype=np.int32
después de definir la forma:ndarray de forma (n_muestras,), dtype=np.int32
. Puedes especificar múltiples dtype como un conjunto:array-like de forma (n_muestras,), dtype={np.float64, np.float32}
. Si quieres mencionar una precisión arbitraria, tienes que utilizarintegral
yfloating
en lugar de los dtype de Pythonint
yfloat
. Cuando se soportan tantoint
comofloating
, no es necesario especificar el dtype.Cuando el valor predeterminado es
None
,None
sólo necesita ser especificado al final condefault=None
. Asegúrate de incluir en la cadena de documentación lo que significa que el parámetro o atributo seaNone
.
Para las reglas de formato no escritas, intenta seguir las buenas obras existentes:
Para «Referencias» en cadenas de documentación, ver el Coeficiente de Silueta (
sklearn.metrics.silhouette_score
).
Cuando edites archivos reStructuredText (
.rst
), intenta mantener la longitud de las líneas por debajo de los 80 caracteres siempre que sea posible (las excepciones son los enlaces y las tablas).No modifiques las etiquetas de sphinx ya que esto rompería las referencias cruzadas existentes y los enlaces externos que apuntan a secciones específicas en la documentación de scikit-learn.
Antes de enviar tu pull request comprueba si tus modificaciones han introducido nuevas advertencias de sphinx e intenta solucionarlas.
Documentación generada sobre CircleCI¶
Cuando cambias la documentación en un pull request, CircleCI la construye automáticamente. Para ver la documentación generada por CircleCI, simplemente dirígete al final de tu página de PR y busca el enlace «ci/circleci: doc artifact».
Pruebas y mejora de la cobertura de las pruebas¶
Las pruebas unitarias de alta calidad son la piedra angular del proceso de desarrollo de scikit-learn. Para ello, utilizamos el paquete pytest. Las pruebas son funciones con un nombre apropiado, ubicadas en los subdirectorios tests
, que comprueban la validez de los algoritmos y las diferentes opciones del código.
Al ejecutar pytest
en una carpeta se ejecutarán todas las pruebas de los subpaquetes correspondientes. Para un flujo de trabajo más detallado de pytest
, consulta la Lista de comprobación de pull request.
Esperamos que la cobertura del código de las nuevas funcionalidades sea de al menos un 90%.
Flujo de trabajo para mejorar la cobertura de las pruebas¶
Para probar la cobertura del código, es necesario instalar el paquete coverage además de pytest.
- Ejecuta “make test-coverage”. La salida lista para cada archivo los números de línea
números que no están probados.
- Encuentra tareas fáciles de hacer, mirando las líneas que no se han probado,
escribe o adapta una prueba específicamente para estas líneas.
Bucle.
Monitorización del rendimiento¶
Esta sección está muy inspirada en la documentación de Pandas.
Cuando se proponen cambios en la base de código existente, es importante asegurarse de que no introducen regresiones en el rendimiento. Scikit-learn utiliza Pruebas de rendimiento asv para controlar el rendimiento de una selección de estimadores y funciones comunes. La suite de pruebas de rendimiento (benchmarks) se puede encontrar en el directorio scikit-learn/asv_benchmarks
.
Para utilizar todas las características de asv, necesitarás conda
o virtualenv
. Para más detalles, consulta la página web de instalación de asv.
En primer lugar, es necesario instalar la versión de desarrollo de asv:
pip install git+https://github.com/airspeed-velocity/asv
y cambia tu directorio a asv_benchmarks/
:
cd asv_benchmarks/
La suite de pruebas de rendimiento está configurada para ejecutarse contra tu clon local de scikit-learn. Asegúrate de que está actualizado:
git fetch upstream
En la suite de pruebas de rendimiento, estas pruebas están organizadas siguiendo la misma estructura que scikit-learn. Por ejemplo, puedes comparar el rendimiento de un estimador específico entre upstream/main y la rama en la que estás trabajando:
asv continuous -b LogisticRegression upstream/main HEAD
El comando utiliza conda por defecto para crear los entornos de pruebas de rendimiento. Si quieres usar virtualenv en su lugar, utiliza la opción -E
:
asv continuous -E virtualenv -b LogisticRegression upstream/main HEAD
También puedes especificar un módulo completo para las pruebas de rendimiento:
asv continuous -b linear_model upstream/main HEAD
Puedes sustituir HEAD
por cualquier rama local. Por defecto, sólo informará de las pruebas de rendimiento que hayan cambiado al menos un 10%. Puedes controlar esta proporción con la opción`-f`.
Para ejecutar la suite completa de pruebas de rendimiento, basta con eliminar la opción -b
:
asv continuous upstream/main HEAD
Sin embargo, esto puede llevar hasta dos horas. La opción -b
también acepta una expresión regular para ejecutar un subconjunto más complejo de pruebas de rendimiento.
Para ejecutar las pruebas de rendimiento sin comparar con otra rama, utiliza el comando run
:
asv run -b linear_model HEAD^!
También puedes ejecutar la suite de pruebas de rendimiento utilizando la versión de scikit-learn ya instalada en tu entorno actual de Python:
asv run --python=same
Es particularmente útil cuando se instala scikit-learn en modo editable para evitar la creación de un nuevo entorno cada vez que se ejecutan las pruebas de rendimiento. Por defecto, los resultados no se guardan cuando se utiliza una instalación existente. Para guardar los resultados debes especificar un hash de confirmación:
asv run --python=same --set-commit-hash=<commit hash>
Las pruebas de rendimiento se guardan y organizan por máquina, entorno y confirmación(commit). Para ver la lista de todas las pruebas de rendimiento guardadas:
asv show
y para ver el informe de una ejecución específica:
asv show <commit hash>
Cuando ejecutes las pruebas de rendimiento para un pull request en el que estés trabajando, por favor, informa de los resultados en github.
La suite de pruebas de rendimiento soporta opciones configurables adicionales que pueden establecerse en el archivo de configuración benchmarks/config.json
. Por ejemplo, las pruebas de rendimiento pueden ejecutarse para una lista de valores proporcionada para el parámetro n_jobs
.
Más información sobre cómo escribir una prueba de rendimiento y cómo utilizar asv, puedes encontrarla en la documentación de asv.
Mantener la compatibilidad con versiones anteriores¶
Obsolescencia¶
Si cualquier método, función, atributo o parámetro de acceso público es renombrado, seguimos soportando el antiguo durante dos versiones y emitimos una advertencia de obsolescencia cuando es llamado/pasado/accesado. Por ejemplo, si la función zero_one
es renombrada a zero_one_loss
, añadimos el decorador deprecated
(de sklearn.utils
) a zero_one
y llamamos a zero_one_loss
desde esa función:
from ..utils import deprecated
def zero_one_loss(y_true, y_pred, normalize=True):
# actual implementation
pass
@deprecated("Function 'zero_one' was renamed to 'zero_one_loss' "
"in version 0.13 and will be removed in release 0.15. "
"Default behavior is changed from 'normalize=False' to "
"'normalize=True'")
def zero_one(y_true, y_pred, normalize=False):
return zero_one_loss(y_true, y_pred, normalize)
Si un atributo va a ser obsoleto, utiliza el decorador deprecated
en uno property. Ten en cuenta que el decorador property
debe colocarse antes del decorador deprecated
para que las cadenas de documentación se muestren correctamente. Por ejemplo, cambiar el nombre de un atributo labels_
a classes_
puede hacerse como:
@deprecated("Attribute labels_ was deprecated in version 0.13 and "
"will be removed in 0.15. Use 'classes_' instead")
@property
def labels_(self):
return self.classes_
Si un parámetro tiene que quedar obsoleto, una advertencia FutureWarning
debe ser levantada también. En el siguiente ejemplo, k está obsoleto y se ha renombrado a n_clusters:
import warnings
def example_function(n_clusters=8, k='deprecated'):
if k != 'deprecated':
warnings.warn("'k' was renamed to n_clusters in version 0.13 and "
"will be removed in 0.15.",
FutureWarning)
n_clusters = k
Cuando el cambio es en una clase, validamos y levantamos la advertencia en fit
:
import warnings
class ExampleEstimator(BaseEstimator):
def __init__(self, n_clusters=8, k='deprecated'):
self.n_clusters = n_clusters
self.k = k
def fit(self, X, y):
if self.k != 'deprecated':
warnings.warn("'k' was renamed to n_clusters in version 0.13 and "
"will be removed in 0.15.",
FutureWarning)
self._n_clusters = self.k
else:
self._n_clusters = self.n_clusters
Como en estos ejemplos, el mensaje de advertencia debería indicar siempre tanto la versión en la que se produjo la obsolescencia como la versión en la que se eliminará el antiguo comportamiento. Si la obsolescencia ocurrió en la versión 0.x-dev, el mensaje debería decir que la obsolescencia ocurrió en la versión 0.x y que la eliminación será en 0.(x+2), para que los usuarios tengan tiempo suficiente para adaptar su código al nuevo comportamiento. Por ejemplo, si la obsolescencia se produjo en la versión 0.18-dev, el mensaje debería decir que se produjo en la versión 0.18 y que el antiguo comportamiento se eliminará en la versión 0.20.
Además, debe añadirse una nota de obsolescencia en la cadena de documentación, recordando la misma información que la advertencia de obsolescencia explicada anteriormente. Utiliza la directiva .. deprecated::
:
.. deprecated:: 0.13
``k`` was renamed to ``n_clusters`` in version 0.13 and will be removed
in 0.15.
Además, una obsolescencia requiere una prueba que garantice que la advertencia se produzca en los casos pertinentes, pero no en los demás. La advertencia debe capturarse en todas las demás pruebas (utilizando, por ejemplo, @pytest.mark.filterwarnings
), y no debe haber ninguna advertencia en los ejemplos.
Cambia el valor predeterminado de un parámetro¶
Si es necesario cambiar el valor predeterminado de un parámetro, sustituye el valor por defecto por un valor específico (por ejemplo, warn
) y lanza FutureWarning
cuando los usuarios utilicen el valor predeterminado. En el siguiente ejemplo, cambiamos el valor predeterminado de n_clusters
de 5 a 10 (la versión actual es 0.20):
import warnings
def example_function(n_clusters='warn'):
if n_clusters == 'warn':
warnings.warn("The default value of n_clusters will change from "
"5 to 10 in 0.22.", FutureWarning)
n_clusters = 5
Cuando el cambio es en una clase, validamos y levantamos la advertencia en fit
:
import warnings
class ExampleEstimator:
def __init__(self, n_clusters='warn'):
self.n_clusters = n_clusters
def fit(self, X, y):
if self.n_clusters == 'warn':
warnings.warn("The default value of n_clusters will change from "
"5 to 10 in 0.22.", FutureWarning)
self._n_clusters = 5
Como en el caso de las obsolescencias, el mensaje de advertencia debe indicar siempre la versión en la que se ha producido el cambio y la versión en la que se eliminará el antiguo comportamiento. En consecuencia, la cadena de documentación debe actualizarse. Necesitamos una prueba para garantizar que la advertencia se produce en los casos pertinentes, pero no en otros casos. La advertencia debe ser capturada en todas las demás pruebas (usando, por ejemplo, @pytest.mark.filterwarnings
), y no debe haber ninguna advertencia en los ejemplos.
Pautas para la revisión del código¶
La revisión del código aportado al proyecto como PRs es un componente crucial del desarrollo de scikit-learn. Animamos a cualquiera a empezar a revisar el código de otros desarrolladores. El proceso de revisión de código es a menudo muy educativo para todos los involucrados. Esto es particularmente apropiado si se trata de una característica que te gustaría utilizar, y así puedes responder críticamente sobre si el PR satisface tus necesidades. Aunque cada pull request debe ser aprobado por dos desarrolladores principales, puedes acelerar este proceso aportando tus comentarios.
He aquí algunos aspectos importantes que deben cubrirse en cualquier revisión de código, desde preguntas de alto nivel hasta una lista de comprobación más detallada.
¿Lo queremos en la biblioteca? ¿Es probable que se utilice? ¿A ti, como usuario de scikit-learn, te gusta el cambio y tienes la intención de utilizarlo? ¿Está dentro del alcance de scikit-learn? ¿Valdrá la pena el coste de mantenimiento de una nueva característica?
¿Es el código coherente con la API de scikit-learn? ¿Las funciones/clases/parámetros públicos están bien nombrados y diseñados intuitivamente?
¿Están todas las funciones/clases públicas y sus parámetros, tipos de retorno y atributos almacenados nombrados de acuerdo con las convenciones de scikit-learn y documentados claramente?
¿Se describen las nuevas funcionalidades en el manual de usuario y se ilustran con ejemplos?
¿Se prueban todas las funciones/clases públicas? ¿Se prueba un conjunto razonable de parámetros, sus valores, tipos de valores y combinaciones? ¿Las pruebas validan que el código es correcto, es decir, que hace lo que dice la documentación? Si el cambio es una corrección de errores, ¿se incluye una prueba de no regresión? Mira esto para empezar con las pruebas en Python.
¿Pasan las pruebas en la compilación de integración continua? Si procede, ayuda al colaborador a entender por qué han fallado las pruebas.
¿Cubren las pruebas todas las líneas de código (ver el informe de cobertura en el registro de construcción)? Si no es así, ¿las líneas que no tienen cobertura son buenas excepciones?
¿Es el código fácil de leer y poco redundante? ¿Hay que mejorar los nombres de las variables para que sean más claros o coherentes? ¿Hay que añadir comentarios? ¿Hay que eliminar los comentarios por considerarlos inútiles o extraños?
¿Podría reescribirse fácilmente el código para que se ejecute de forma mucho más eficiente para los ajustes pertinentes?
¿Es el código compatible con versiones anteriores? (¿o es necesario un ciclo de obsolescencia?)
¿Añadirá el nuevo código alguna dependencia de otras bibliotecas? (es poco probable que se acepte)
¿La documentación se muestra correctamente (ver la sección Documentación para más detalles), y los gráficos son instructivos?
Respuestas estándar para la revisión incluye algunos comentarios frecuentes que pueden hacer los revisores.
Lectura del código base existente¶
Leer y digerir una base de código existente es siempre un ejercicio difícil que requiere tiempo y experiencia para dominarlo. Aunque intentemos escribir código sencillo en general, la comprensión del código puede parecer abrumadora al principio, dado el gran tamaño del proyecto. He aquí una lista de consejos que pueden ayudar a hacer esta tarea más fácil y rápida (sin ningún orden en particular).
Familiarízate con la APIs de objetos de scikit-learn: entiende para qué se utilizan fit, predict, transform, etc.
Antes de sumergirte en la lectura del código de una función/clase, revisa primero los documentos e intenta hacerte una idea de lo que hace cada parámetro/atributo. También puede ayudar el detenerse un minuto y pensar ¿Cómo haría esto yo mismo si tuviera que hacerlo?
Lo más complicado suele ser identificar qué partes del código son relevantes y cuáles no. En scikit-learn se realiza una gran cantidad de comprobaciones de entrada, especialmente al principio de los métodos fit. A veces, sólo una parte muy pequeña del código está haciendo el trabajo real. Por ejemplo, mirando el método
fit()
deLinearRegression
, lo que se está buscando podría ser sólo la llamada alscipy.linalg.lstsq
, pero está enterrado en múltiples líneas de comprobación de entrada y el manejo de diferentes tipos de parámetros.Debido al uso de la Herencia, algunos métodos pueden ser implementados en las clases padre. Todos los estimadores heredan al menos de
BaseEstimator
, y de una claseMixin
(por ejemplo,ClassifierMixin
) que permite un comportamiento por defecto dependiendo de la naturaleza del estimador (clasificador, regresor, transformador, etc.).A veces, la lectura de las pruebas de una función determinada te dará una idea de cuál es su propósito. Puedes utilizar
git grep
(ver más abajo) para encontrar todas las pruebas escritas para una función. La mayoría de las pruebas para una función/clase específica se encuentran en la carpetatests/
del móduloA menudo verás código con este aspecto
out = Parallel(...)(delayed(some_function)(param) for param in some_iterable)
. Esto ejecutasome_function
en paralelo usando Joblib.out
es entonces un iterable que contiene los valores devueltos porsome_function
para cada llamada.Utilizamos Cython para escribir código rápido. El código Cython se encuentra en los archivos
.pyx
y.pxd
. El código Cython tiene un sabor más parecido al de C: utilizamos punteros, realizamos asignaciones de memoria manuales, etc. Tener una mínima experiencia en C / C++ es prácticamente obligatorio aquí.Domina tus herramientas.
Con un proyecto tan grande, ser eficiente con tu editor o IDE favorito ayuda mucho a digerir el código base. Ser capaz de saltar rápidamente (o mirar) a la definición de una función/clase/atributo ayuda mucho. También lo es poder ver rápidamente dónde se utiliza un nombre determinado en un archivo.
git <https://git-scm.com/book/en>`_ también tiene algunas funcionalidades esenciales (killer) incorporadas. A menudo es útil entender cómo ha cambiado un archivo a lo largo del tiempo, utilizando por ejemplo, ``git blame
(manual). Esto también se puede hacer directamente en GitHub.git grep
(ejemplos) también es extremadamente útil para ver cada ocurrencia de un patrón (por ejemplo, una llamada a una función o una variable) en la base de código.