Ga naar hoofdinhoud

GitHub Actions en MakeFile: een hands-on introductie

Leer de generatie van datarapporten automatiseren met Makefile en GitHub Actions.
· 11 min lezen

Verken met AI

Als data scientists houden we ons meestal niet bezig met deployment en onderhoud—wij bouwen de statistische modellen, en engineers doen de rest.

Maar daar komt verandering in!

Omdat de vraag groeit naar data scientists die de kloof kunnen overbruggen tussen modelbouw en productie, kan vertrouwd raken met automatisering en CI/CD (Continuous Integration/Continuous Deployment) je een strategisch voordeel geven.

In deze tutorial kijken we naar twee populaire automationtools: Make (lokale automatisering) en GitHub Actions (cloudgebaseerde automatisering). We richten ons vooral op hoe je deze tools inzet in dataprojecten.

GitHub Actions en MakeFile tutorial omslag

GitHub Action en Make. Afbeelding door Abid Ali Awan.

Wil je meer leren over automatisering in de context van data science? Bekijk dan deze cursus over Fully Automated MLOps.

Introductie tot MakeFile

Een Makefile is een blauwdruk voor het bouwen en beheren van softwareprojecten. Het is een bestand met instructies voor het automatiseren van taken, het stroomlijnen van complexe buildprocessen en het borgen van consistentie.

Om de commando’s in de Makefile uit te voeren, gebruiken we de make-commandlinetool. Deze tool kun je aanroepen zoals een Python-programma door argumenten mee te geven of gewoon op zichzelf draaien.

Kernonderdelen

Een Makefile bestaat meestal uit een lijst met targets, dependencies, actions en variabelen:

  • Target: Dit zijn de gewenste uitkomsten, zoals "build", "test" of "clean". Zie het als doelen die je via de Makefile wilt bereiken.
  • Dependencies: Dit zijn de bestanden die nodig zijn om het target te bouwen. Zie ze als de ingrediënten voor elk recept (target).
  • Actions: Dit zijn de instructies of scripts die het systeem vertellen hoe het target te bouwen. Ze kunnen commando’s bevatten zoals python test.py.
  • Variabelen: Makefiles bieden globale variabelen die werken als argumenten voor de actions. In het voorbeeld hierboven zou je python test.py $variable_1 $variable_2 kunnen hebben.

Kort samengevat, zo kan een template van een MakeFile eruitzien:

Variable = some_value

Target: Dependencies
    Actions (commands to build the target) $Variable

Met onze voorbeelden van hierboven kan de MakeFile er zo uitzien:

# Define variables
variable_1 = 5
variable_2 = 10

# Target to run a test with variables
test: test_data.txt # Dependency on test data file
	python test.py $variable_1 $variable_2

De Make CLI-tool installeren

We kunnen de Make CLI-tool op alle besturingssystemen installeren.

Linux

Voor Linux gebruiken we het volgende commando in de terminal:

$ sudo apt install make

MacOS

Voor macOS kunnen we homebrew gebruiken om make te installeren:

$ brew install make

Windows

Windows werkt net even anders. De Make-tool kun je op meerdere manieren gebruiken. De populairste opties zijn WSL (Ubuntu Linxus), w64devkit en GnuWin32.

Laten we GnuWin32 downloaden en installeren via de SourceForge-pagina.

Om het als commandlinetool in de terminal te gebruiken, moeten we de maplocatie toevoegen aan de Windows-omgevingsvariabele. Dit zijn de stappen die we kunnen nemen:

  • Zoek naar "environment variables" in het startmenu—dit brengt ons naar het venster System Properties.
  • Klik in het venster System Properties op de knop Environment Variables.
  • Zoek in het systeemvariabele-gedeelte de variabele "Path" en bewerk deze—er opent een nieuw venster waar we het nieuwe pad naar de Make-toolmap kunnen toevoegen.

Omgevingsvariabele instellen in Windows

Om te testen of Make succesvol is geïnstalleerd, kunnen we make -h typen in PowerShell.

Make CLI-tool in Windows PowerShell

MakeFile gebruiken voor een data­scienceproject

