Cookiecutter Template für Data-Science-Projekte

Für meine Data-Science-Projekte nutze ich ein selbsterstelltes Cookiecutter-Template, welches ich hier vorstelle. Dieses ist auf GitHub zu finden. Hier ist die Ordnerstruktur des Templates zu sehen:

└───{{cookiecutter.long_name}}
    ├───.github
    │   └───workflows
    ├───.streamlit
    ├───data
    │   ├───processed
    │   └───raw
    ├───html
    ├───images
    │   ├───figures
    │   ├───headers
    │   └───test
    ├───notebooks
    │   └───parameters
    └───src
        └───{{cookiecutter.long_name}}

Das Ziel ist es, möglichst nahe an den gängigen Strukturen zu bleiben, damit das jeweilige Projekt besser nachvollziehbar ist. Die Ordner data, notebooks und src sind in so ziemlich jedem Template zu finden, was ich bei der Recherche gesehen habe.

Dotfiles (und andere Dateien im root-Verzeichnis)

Wichtig sind in diesem Template die sogenannten Dotfiles, also Konfigurationsdateien, die oft mit einem ».« beginnen und im root-Verzeichnis zu finden sind. In diesem Fall sind im root-Verzeichnis vorhanden:

.gitignore
.isort.cfg
.pre-commit-config.yaml
.pylintrc
jupytext.yml
LICENSE
makefile
README.md
requirements.txt
runtime.txt
streamlit_app.py

Über einige dieser Dateien werde ich noch ausführlichere Artikel schreiben, ich gebe im Folgenden nur Übersicht.

In jedem Projekt erstelle ich ein Paket, welches mit pip install -e /src/ installiert werden kann. Dafür ist bereits eine pyproject.toml-Datei angelegt. Dieses projekteigene Paket ist bereits in den Requirements vorhanden, so dass es mit den anderen Paketen mittels pip install -r requirements.txt installiert werden kann.

Für das automatische Sortieren von Imports ist das zugehörige Paket bereits als known_first_party in der .isort-config.yaml gelistet.

Ich teste meine Projekte mittels GitHub Actions bei jedem push zum GitHub-Repository. Hierfür habe ich drei Workflows definiert:

  1. black.yml definiert den Test auf den Programmierstil
  2. pylint.yml definiert das Linten mittels pylint
  3. tests.yml definiert das Ausführen aller Jupyter Notebooks mittels Papermill unter der Verwendung von Testparametern

Jupyter Notebooks weisen einige Besonderheiten auf, die beim Linten zu beachten sind. Zum Beispiel enthalten diese Dateien Markdown, so dass Leerzeichen am Zeilenende sinnvoll sind. Damit Pylint also nicht bei den für Notebook typischen Merkmalen auslöst, gibt es die .pylintrc.

Die runtime.txt ist für share.streamlit.io notwendig enthält lediglich die jeweils spezifizierte Python-Version.

In der Datei README.md sind bereits die Badges für die Tests sowie für binder und nbviewer vorhanden. Außerdem enthalten meine Projekte immer eine Tabelle mit den Notebooks.

Jupyter Notebooks harmonieren nicht gerade mit Versionskontrolle, daher nutze ich Jupytext, um sie in .py-Dateien umzuwandeln. Jupytext verwendet die  jupytext.yml, um zu wissen, welche Formate miteinander zu synchronisieren sind.

Die makefile enthält schließlich eine Reihe von Befehlen, die u. a. das Synchronisieren (mit Jupytext) und Testen vereinfachen.

Anwendung

Das Template kann wie alle anderen Templates verwendet werden. Man geht in das Verzeichnis, in dem das Projekt erstellt werden soll (es wird automatisch ein Unterverzeichnis erstellt) und gibt ein:

github clone https://github.com/Langhammer/ds_template_01.git
cookiecutter .\ds_template_01\ 

Ich erstelle für jedes Projekt eine Entwicklungsumgebung, in die alle Pakete installiert werden. Diese Umgebung nenne ich jeweils {{Kurzname}}_env (z. B. tsde_env für das Projekt train-stats-de). Das dabei automatisch erstellte Verzeichnis ist bereits in .gitignore enthalten.

python -m venv abbreviation_env 

Als nächstes initiiere ich das Repository und mache den ersten Commit.

git init
git add .
git commit -m "Initial commit"
git push

Kay Langhammer

Data Scientist

Kay Langhammer 2023