Data Science & Machine Learning Engineering auf Linux
Erstellt: 05.11.2026 · Zuletzt aktualisiert: 06.11.2026 · Nejat Hakan
Modernes Data Science und Machine Learning Engineering finden nicht in isolierten Tabellenkalkulationen statt – sie laufen auf Linux. Von der Vorverarbeitung gigantischer Log-Streams auf der CLI und GPU-beschleunigtem Training tiefer neuronaler Netze bis hin zu verteilten Apache Spark-Clustern und containerisierten Inference-APIs: Linux ist das native Betriebssystem des weltweiten KI-Ökosystems.
Dieser Leitfaden schlägt die Brücke zwischen klassischem Linux-Systems-Engineering und angewandter Data Science: von reproduzierbaren Python-Umgebungen (uv & venv) über POSIX-Kommandozeilen-Datenanalysen und explorative Visualisierung bis hin zu leckfreien Scikit-learn-Pipelines, Deep Learning, PySpark, MLflow und Microservice-Deployments mit FastAPI.
1. Warum Linux Data Science & MLOps dominiert
Die Modellentwicklung direkt in derselben Betriebssystemumgebung durchzuführen, in der Modelle später produktiv laufen, verhindert Reibungsverluste zwischen Experiment und Live-Betrieb:
%%{init: {'flowchart': {'wrappingWidth': 600, 'subGraphTitleMargin': {'top': 15, 'bottom': 15}}}}%%
flowchart TB
subgraph Ingest ["1️⃣ Ingestion & CLI-Wrangling"]
Raw[("🗄️ Roh-Logs, APIs & SQL")] --> CLI["🐧 POSIX-Stream-Tools<br/>(curl, awk, grep, sed, jq)"]
end
subgraph Explore ["2️⃣ Exploration & Feature-Eng."]
CLI --> DF["🐼 Pandas 2 / Polars<br/>Vektorisierte DataFrames"]
DF --> Viz["📊 Matplotlib & Seaborn<br/>Statistische EDA"]
end
subgraph Train ["3️⃣ Modellierung & Tracking"]
Viz --> Pipe["⚙️ Scikit-learn / PyTorch<br/>Leckfreie ML-Pipelines"]
Pipe --> MLF["📈 MLflow Registry<br/>Metriken, Params & Artefakte"]
end
subgraph Serve ["4️⃣ Produktions-Serving"]
MLF ==> API["🚀 FastAPI + Uvicorn<br/>Containerisierte Inference-API"]
end
Vier zentrale Gründe für Linux in Data Science
-
Stream-Verarbeitung in Hochgeschwindigkeit
Bevor eine 20 GB CSV-Datei in den RAM geladen wird, filtern, zerlegen und aggregieren POSIX-Tools (
awk,sed,grep,cut,sort,jq) Millionen von Zeilen in Sekunden mit minimalem Speicherverbrauch. -
Native GPU- & CUDA-Beschleunigung
Erstklassige Kernel-Treiber für NVIDIA CUDA / cuDNN und AMD ROCm für maximalen Tensor-Durchsatz in PyTorch, TensorFlow und lokalen LLMs ohne Virtualisierungs-Overhead.
-
Isolierte, reproduzierbare Toolchains
Nahtlose Integration schneller Umgebungsmanager (
uv,venv,conda) mit System-Compilern (gcc,gfortran,openblas) und rootless Podman / Docker-Containern. -
100 % Produktionsparität
Über 95 % aller Cloud-ML-Instanzen, Kubernetes-Cluster und Apache-Spark-Knoten laufen unter Linux. Lokale Entwicklung unter Linux garantiert absolute Kompatibilität mit dem Produktivsystem.
2. Einrichtung einer High-Performance Data-Science-Umgebung
Schritt 1: Build-Tools & Systembibliotheken installieren
Zahlreiche rechenintensive Python-Bibliotheken (numpy, scipy, scikit-learn, psycopg2) binden kompilierte C-, C++- und Fortran-Bibliotheken ein (OpenBLAS, LAPACK). Installiere vorab die Basispakete:
Schritt 2: Isolierte Python-Umgebung erstellen (uv vs. venv)
Goldene Regel: Niemals sudo pip install ausführen!
Moderne Linux-Distributionen erzwingen PEP 668 (externally-managed-environment), um Systemtools (apt, unattended-upgrades) vor inkompatiblen Abhängigkeiten zu schützen. Arbeite immer in einer virtuellen Umgebung!
uv (von Astral) ist die moderne, extrem schnelle Alternative zu pip und venv. Es löst Abhängigkeiten blitzschnell auf:
# 1. uv installieren (falls noch nicht vorhanden)
curl -LsSf https://astral.sh/uv/install.sh | sh
# 2. Projektverzeichnis und virtuelle Umgebung anlegen
mkdir -p ~/ds-workspace && cd ~/ds-workspace
uv venv .venv
source .venv/bin/activate
# 3. Den Data-Science-Stack in Sekundenschnelle installieren
uv pip install numpy pandas matplotlib seaborn scikit-learn jupyterlab mlflow fastapi uvicorn joblib
Nativ in jeder Standard-Python-3-Installation ohne Zusatzwerkzeuge enthalten:
Das Python Data-Science-Ökosystem im Überblick
| Bibliothek | Primäre Aufgabe | Zentrale Datenstruktur |
|---|---|---|
| NumPy | Vektorisierte Numerik & Lineare Algebra in C | ndarray (Mehrdimensionales zusammenhängendes Array) |
| Pandas 2.x | Tabellarische Datenanalyse, Zeitreihen & Joins | DataFrame & Series (NumPy / PyArrow Backend) |
| 📊 Matplotlib & Seaborn | Publikationsreife 2D-Plots & statistische Visualisierung | Figure, Axes & deklarative Diagramme |
| Scikit-learn | Klassisches Machine Learning, Preprocessing & Evaluation | Estimator (.fit()), Transformer (.transform()), Pipeline |
| PyTorch / Keras | Deep Learning, neuronale Netze & GPU-Autograd | torch.Tensor, nn.Module, keras.Sequential |
| MLflow | Experiment-Tracking, Hyperparameter-Logging & Model Registry | Runs, Metrics, Parameters & Model Artifacts |
JupyterLab auf einem Headless-Linux-Server via SSH-Tunnel betreiben
Wenn JupyterLab auf einem Remote-Server läuft, exponiere Port 8888 niemals direkt ins Internet! Binde JupyterLab an 127.0.0.1 und tunnel den Port sicher via SSH:
# 1. Auf dem Remote-Server (in aktivierter .venv):
jupyter lab --no-browser --ip=127.0.0.1 --port=8888
# 2. Auf dem lokalen Rechner: Port 8888 via SSH weiterleiten
ssh -N -L 8888:127.0.0.1:8888 nejathakan
http://localhost:8888 im Browser deines Laptops!
3. Daten-Inspektion direkt auf der Kommandozeile
Erfahrene Data Scientists untersuchen und bereinigen Rohdaten vorab direkt in der Linux-Shell, bevor sie Python starten:
%%{init: {'flowchart': {'wrappingWidth': 600}}}%%
flowchart TB
Download["🌐 curl / wget<br/>CSV oder JSON-API laden"] ==> Inspect["🔍 file / head / wc -l<br/>Encoding & Zeilenanzahl prüfen"]
Inspect ==> Filter["✂️ grep / cut / sed<br/>Filtern & Delimiter bereinigen"]
Filter ==> Aggregate["⚡ awk / sort / uniq -c<br/>Gruppieren & Aggregieren"]
Der POSIX-CLI-Spickzettel für Data Scientists
| Aufgabe | Befehl | Vorteil gegenüber Python |
|---|---|---|
| Zeilen sofort zählen | wc -l dataset.csv |
Zählt 50 Mio. Zeilen in ~1 Sekunde ohne RAM-Bedarf. |
| Header & Stichprobe ansehen | head -n 5 dataset.csv && tail -n 5 dataset.csv |
Zeigt Trennzeichen, fehlende Kopfzeilen und Leerzeilen sofort. |
| Encoding & Nullwerte prüfen | file -i dataset.csv und grep -c ",," dataset.csv |
Erkennt UTF-8/ISO-8859-Konflikte und leere Felder sofort. |
| Spalten extrahieren | cut -d',' -f1,5 dataset.csv \| head |
Schneidet Spalten direkt als Bytestream aus. |
| Kategorien zählen | cut -d',' -f5 iris.csv \| grep -v '^$' \| sort \| uniq -c |
Schnelles Äquivalent zu value_counts() in reiner Bash. |
| Schnelle Mittelwerte berechnen | awk -F',' 'NR>1 {sum+=$1; n++} END {print sum/n}' iris.csv |
Berechnet den Durchschnitt von Spalte 1 in einem Durchlauf (O(1) RAM). |
JSON-APIs zerlegen (jq) |
curl -s https://api.example.com/items \| jq '.[] \| {id, price}' |
Formatiert und filtert verschachtelte JSON-Daten direkt im Terminal. |
Hands-On Lab 1: Datenanalyse ohne Python am UCI Iris-Datensatz
Lade den bekannten UCI Iris-Datensatz und analysiere Zeilenanzahl, Klassenverteilung und Mittelwerte rein über die Shell:
mkdir -p ~/ds-workspace/labs && cd ~/ds-workspace/labs
wget -q "https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data" -O iris.csv
# Leerzeilen am Dateiende direkt mit sed entfernen
sed -i '/^$/d' iris.csv
# Zeilenanzahl und erste 5 Zeilen prüfen
wc -l iris.csv
head -n 5 iris.csv
# Klassenverteilung ermitteln (wie value_counts)
echo "--- Klassenverteilung ---"
cut -d',' -f5 iris.csv | sort | uniq -c
# Durchschnittliche Kelchblattlänge (Spalte 1) pro Art (Spalte 5) via awk berechnen
echo "--- Durchschnittliche Kelchblattlänge pro Art ---"
awk -F',' '{sum[$5] += $1; count[$5]++} END {for (s in sum) printf "%-18s : %.2f cm (n=%d)\n", s, sum[s]/count[s], count[s]}' iris.csv
4. Explorative Datenanalyse (EDA) & Statistische Visualisierung
Nach der ersten Vorprüfung laden wir den Datensatz in Pandas für mehrdimensionale EDA und erzeugen Visualisierungen mit Seaborn und Matplotlib.
Die richtige Visualisierung wählen
-
Verteilung:
sns.histplot&sns.boxplot
Zeigt Schiefe, Modalität, Median, Interquartilsabstand (
IQR) und Extremwerte numerischer Features über verschiedene Gruppen hinweg. -
Beziehungen:
sns.scatterplot&sns.pairplot
Visualisiert paarweise Wechselwirkungen zwischen Merkmalen und Trennbarkeiten über Zielklassen hinweg (
hue='Species'). -
Korrelationen:
sns.heatmap(df.corr())
Quantifiziert Pearson- (
r) oder Spearman-Rangkorrelationen zwischen allen Variablen, um Kollinearität und prädiktive Merkmale aufzudecken. -
Aggregationen:
sns.barplot&sns.countplot
Vergleicht Klassenverteilungen und Gruppenmittelwerte inklusive Konfidenzintervallen für diskrete kategoriale Variablen.
Hands-On Lab 2: Automatisierte EDA & Plot-Generierung auf Headless Linux
Auf einem Linux-Server benötigt man keine grafische Oberfläche – plt.savefig(..., dpi=300) exportiert hochauflösende Grafiken direkt auf die Festplatte:
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
cols = ["SepalLengthCm", "SepalWidthCm", "PetalLengthCm", "PetalWidthCm", "Species"]
df = pd.read_csv("iris.csv", header=None, names=cols)
print("=== 1. Dimensionen & Fehlwerte ===")
print(f"Shape: {df.shape}")
print(df.isna().sum())
print("\n=== 2. Statistische Zusammenfassung ===")
print(df.groupby("Species").describe().T)
# Korrelationsmatrix & Pairplot als 300-DPI-Grafiken speichern
sns.set_theme(style="whitegrid")
plt.figure(figsize=(7, 5))
corr = df.drop(columns=["Species"]).corr()
sns.heatmap(corr, annot=True, cmap="crest", fmt=".2f", linewidths=0.5)
plt.title("Iris Feature Correlation Matrix")
plt.tight_layout()
plt.savefig("iris_correlation_heatmap.png", dpi=300)
plt.close()
pair_grid = sns.pairplot(df, hue="Species", markers=["o", "s", "D"])
pair_grid.fig.suptitle("Pairwise Feature Separability", y=1.02)
pair_grid.savefig("iris_pairplot.png", dpi=300)
print("\n[OK] 'iris_correlation_heatmap.png' und 'iris_pairplot.png' gespeichert!")
5. Feature Engineering & Leckfreie ML-Pipelines
Echte Datensätze enthalten fehlende Werte (NaN), unausgewogene Verteilungen und unkodierte Textspalten.
Der häufigste Fehler im Machine Learning: Data Leakage!
Wende niemals scaler.fit_transform(df) oder Median-Imputationen auf den gesamten Datensatz vor dem Train/Test-Split an! Wenn Mittelwerte oder Standardabweichungen über den gesamten Datensatz berechnet werden, fließen Informationen des Testdatensatzes in die Trainingsphase ein – das führt zu scheinbar exzellenten, in der Praxis jedoch instabilen Modellen.
Die saubere Lösung: Scikit-learn ColumnTransformer + Pipeline
Statt manueller pd.get_dummies()-Aufrufe, die beim Fehlen einer Kategorie im Testset scheitern, kapseln wir alle Vorverarbeitungsschritte in einer Scikit-learn Pipeline:
%%{init: {'flowchart': {'wrappingWidth': 600, 'subGraphTitleMargin': {'top': 15, 'bottom': 15}}}}%%
flowchart TB
Raw["📋 Raw Input DataFrame<br/>Age, Fare, Pclass, Sex, Title"]
CT["🔀 ColumnTransformer<br/>Feature-Typen aufteilen"]
subgraph Preprocessing ["Scikit-learn Vorverarbeitungs-Pipelines"]
direction TB
N_Branch["🔢 Numerischer Zweig<br/>(Age, Fare, FamilySize)"]
N1["SimpleImputer (strategy='median')"]
N2["StandardScaler (Zero Mean, Unit Variance)"]
N_Branch --> N1 --> N2
C_Branch["🏷️ Kategorialer Zweig<br/>(Pclass, Sex, Embarked, Title)"]
C1["SimpleImputer (strategy='most_frequent')"]
C2["OneHotEncoder (handle_unknown='ignore')"]
C_Branch --> C1 --> C2
end
Concat["🧱 Einheitliche Feature-Matrix (Concat)"]
Model["🌲 Estimator-Modell (RandomForest / LogReg)"]
Raw ==> CT
CT --> N_Branch
CT --> C_Branch
N2 ==> Concat
C2 ==> Concat
Concat ==> Model
Warum diese Architektur überlegen ist:
- Null Data Leakage: Bei
pipeline.fit(X_train, y_train)werden Mediane und Skalierungswerte ausschließlich ausX_traingelernt und beipipeline.predict(X_test)exakt aufX_testangewendet. - Robustheit im Live-Betrieb: Erhält die Produktions-API eine bisher ungesehene Kategorie, ignoriert
OneHotEncoder(handle_unknown='ignore')diese sicher ohne Fehlermeldung. - Einfache Serialisierung: Die gesamte Pipeline (Imputer + Encoder + Skalierer + Modell) wird in einer einzigen
.joblib-Datei abgelegt.
Hands-On Lab 3: Leckfreie Pipeline am Titanic-Datensatz trainieren
import pandas as pd
import numpy as np
import joblib
from sklearn.model_selection import train_test_split, StratifiedKFold, GridSearchCV
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, roc_auc_score
# 1. Titanic-Datensatz laden
url = "https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv"
df = pd.read_csv(url)
# 2. Feature-Engineering auf Zeilenebene (Sicher vor dem Split, da nur eigene Werte genutzt werden)
df["FamilySize"] = df["SibSp"] + df["Parch"] + 1
df["IsAlone"] = (df["FamilySize"] == 1).astype(int)
df["Title"] = df["Name"].str.extract(r" ([A-Za-z]+)\.", expand=False)
df["Title"] = df["Title"].where(df["Title"].isin(["Mr", "Miss", "Mrs", "Master"]), "Rare")
features = ["Pclass", "Sex", "Age", "Fare", "Embarked", "FamilySize", "IsAlone", "Title"]
X = df[features]
y = df["Survived"]
# 3. Stratified Train/Test Split VOR jeglicher Imputation oder Skalierung!
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=42, stratify=y
)
# 4. Leckfreie Vorverarbeitungspipelines aufbauen
num_cols = ["Age", "Fare", "FamilySize"]
cat_cols = ["Pclass", "Sex", "Embarked", "Title", "IsAlone"]
num_transformer = Pipeline([
("imputer", SimpleImputer(strategy="median")),
("scaler", StandardScaler())
])
cat_transformer = Pipeline([
("imputer", SimpleImputer(strategy="most_frequent")),
("onehot", OneHotEncoder(handle_unknown="ignore", sparse_output=False))
])
preprocessor = ColumnTransformer([
("num", num_transformer, num_cols),
("cat", cat_transformer, cat_cols)
])
full_pipeline = Pipeline([
("prep", preprocessor),
("clf", RandomForestClassifier(random_state=42, n_jobs=-1))
])
# 5. Hyperparameter-Tuning via 5-Fold Stratified Cross-Validation
param_grid = {
"clf__n_estimators": [100, 200],
"clf__max_depth": [5, 10, None],
"clf__min_samples_leaf": [1, 2, 4]
}
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
grid = GridSearchCV(full_pipeline, param_grid, cv=cv, scoring="roc_auc", n_jobs=-1)
grid.fit(X_train, y_train)
print(f"Bester CV ROC-AUC: {grid.best_score_:.4f}")
print(f"Beste Parameter : {grid.best_params_}")
# 6. Finale Auswertung auf dem unberührten Test-Set
best_pipeline = grid.best_estimator_
y_pred = best_pipeline.predict(X_test)
y_prob = best_pipeline.predict_proba(X_test)[:, 1]
print(f"\nTest-Set ROC-AUC: {roc_auc_score(y_test, y_prob):.4f}")
print("\nKlassifikationsbericht:\n", classification_report(y_test, y_pred))
# 7. Gesamte Pipeline in einem einzigen Artefakt speichern
joblib.dump(best_pipeline, "titanic_production_pipeline.joblib")
print("[OK] Pipeline gespeichert unter 'titanic_production_pipeline.joblib'")
6. Modell-Evaluationsmetriken im Überblick
| Problemtyp | Metrik | Bedeutung | Wann anwenden? |
|---|---|---|---|
| Klassifikation | Precision (Präzision) | TP / (TP + FP) |
Wenn False Positives teuer sind (z. B. legitime E-Mail als Spam blockiert). |
| Klassifikation | Recall (Sensitivität) | TP / (TP + FN) |
Wenn False Negatives gefährlich sind (z. B. medizinische Diagnose, Einbruchserkennung). |
| Klassifikation | F1-Score | 2 × (Precision × Recall) / (Precision + Recall) |
Harmonisches Mittel aus Precision & Recall; ideal bei unbalancierten Klassen. |
| Klassifikation | ROC-AUC | Fläche unter der TPR/FPR-Kurve | Schwellenwertunabhängige Modellgüte (1.0 = perfekt, 0.5 = Zufall). |
| Regression | MAE | (1/n) × Σ \|y_true - y_pred\| |
Durchschnittlicher Fehler in Originaleinheiten; robust gegen Ausreißer. |
| Regression | RMSE | √((1/n) × Σ (y_true - y_pred)²) |
Bestraft große Abweichungen durch Quadrierung besonders hart. |
| Regression | R² (Bestimmtheitsmaß) | 1 - (SS_res / SS_tot) |
Anteil der erklärten Varianz der Zielvariablen (1.0 = optimal). |
7. Deep Learning auf Linux (PyTorch & Keras/TensorFlow)
Für unstrukturierte Daten (Bilder, Audio, Texte, Zeitreihen) lernen tiefe neuronale Netze Repräsentationen hierarchisch:
Bietet explizite Kontrolle über GPU-Allokation (cuda/cpu), dynamische Berechnungsgraphen (autograd) und Trainingsschleifen:
import torch
import torch.nn as nn
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"PyTorch Version {torch.__version__} läuft auf: {device}")
class MnistCNN(nn.Module):
def __init__(self):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(1, 32, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2),
)
self.classifier = nn.Sequential(
nn.Flatten(),
nn.Dropout(0.5),
nn.Linear(64 * 7 * 7, 10)
)
def forward(self, x):
return self.classifier(self.features(x))
model = MnistCNN().to(device)
print(model)
Ermöglicht schnelles Prototyping mit integrierten Trainingsschleifen (model.fit):
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train = (x_train.astype("float32") / 255.0)[..., None]
x_test = (x_test.astype("float32") / 255.0)[..., None]
model = keras.Sequential([
keras.Input(shape=(28, 28, 1)),
layers.Conv2D(32, kernel_size=(3, 3), activation="relu"),
layers.MaxPooling2D(pool_size=(2, 2)),
layers.Conv2D(64, kernel_size=(3, 3), activation="relu"),
layers.MaxPooling2D(pool_size=(2, 2)),
layers.Flatten(),
layers.Dropout(0.5),
layers.Dense(10, activation="softmax"),
])
model.compile(loss="sparse_categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
model.fit(x_train, y_train, batch_size=128, epochs=5, validation_split=0.1)
test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0)
print(f"Test Accuracy: {test_acc:.4f}")
8. Verteilte Big-Data-Verarbeitung mit PySpark
Übersteigen Datensätze den RAM eines Einzelsystems, verteilt Apache Spark (PySpark) Berechnungen über alle CPU-Kerne oder Cluster-Knoten via Lazy Evaluation:
from pyspark.sql import SparkSession
from pyspark.sql.functions import regexp_extract, col, desc
spark = SparkSession.builder \
.appName("LinuxLogAnalytics") \
.master("local[*]") \
.getOrCreate()
spark.sparkContext.setLogLevel("WARN")
log_regex = r'^(\S+) \S+ \S+ \[([\w:/]+\s[+\-]\d{4})\] "(\S+) (\S+)\s*\S*" (\d{3}) (\d+)'
raw_logs = spark.read.text("/var/log/nginx/access.log")
parsed_df = raw_logs.select(
regexp_extract("value", log_regex, 1).alias("client_ip"),
regexp_extract("value", log_regex, 3).alias("http_method"),
regexp_extract("value", log_regex, 4).alias("endpoint"),
regexp_extract("value", log_regex, 5).cast("integer").alias("status_code"),
regexp_extract("value", log_regex, 6).cast("long").alias("bytes")
).filter(col("client_ip") != "")
parsed_df.groupBy("status_code").count().orderBy(desc("count")).show()
parsed_df.groupBy("client_ip").count().orderBy(desc("count")).limit(10).show()
spark.stop()
9. MLOps: Experiment-Tracking (MLflow) & FastAPI-Deployment
Ein Modell im Jupyter-Notebook erzeugt noch keinen Produktionswert. In einer professionellen MLOps-Pipeline:
1. MLflow protokolliert Hyperparameter, Metriken und Modellversionen beim Training.
2. FastAPI + Pydantic stellt die gespeicherte Pipeline als typsicheren, schnellen ASGI-Dienst mit automatischer Dokumentation (/docs) bereit.
%%{init: {'flowchart': {'wrappingWidth': 600, 'subGraphTitleMargin': {'top': 15, 'bottom': 15}}}}%%
flowchart TB
Client(("🌐 Client / Backend App")) ==>|"POST /predict (JSON)"| FastAPI
subgraph Container ["📦 Rootless-Container (FastAPI + Uvicorn)"]
FastAPI["⚡ FastAPI Endpoint"] ==> Pydantic["🛡️ Pydantic v2 Schema<br/>(Strikte Typvalidierung)"]
Pydantic ==> Joblib["⚙️ Scikit-learn Pipeline<br/>(Imputer → OneHot → RF)"]
end
Joblib ==>|"JSON: prediction + probability"| Client
Hands-On Lab 4: Modellbereitstellung via FastAPI
Da wir die gesamte Pipeline inklusive Vorverarbeitung in titanic_production_pipeline.joblib gespeichert haben, benötigt die API keinerlei manuelle Transformationen:
from fastapi import FastAPI
from pydantic import BaseModel, Field
import joblib
import pandas as pd
app = FastAPI(title="Titanic Survival Inference API", version="1.0.0")
pipeline = joblib.load("titanic_production_pipeline.joblib")
class PassengerInput(BaseModel):
Pclass: int = Field(..., ge=1, le=3, examples=[1])
Sex: str = Field(..., examples=["female"])
Age: float = Field(..., ge=0, le=120, examples=[38.0])
Fare: float = Field(..., ge=0, examples=[71.28])
Embarked: str = Field(..., examples=["C"])
FamilySize: int = Field(..., ge=1, examples=[2])
IsAlone: int = Field(..., ge=0, le=1, examples=[0])
Title: str = Field(..., examples=["Mrs"])
@app.post("/predict")
def predict_survival(passenger: PassengerInput):
df_input = pd.DataFrame([passenger.model_dump()])
pred = int(pipeline.predict(df_input)[0])
prob = float(pipeline.predict_proba(df_input)[0][1])
return {
"survived": pred,
"label": "Survived" if pred == 1 else "Did Not Survive",
"survival_probability": round(prob, 4)
}
API testen:
uvicorn app:app --host 127.0.0.1 --port 8000 &
curl -s -X POST "http://127.0.0.1:8000/predict" \
-H "Content-Type: application/json" \
-d '{"Pclass": 1, "Sex": "female", "Age": 38.0, "Fare": 71.28, "Embarked": "C", "FamilySize": 2, "IsAlone": 0, "Title": "Mrs"}' | jq .
10. Fehlerbehebung & Häufige Fragen
1. Warum bricht mein Python-Prozess mit Killed (Exit-Code 137) beim Laden großer Dateien ab?
Ursache: Der Out-Of-Memory (OOM) Killer des Linux-Kernels (dmesg -T | grep -i oom) hat den Prozess beendet, da pd.read_csv() oft das 3- bis 5-fache der Dateigröße im RAM belegt.
Lösung:
1. Nutze die PyArrow-Engine: pd.read_csv("big.csv", engine="pyarrow").
2. Filtere Spalten vorab mit awk oder nutze speicherschonendes Streaming mit DuckDB oder Polars (pl.scan_csv()).
2. Wie verifiziere ich die NVIDIA-GPU-Nutzung in PyTorch unter Linux?
Lösung: Prüfe zunächst den Treiber über nvidia-smi und teste danach in Python:
3. Fehler error: externally-managed-environment bei pip install
Ursache: Debian 12 und Ubuntu 24.04 erzwingen PEP 668, um Konflikte mit dem Paketmanager apt zu vermeiden.
Lösung: Erstelle immer eine virtuelle Umgebung (uv venv .venv && source .venv/bin/activate oder python3 -m venv .venv).