In deze sectie leren we hoe je Makefile en de Make CLI-tools gebruikt in een data­scienceproject.

We gebruiken de dataset World Happiness Report 2023 om data­verwerking, analyse en het opslaan van datasamenvattingen en visualisaties te behandelen.

Opzetten

We beginnen met naar de projectmap gaan en een map Makefile-Action aan te maken. Vervolgens maken we daarin het bestand data_processing.py en starten we de VSCode-editor.

$ cd GitHub
$ mkdir Makefile-Action
$ cd .\Makefile-Action\
$ code data_processing.py

Dataverwerking

We beginnen met het verwerken van onze data in Python. In het onderstaande codeblok doen we het volgende (let op: dit is voorbeeldcode—in een echte situatie zouden we waarschijnlijk meer stappen moeten uitvoeren):

  1. Laad de ruwe dataset vanaf de locatie die door de gebruiker is opgegeven.
  2. Hernoem alle kolommen voor betere leesbaarheid.
  3. Vul de missende waarden aan.
  4. Sla de opgeschoonde dataset op.

Bestand: data_processing.py

import sys
import pandas as pd

# Check if the data location argument is provided
if len(sys.argv) != 2:
    print("Usage: python data_processing.py <data_location>")
    sys.exit(1)

# Load the raw dataset (step 1)
df = pd.read_csv(sys.argv[1])

# Rename columns to more descriptive names (step 2)
df.columns = [
    "Country",
    "Happiness Score",
    "Happiness Score Error",
    "Upper Whisker",
    "Lower Whisker",
    "GDP per Capita",
    "Social Support",
    "Healthy Life Expectancy",
    "Freedom to Make Life Choices",
    "Generosity",
    "Perceptions of Corruption",
    "Dystopia Happiness Score",
    "GDP per Capita",
    "Social Support",
    "Healthy Life Expectancy",
    "Freedom to Make Life Choices",
    "Generosity",
    "Perceptions of Corruption",
    "Dystopia Residual",
]

# Handle missing values by replacing them with the mean (step 3)
df.fillna(df.mean(numeric_only=True), inplace=True)

# Check for missing values after cleaning
print("Missing values after cleaning:")
print(df.isnull().sum())

print(df.head())

# Save the cleaned and normalized dataset to a new CSV file (step 4)
df.to_csv("processed_data\WHR2023_cleaned.csv", index=False)

Data-analyse

Nu gaan we verder met het analyseren van de data en slaan we alle code op in een bestand met de naam data_analysis.py. Dit bestand kun je aanmaken met het volgende terminalcommando:

$ code data_analysis.py

We kunnen ook het echo-commando gebruiken om het Python-bestand te maken en het in een andere code-editor te openen.

$ echo "" > data_analysis.py

In het onderstaande codeblok doen we het volgende:

  1. Laad de schone dataset met de input van de gebruiker.
  2. Genereer de data­samenvatting, de datainfo en de eerste 5 rijen van de DataFrame en sla dit op in het TXT-bestand.
  3. Maak visualisaties voor:
    • De verdeling van happiness-scores
    • Top 20 landen op basis van happiness-score
    • Happiness-score versus bbp per capita
    • Happiness-score versus sociale steun
    • Een correlatie-heatmap
  4. Sla alle visualisaties op in de map “figures”.

Bestand: data_analysis.py

import io
import sys

import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

# Check if the data location argument is provided
if len(sys.argv) != 2:
    print("Usage: python data_analysis.py <data_location>")
    sys.exit(1)

# Load the clean dataset (step 1)
df = pd.read_csv(sys.argv[1])

# Data summary (step 2)
print("Data Summary:")
summary = df.describe()
data_head = df.head()
print(summary)
print(data_head)

# Collecting data information
buffer = io.StringIO()
df.info(buf=buffer)
info = buffer.getvalue()

## Write metrics to file
with open("processed_data/summary.txt", "w") as outfile:
    f"\n## Data Summary\n\n{summary}\n\n## Data Info\n\n{info}\n\n## Dataframe\n\n{data_head}"

print("Data summary saved in processed_data folder!")

# Distribution of Happiness Score (step 3)
plt.figure(figsize=(10, 6))
sns.displot(df["Happiness Score"])
plt.title("Distribution of Happiness Score")
plt.xlabel("Happiness Score")
plt.ylabel("Frequency")
plt.savefig("figures/happiness_score_distribution.png")

# Top 20 countries by Happiness Score
top_20_countries = df.nlargest(20, "Happiness Score")
plt.figure(figsize=(10, 6))
sns.barplot(x="Country", y="Happiness Score", data=top_20_countries)
plt.title("Top 20 Countries by Happiness Score")
plt.xlabel("Country")
plt.ylabel("Happiness Score")
plt.xticks(rotation=90)
plt.savefig("figures/top_20_countries_by_happiness_score.png")

# Scatter plot of Happiness Score vs GDP per Capita
plt.figure(figsize=(10, 6))
sns.scatterplot(x="GDP per Capita", y="Happiness Score", data=df)
plt.title("Happiness Score vs GDP per Capita")
plt.xlabel("GDP per Capita")
plt.ylabel("Happiness Score")
plt.savefig("figures/happiness_score_vs_gdp_per_capita.png")

# Visualize the relationship between Happiness Score and Social Support
plt.figure(figsize=(10, 6))
plt.scatter(x="Social Support", y="Happiness Score", data=df)
plt.xlabel("Social Support")
plt.ylabel("Happiness Score")
plt.title("Relationship between Social Support and Happiness Score")
plt.savefig("figures/social_support_happiness_relationship.png")

# Heatmap of correlations between variables
corr_matrix = df.drop("Country", axis=1).corr()
plt.figure(figsize=(12, 10))
sns.heatmap(corr_matrix, annot=True, cmap="coolwarm", square=True)
plt.title("Correlation Heatmap")
plt.savefig("figures/correlation_heatmap.png")
print("Visualizations saved to figures folder!")

Makefile maken

Voordat we een Makefile maken, moeten we een requirements.txt-bestand opzetten om alle vereiste Python-packages op een nieuwe machine te installeren. Zo ziet het requirements.txt-bestand eruit:

pandas
numpy
seaborn
matplotlib
black

Onze Makefile bestaat uit variabelen, dependencies, targets en actions—we lopen alle bouwstenen langs. We maken een bestand met de naam Makefile en voegen acties toe voor de targets:

  • install: Dit werkt de pip-versie bij en installeert alle benodigde Python-packages met requirements.txt.
  • format: Dit formatteert alle Python-bestanden met de tool Black.
  • process: Dit draait het Python-bestand `data_processing.py` met een pad naar ruwe data als variabele en dependency.
  • analyze: Dit draait het Python-bestand `data_analysis.py` met een pad naar verwerkte data als variabele en dependency.
  • clean: Dit verwijdert alle bestanden en figuren die zijn gegenereerd tijdens het draaien van de Python-bestanden.
  • all: Dit draait alle geldige targets achter elkaar.

Bestand: Makefile

RAW_DATA_PATH = "raw_data/WHR2023.csv"
PROCESSED_DATA = "processed_data/WHR2023_cleaned.csv"

install:
    pip install --upgrade pip &&\
        pip install -r requirements.txt

format:
        black *.py --line-length 88

process: ./raw_data/WHR2023.csv
        python data_processing.py $(RAW_DATA_PATH)

analyze: ./processed_data/WHR2023_cleaned.csv
        python data_analysis.py $(PROCESSED_DATA)

clean:
        rm -f processed_data/* **/*.png

all: install format process analyze

Om het target uit te voeren, gebruiken we de tool make en geven we de targetnaam op in de terminal.

$ make format

De Black-script is succesvol uitgevoerd.

make-commando uitvoeren in terminal

Laten we het Python-script voor dataverwerking proberen te draaien.

Belangrijk om te weten: het controleert de targetdependencies voordat het process-target wordt uitgevoerd. In ons geval checkt het of het ruwe databestand bestaat. Zo niet, dan start het commando niet.

$ make process

Zo simpel is het dus.

make-commando uitvoeren

Je kunt zelfs de bestaande variabele overschrijven door een extra argument mee te geven aan het make-commando.

In ons geval hebben we het pad naar de ruwe data gewijzigd.

$ make process RAW_DATA_PATH="WHR2022.csv"

Het Python-script draaide met het andere invoerargument.

make-commando uitvoeren met invoerargument

Om de hele workflow te automatiseren, gebruiken we all als target, waarmee de targets install, format, process en analyze één voor één worden uitgevoerd.

$ make all

Het make-commando installeerde de Python-packages, formatteerde de code, verwerkte de data en sloeg de samenvatting en visualisaties op.

terminaluitvoer

datavisualisatie op World Happiness-dataset 2023

Zo zou je projectmap eruit moeten zien na het draaien van het commando make all:

Projectbestanden en -mappen

Introductie tot GitHub Actions

Hoewel Make uitblinkt in lokale automatisering binnen onze ontwikkelomgeving, biedt GitHub Actions een cloudgebaseerd alternatief.

GitHub Actions wordt doorgaans gebruikt voor CI/CD, waarmee ontwikkelaars de applicatie direct vanuit GitHub kunnen compileren, bouwen, testen en naar productie deployen.

We kunnen bijvoorbeeld een custom workflow maken die wordt getriggerd door specifieke events zoals push of pull requests. Die workflow draait shellscripts en Pythonscripts, of we kunnen zelfs kant-en-klare actions gebruiken. De custom workflow is een YML-bestand, en het is meestal vrij eenvoudig te begrijpen en eigen runs en actions te schrijven.

Kernonderdelen

Laten we de kernonderdelen van GitHub Actions verkennen:

  • Workflows worden gedefinieerd met YML-bestanden, die de stappen specificeren en de voorwaarden waaronder ze moeten worden uitgevoerd.
  • Events zijn specifieke activiteiten die een workflowrun triggeren, zoals push, pull_request, schedule en meer.
  • Runners zijn machines die de workflows draaien wanneer ze getriggerd worden. GitHub biedt gehoste, gratis runners voor Linux, Windows en macOS.
  • Jobs zijn een set stappen die op dezelfde runner worden uitgevoerd. Standaard draaien jobs parallel maar je kunt ze sequentieel laten lopen.
  • Steps zijn taken die commando’s of actions draaien, vergelijkbaar met Makefile-actions.
  • Actions zijn custom applicaties voor het GitHub Actions-platform die een complexe maar vaak herhaalde taak uitvoeren. Er zijn veel actions om uit te kiezen, waarvan de meeste door de open­sourcecommunity worden ondersteund.

Aan de slag met GitHub Actions

In deze sectie leren we GitHub Actions gebruiken en proberen we de commando’s te repliceren die we eerder in de Makefile gebruikten.

Om onze code naar GitHub over te zetten, moeten we onze projectmap omzetten naar een Git-repository met:

$ git init

Daarna maken we een nieuwe repository op GitHub en kopiëren we de URL.

Een nieuwe GitHub-repository aanmaken

In de terminal typen we de onderstaande commando’s om:

  1. De link naar de remote repository toe te voegen.
  2. De bestanden van de remote repository te pullen.
  3. Alle bestanden toe te voegen en te committen met een commitboodschap.
  4. Het bestand van de lokale master naar de remote main-branch te pushen.
$ git remote add github https://github.com/kingabzpro/Makefile-Actions.git
$ git pull github main
$ git add . 
$ git commit -m "adding all the files"
$ git push github master:main

Terzijde: heb je een korte opfrisser nodig over GitHub of Git? Bekijk deze beginnersvriendelijke tutorial over GitHub en Git. Hiermee kun je je data­scienceproject versiebeheer geven en het met het team delen via de Git CLI-tool.

We gaan verder—we zien dat alle bestanden succesvol zijn overgezet naar de remote repository.

Bestanden pushen naar remote repository

Vervolgens maken we een GitHub Action-workflow. Ga eerst naar het tabblad Actions op onze repository kingabzpro/Makefile-Actions. Klik daarna op de blauwe tekst “set up a workflow yourself.”

aan de slag met GitHub Actions

We worden doorgestuurd naar het YML-bestand, waar we alle code schrijven om de omgeving in te richten en de commando’s uit te voeren. We zullen:

  1. De naam van de workflow opgeven.
  2. De triggerevents instellen om de workflow uit te voeren wanneer code naar de main-branch wordt gepusht of er een pull request is op de main-branch.
  3. Een job instellen met de nieuwste Ubuntu Linux-machine.
  4. De checkout v3-action gebruiken in de step-sectie. Dit helpt onze workflow toegang te krijgen tot repositories.
  5. De benodigde Python-packages installeren, de code formatteren en beide Pythonscripts met variabelen draaien.
name: Data Processing and Analysis

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install Packages
        run: |
          pip install --upgrade pip
          pip install -r requirements.txt
      - name: Format
        run: black *.py --line-length 88
      - name: Data Processing
        env:
          RAW_DATA_DIR: "./raw_data/WHR2023.csv"
        run: python data_processing.py $RAW_DATA_DIR
      - name: Data Analysis
        env:
          CLEAN_DATA_DIR: "./processed_data/WHR2023_cleaned.csv"
        run: python data_analysis.py $CLEAN_DATA_DIR

Na het committen van het workflowbestand met de boodschap start de workflow automatisch.

de workflow draaien

Het duurt minstens 20 seconden om alle stappen af te ronden.

Om de logs te bekijken, klikken we eerst op de workflowrun, vervolgens op de knop Build en daarna op elke job om de logs te openen.

Build-logs van GitHub Actions

Vond je dit leuk? Dan vind je vast ook deze Beginner's Guide to CI/CD for Machine Learning interessant, die de basis behandelt van het bouwen en automatiseren van een machinelearning­workflow.

GitHub Actions combineren met MakeFile

Om GitHub Action-workflows te vereenvoudigen en te standaardiseren, gebruiken developers Make-commando’s binnen het workflowbestand. In deze sectie leren we onze workflowcode te vereenvoudigen met het Make-commando en maken we kennis met de Continuous Machine Learning (CML)-action.

Voordat we beginnen, moeten we het workflowbestand van de remote repository pullen.

$ git pull

CML gebruiken

Continuous Machine Learning (CML) is een open­sourcelibrary van iterative.ai waarmee we continuous integration in ons data­scienceproject kunnen implementeren.

In dit project gebruiken we de GitHub Action iterative/setup-cml die CML-functies in de workflow gebruikt om het analysereport te genereren met figuren en datastatistieken.

Het rapport wordt aangemaakt en gekoppeld aan onze GitHub-commit, zodat ons team het kan bekijken en goedkeuren voordat we mergen.

We passen de Makefile aan en voegen een extra target “summary” toe. Let op:

  • Het target is een meerregelig script dat de tekstdata uit summary.txt naar report.md overzet.
  • Vervolgens voegt het één voor één de koppen voor elke figuur toe en Markdown-code om de figuur in het bestand report.md te tonen.
  • Tot slot gebruiken we de tool cml om een data­analytisch rapport te maken en dit te tonen onder de commitcomments.

Stel je voor dat je al die regels aan het GitHub-workflowbestand toevoegt—dat zou lastig lezen en aanpassen zijn. In plaats daarvan gebruiken we make summary.

Bestand: Makefile

summary: ./processed_data/summary.txt
    echo "# Data Summary" > report.md
    cat ./processed_data/summary.txt >> report.md
   
    echo '\n# Data Analysis' >> report.md
    echo '\n## Correlation Heatmap' >> report.md
    echo '![Correlation Heatmap](./figures/correlation_heatmap.png)' >> report.md

    echo '\n## Happiness Score Distribution' >> report.md
    echo '![Happiness Score Distribution](./figures/happiness_score_distribution.png)' >> report.md

    echo '\n## Happiness Score vs GDP per Capita' >> report.md
    echo '![Happiness Score vs GDP per Capita](./figures/happiness_score_vs_gdp_per_capita.png)' >> report.md
   
    echo '\n## Social Support vs Happiness Relationship' >> report.md
    echo '![Social Support Happiness Relationship](./figures/social_support_happiness_relationship.png)' >> report.md
   
    echo '\n## Top 20 Countries by Happiness Score' >> report.md
    echo '![Top 20 Countries by Happiness Score](./figures/top_20_countries_by_happiness_score.png)' >> report.md
   
    cml comment create report.md

Het workflowbestand bewerken met het make-commando.

Het GiHub Action-bestand aanpassen

We bewerken nu ons main.yml-bestand, dat we vinden in de map .github/workflows.

We vervangen alle commando’s en Pythonscripts door het make-commando en geven permissie aan de CML Action om het datarapport te maken in de commitcomment. Zorg er bovendien voor dat we de Action iterative/setup-cml@v3 aan onze run toevoegen.

name: Data Processing and Analysis

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

permissions: write-all

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: iterative/setup-cml@v3
      - name: Install Packages
        run: make install
      - name: Format
        run: make format
      - name: Data Processing
        env:
          RAW_DATA_DIR: "./raw_data/WHR2023.csv"
        run: make process RAW_DATA_PATH=$RAW_DATA_DIR
      - name: Data Analysis
        env:
          CLEAN_DATA_DIR: "./processed_data/WHR2023_cleaned.csv"
        run: make analyze PROCESSED_DATA=$CLEAN_DATA_DIR
      - name: Data Summary
        env:
          REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: make summary

De workflow draaien

Om de workflow uit te voeren, hoeven we alleen alle wijzigingen te committen en te synchroniseren met de remote main-branch.

$ git commit -am "makefile and github action combo"
$ git push github master:main

GitHub Action-workflow draaien

Het duurde 32 seconden om de workflow te draaien—ons rapport is klaar voor review. Ga naar de build-samenvatting, scroll omlaag en klik op het tabblad Data Summary, en klik vervolgens op de commentlink (de link die je op regel 20 in de afbeelding hieronder ziet):

workflow succesvol afgerond

Zoals je ziet zijn de datasamenvatting en datavisualisaties aan onze commit toegevoegd.

Geautomatiseerd analytisch rapport gegenereerd met GitHub Actions "CML".

Het project is beschikbaar op kingabzpro/Makefile-Actions, en je kunt het gebruiken als leidraad als je vastloopt. De repository is openbaar, dus fork ’m en ervaar zelf de magie!

Wil je een GitHub-certificering behalen? Bekijk dan onze uitgebreide gids over de verschillende GitHub-certificeringen!

Conclusie

In deze tutorial hebben we ons gericht op Makefile en GitHub Actions voor het automatiseren van het genereren van data­analytische rapporten.

We leerden ook hoe je de workflow bouwt en draait en de Make-tool binnen de GitHub-workflow gebruikt om het automatiseringsproces te optimaliseren en te vereenvoudigen. In plaats van meerdere regels code te schrijven, kunnen we make summary gebruiken om een data­analyserapport te genereren dat aan onze commit wordt gekoppeld.

Wil je de kunst van CI/CD voor data science onder de knie krijgen? Probeer dan deze cursus over CI/CD for Machine Learning. Die behandelt de basis van CI/CD, GitHub Actions, dataversiebeheer en het automatiseren van model-hyperparameteroptimalisatie en evaluatie.

Abid Ali Awan

Auteur

Abid Ali Awan

Als gecertificeerd data scientist haal ik met passie het maximale uit de nieuwste technologie om innovatieve machinelearning-toepassingen te bouwen. Met een sterke achtergrond in spraakherkenning, data-analyse en -rapportage, MLOps, conversationele AI en NLP heb ik mijn vaardigheden aangescherpt in het ontwikkelen van intelligente systemen die echt impact maken. Naast mijn technische expertise ben ik ook een sterke communicator met een talent om complexe concepten terug te brengen tot heldere, beknopte taal. Daardoor ben ik uitgegroeid tot een veelgelezen blogger over data science, waar ik mijn inzichten en ervaringen deel met een groeiende community van data-professionals. Op dit moment richt ik me op contentcreatie en redactie, waarbij ik met large language models werk aan krachtige en aansprekende content die zowel bedrijven als individuen helpt het beste uit hun data te halen.

Onderwerpen

Gerelateerd