Weiter zum Inhalt

Preprocessing in Data Science (Teil 1): Zentrieren, Skalieren und k-NN

Dieser Artikel zeigt, warum Preprocessing in der Machine-Learning-Pipeline so wichtig ist – anhand davon, wie Zentrierung und Skalierung die Modellleistung verbessern können.
Aktualisiert 18. Sept. 2026  · 11 Min. lesen

Mit KI erkunden

ChatGPTClaudePerplexity
\n
Daten-Preprocessing ist ein Sammelbegriff für eine Reihe von Arbeitsschritten, mit denen Data Scientists ihre Daten in eine Form bringen, die besser zu ihrem Vorhaben passt. Bevor du zum Beispiel eine Sentimentanalyse von Twitter-Daten durchführst, möchtest du vermutlich HTML-Tags und überflüssige Leerzeichen entfernen, Abkürzungen ausschreiben und die Tweets in Wortlisten zerlegen. Bei räumlichen Daten bietet es sich an, sie so zu skalieren, dass sie einheitsunabhängig werden – dein Algorithmus soll sich nicht darum kümmern müssen, ob die ursprünglichen Messungen in Meilen oder Zentimetern vorlagen. Allerdings findet Preprocessing nie im luftleeren Raum statt. Es ist immer Mittel zum Zweck, und es gibt keine in Stein gemeißelten Regeln: Es existieren bewährte Verfahren, wie wir sehen werden, und du entwickelst mit der Zeit ein Gefühl dafür, was funktioniert. Am Ende ist Preprocessing jedoch Teil einer ergebnisorientierten Pipeline, und seine Wirkung muss im Kontext bewertet werden.
\n
\n
\n

In diesem Artikel nutze ich das Beispiel der Skalierung numerischer Daten (numerische Daten: Werte bestehen aus Zahlen statt Kategorien/Strings; Skalierung: mithilfe einfacher Arithmetik den Wertebereich verändern; Details folgen), um zu zeigen, warum du Preprocessing stets als Bestandteil einer größeren Struktur betrachten solltest: der Machine-Learning-(ML)-Pipeline. Dazu schauen wir uns ein Praxisbeispiel an, in dem Skalierung die Modellleistung verbessert.

\n

Zunächst führe ich in Klassifikationsprobleme im ML ein und in k-Nearest Neighbors, einen der einfachsten Algorithmen dafür. Um die Bedeutung der Skalierung numerischer Daten in diesem Setting zu verstehen, stelle ich Metriken zur Beurteilung der Modellleistung sowie die Konzepte Trainings- und Testset vor. All das wenden wir anschließend auf einen Datensatz an, in dem ich die Qualität von Rotwein klassifizieren möchte. Außerdem ordne ich Preprocessing an der sinnvollsten Stelle ein: zu Beginn einer iterativen Data-Science-Pipeline. Alle Beispiele sind in Python. Wenn du Python noch nicht kennst, findest du unsere DataCamp-Kurse hier. Ich verwende die Bibliotheken pandas für DataFrames und scikit-learn für Machine Learning.

\n

Dies ist Teil eins eines dreiteiligen Tutorials:

\n

Teil 2: Zentrieren, Skalieren und Logistische Regression

\n

Teil 3: Skalierung synthetischer Daten

\n
\n
\n
\n
\n
\n
\n

Ein kurzer Einstieg in Klassifikationsprobleme im Machine Learning

\n
\n
\n
\n
\n
\n
\n

Dinge in der erlebbaren Welt zu klassifizieren und zu benennen, ist eine uralte Kunst. Bereits im 4. Jahrhundert v. Chr. entwarf Aristoteles ein Klassifikationssystem für Lebewesen, das 2.000 Jahre lang genutzt wurde. Heute verstehen wir Klassifikation meist als Machine-Learning-Aufgabe, genauer als Aufgabe des überwachtes Lernens. Das Grundprinzip ist simpel: Wir haben Daten, bestehend aus Prädiktorvariablen und einer Zielvariablen. Ziel des überwachten Lernens ist es, ein Modell zu bauen, das die Zielvariable auf Basis der Prädiktoren „gut“ vorhersagt. Besteht die Zielvariable aus Kategorien (z. B. „Klick“ oder „kein Klick“, „bösartig“ oder „gutartig“), sprechen wir von Klassifikation. Handelt es sich dagegen um eine stetige Variable (z. B. Hauspreis), ist es eine Regression.

\n

Ein Beispiel macht es greifbar: Im Heart-Disease-Datensatz gibt es 75 Prädiktoren wie „Alter“, „Geschlecht“ und „Raucherstatus“. Die Zielvariable beschreibt das Vorhandensein von Herzerkrankungen und reicht von 0 (keine) bis 4. Viele Arbeiten zu diesem Datensatz konzentrieren sich darauf, das Vorhandensein von Herzkrankheiten vom Nichtvorhandensein zu unterscheiden. Das ist eine Klassifikationsaufgabe. Würdest du versuchen, den tatsächlichen Wert (0 bis 4) vorherzusagen, wäre das ein Regressionsproblem (weil die Zielvariable geordnet ist). Über Regression spreche ich im nächsten Beitrag. Hier schauen wir uns einen der einfachsten Klassifikations-Algorithmen an: den k-Nearest-Neighbors-Algorithmus.

\n
\n
\n
\n
\n
\n
\n

k-Nearest Neighbors für Klassifikation im Machine Learning

\n
\n
\n
\n
\n
\n
\n

Angenommen, wir haben gelabelte Daten, etwa Merkmale von Rotwein (z. B. Alkoholgehalt, Dichte, Zitronensäuregehalt, pH-Wert usw.; das sind die Prädiktoren) mit der Zielvariable „Quality“ und den Labels „good“ & „bad“. Dann besteht die Klassifikationsaufgabe darin, für einen neuen, noch nicht gelabelten Wein seine „Quality“ vorherzusagen. Sind alle Prädiktoren numerisch (für kategoriale gibt es andere Ansätze), kann jede Zeile/jeder Wein als ein Punkt in einem n-dimensionalen Raum betrachtet werden. k-Nearest Neighbors (k-NN) ist dann ein konzeptionell und rechnerisch einfacher Klassifikationsansatz: Für jeden neuen, ungelabelten Wein berechnen wir für ein ganzzahliges k seine k nächsten Nachbarn im n-dimensionalen Prädiktorraums. Dann schauen wir auf die Labels dieser k Nachbarn („good“ oder „bad“) und vergeben dem neuen Wein das Label mit den meisten Stimmen (z. B. wenn k = 5, drei Nachbarn „good“ und zwei „bad“, labelt das Modell den Wein als „good“). Beachte: „Training“ bedeutet hier im Grunde nur, die Datenpunkte zu speichern – es gibt keine zu schätzenden Parameter!

\n
\n
\n
\n
\n
\n
\n

Eine visuelle Beschreibung von k-Nearest Neighbors

\n
\n
\n
\n
\n
\n
\n

In der Abbildung unten siehst du k-NN in 2D: Wie würdest du den Punkt in der Mitte klassifizieren? Wenn k=3 ist, wäre er rot; bei k=5 wäre er grün.

\n
\n
\n
\n
\n
\n
\n
\n
 
\n
\"k-nn
\n
\n
\n
\n
\n
\n
\n
\n

k-NN in Python (scikit-learn) implementieren

\n
\n
\n
\n
\n
Schauen wir uns k-NN nun in Aktion an. Dafür nutzen wir das Wine-Quality-Dataset: Wir laden es in ein pandas-DataFrame und zeichnen anschließend Histogramme der Prädiktorvariablen, um ein Gefühl für die Daten zu bekommen.
\n
\n
import pandas as pd%matplotlib inlineimport matplotlib.pyplot as pltplt.style.use('ggplot')df = pd.read_csv('http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv ' , sep = ';')X = df.drop('quality' , 1).values # drop target variabley1 = df['quality'].valuespd.DataFrame.hist(df, figsize = [15,15]);
\n
\n
\n
\n
\n
\n
\n
\"bar
\n
\n
\n
\n
\n
\n
\n
\n

Schau dir zunächst die Wertebereiche der Prädiktoren an: „free sulfur dioxide“ reicht von 0 bis ca. 70, „volatile acidity“ von ca. 0 bis 1,2. Ersteres hat also einen zwei Größenordnungen größeren Bereich als letzteres. Jeder Algorithmus, der Distanzen zwischen Punkten berücksichtigt – wie k-NN –, kann dadurch stark und unfair auf Variablen mit großem Wertebereich fokussieren, etwa auf „free sulfur dioxide“, das womöglich nur Rauschen enthält. Das ist ein starkes Argument für die Skalierung der Daten, zu der wir gleich kommen.

\n

Die Zielvariable ist eine „Quality“-Bewertung und reicht von 3 bis 8. Für eine einfachere Darstellung machen wir daraus eine binäre Variable: „good“ (Rating > 5) und „bad“ (Rating <= 5). Wir plotten Histogramme beider Varianten, um ein Gefühl für die Verteilung zu bekommen.

\n
y = y1 <= 5 # is the rating <= 5?# plot histograms of original target variable# and aggregated target variableplt.figure(figsize=(20,5));plt.subplot(1, 2, 1 );plt.hist(y1);plt.xlabel('original target value')plt.ylabel('count')plt.subplot(1, 2, 2);plt.hist(y)plt.xlabel('aggregated target value')plt.show()
\n\n
\n
\n
\n
\n
\n
\n
\n
\"bar
\n
\n
\n
\n
\n
\n
Jetzt sind wir fast bereit für k-Nearest Neighbors. Wenn wir die Leistung unseres Modells mit und ohne Preprocessing vergleichen wollen, brauchen wir jedoch zunächst eine Möglichkeit, die „Güte“ eines Modells zu messen:
\n
\n
\n
\n
\n

k-Nearest Neighbors: Wie gut performt es?

\n
\n
\n
\n
\n
Es gibt mehrere Kennzahlen für Klassifikationsprobleme. Entscheidend ist, dass die Wahl der Kennzahl stark von Domäne und Fragestellung abhängt. Bei Datensätzen mit ausgewogenen Klassen (alle Zielwerte sind etwa gleich häufig) betrachten Data Scientists häufig die Accuracy als Leistungsmaß. Tatsächlich ist Accuracy in scikit-learn die Standardmetrik für k-Nearest Neighbors und auch für Logistische Regression. Was ist Accuracy? Es ist einfach die Zahl der korrekten Vorhersagen geteilt durch die Gesamtzahl der Vorhersagen:
\n
\n
$$\\text{Accuracy}=\\frac{\\text{Number of Correct Predictions}}{\\text{Total Number of Predictions}}.$$
\n
\n
\n
\n
\n
\n

Hinweis: Accuracy lässt sich auch anhand der Konfusionsmatrix definieren und wird für binäre Klassifikation häufig über True Positives und False Negatives beschrieben. Weitere gängige Kennzahlen aus der Konfusionsmatrix sind Precision (True Positives geteilt durch True Positives plus False Positives) und Recall (True Positives geteilt durch True Positives plus False Negatives). Eine weitere Kennzahl ist der F1-Score, das harmonische Mittel aus Precision und Recall. Siehe Machine Learning Mastery für eine gute Einführung; außerdem die Wikipedia-Artikel zur Konfusionsmatrix und zum F1-Score.

\n
\n
\n
\n
\n

k-Nearest Neighbors: Praxisleistung und Train-Test-Split

\n
\n
\n
Eine Metrik wie Accuracy ist gut und schön, aber wenn wir das Modell auf allen vorhandenen Daten fitten, von welchem Datensatz berichten wir dann die Accuracy? Wir wollen ein Modell, das gut auf neue Daten generalisiert. Trainieren wir es auf einem Datensatz D, kann die Accuracy auf demselben Datensatz D das Modell besser aussehen lassen, als es tatsächlich ist. Das nennt man Overfitting. Um das zu vermeiden, trainieren Data Scientists ihr Modell meist auf einem Teil der Daten, dem Trainingsset, und bewerten die Leistung auf dem Rest der Daten, dem Testset. Genau das machen wir hier. Als Faustregel gelten ca. 80 % Training und 20 % Test. Teilen wir also die Rotwein-Daten auf:
\n
\n
from sklearn.cross_validation import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)We now build the k-NN model, make predictions on the test set and compare these predictions to the ground truth in order to get a measure of model performance:from sklearn import neighbors, linear_modelknn = neighbors.KNeighborsClassifier(n_neighbors = 5)knn_model_1 = knn.fit(X_train, y_train)print('k-NN accuracy for test set: %f' % knn_model_1.score(X_test, y_test))k-NN accuracy for test set: 0.612500
\n
\n
\n
\n
\n
\n
\n
\n

Es sei noch einmal betont: Die Standardmetrik für k-NN in scikit-learn ist
Accuracy. Eine Accuracy von 61 % ist nicht überragend, aber für ein Modell out of the box ohne Preprocessing auch nicht katastrophal. Um weitere Kennzahlen zu prüfen, nutzen wir zusätzlich den Classification Report von scikit-learn:

\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
from sklearn.metrics import classification_reporty_true, y_pred = y_test, knn_model_1.predict(X_test)print(classification_report(y_true, y_pred))
\n
\n
\n
\n
\n
\n
\n
\n
 
\n
\n
             precision    recall  f1-score   support      False       0.66      0.64      0.65       179       True       0.56      0.57      0.57       141avg / total       0.61      0.61      0.61       320
\n
\n
\n
\n
\n
\n
\n
\n
\n

Jetzt führen wir Skalierung und Zentrierung ein – die grundlegendsten Methoden des Preprocessings numerischer Daten – und prüfen, ob und wie sie die Modellleistung beeinflussen.

\n
\n
\n
\n
\n
\n
\n

Die Mechanik des Preprocessings: Skalieren und Zentrieren

\n
\n
\n
\n
\n
\n
\n

Bevor du ein Modell wie Regression (Vorhersage einer stetigen Variable) oder Klassifikation (Vorhersage einer diskreten Variable) trainierst, lohnt sich fast immer etwas Preprocessing. Für numerische Variablen ist es üblich, die Daten zu normalisieren oder zu standardisieren. Was bedeutet das?

\n

Normalisierung heißt, einen Datensatz so zu skalieren, dass das Minimum 0 und das Maximum 1 ist. Dazu transformieren wir jeden Datenpunkt $x$ zu

\n$$x_{normalized} = \\frac{x-x_{min}}{x_{max}-x_{min}}.$$
\n

Standardisierung ist etwas anderes; sie zentriert die Daten um 0 und skaliert relativ zur Standardabweichung:

\n$$x_{standardized} = \\frac{x-\\mu}{\\sigma},$$
\n

wobei $\\mu$ und $\\sigma$ Mittelwert bzw. Standardabweichung des Datensatzes sind. Wichtig: Diese Transformationen verändern nur den Wertebereich, nicht die Verteilung. Später kannst du weitere Transformationen wie Log- oder Box-Cox-Transformation nutzen, um die Daten „glockenkurviger“ zu machen. Vorher sollten wir aber fragen: Warum skalieren wir überhaupt? Wann ist es besonders sinnvoll? Ist es etwa bei Klassifikation wichtiger als bei Regression?

\n

Beginnen wir mit Klassifikationsaufgaben und sehen wir uns an, wie Skalierung die Leistung von k-Nearest Neighbors beeinflusst:

\n
\n
\n
\n
\n
\n
\n

Preprocessing: Skalierung in der Praxis

\n
\n
\n
\n
\n
\n
\n

Im Folgenden (i) skaliere ich die Daten, (ii) setze k-Nearest Neighbors ein und (iii) prüfe die Modellleistung. Ich verwende die scale-Funktion von scikit-learn, die alle Features (Spalten) des übergebenen Arrays standardisiert.

\n
from sklearn.preprocessing import scaleXs = scale(X)from sklearn.cross_validation import train_test_splitXs_train, Xs_test, y_train, y_test = train_test_split(Xs, y, test_size=0.2, random_state=42)knn_model_2 = knn.fit(Xs_train, y_train)print('k-NN score for test set: %f' % knn_model_2.score(Xs_test, y_test))print('k-NN score for training set: %f' % knn_model_2.score(Xs_train, y_train))y_true, y_pred = y_test, knn_model_2.predict(Xs_test)print(classification_report(y_true, y_pred))
\n
\n
\n
\n
\n
\n
 
\n
\n
\n
\n
\n
\n
 k-NN score for test set: 0.712500k-NN score for training set: 0.814699             precision    recall  f1-score   support      False       0.72      0.79      0.75       179       True       0.70      0.62      0.65       141avg / total       0.71      0.71      0.71       320
\n
\n
\n
\n
\n
\n
\n
\n
\n

Alle Kennzahlen haben sich um 0,1 verbessert – das sind 16 % und damit deutlich. Wie oben angedeutet, gab es vor der Skalierung Prädiktoren mit sehr unterschiedlichen Größenordnungen. Bei einem Algorithmus wie k-NN können dadurch ein oder zwei Features dominieren. Die zwei Hauptgründe fürs Skalieren sind:

\n
    \n
  1. Deine Prädiktoren haben stark unterschiedliche Wertebereiche, und in bestimmten Verfahren wie k-NN musst du verhindern, dass einzelne Features das Ergebnis dominieren.
  2. \n
  3. Du willst Merkmale einheitsunabhängig machen, also unabhängig von der Messskala: Wenn ich ein Feature in Metern habe und du in Zentimetern, erhalten wir durch Skalierung die gleichen Merkmalswerte.
  4. \n
\n
\n
\n
\n
\n
\n
\n

Wir haben gesehen, welche zentrale Rolle Preprocessing – in Form von Skalierung und Zentrierung – in der Data-Science-Pipeline spielt, und damit einen ganzheitlichen Blick auf ML-Aufgaben gefördert. In kommenden Artikeln möchte ich das auf weitere Arten des Preprocessings ausweiten, etwa Transformationen numerischer Daten und Preprocessing kategorialer Daten – beides gehört in jeden Data-Science-Werkzeugkasten. Bevor wir dahin gehen, beleuchte ich im nächsten Artikel die Rolle der Skalierung bei regressionsbasierten Klassifikationsansätzen. Konkret schauen wir auf Logistische Regression – und du wirst sehen, dass das Ergebnis sich deutlich von dem hier bei k-Nearest Neighbors unterscheidet.

\n
\n
\n
\n
\n
\n
\n

Im interaktiven Fenster unten kannst du selbst mit den Daten experimentieren. Starte damit, die Variable n_neig zu ändern – sie legt die Zahl der Nachbarn im k-NN-Algorithmus fest. Du kannst die Daten auch skalieren, indem du sc = True setzt. Führe dann das gesamte Skript aus, um die Accuracy des Modells sowie den Classification Report zu sehen.

\n
import pandas as pdimport matplotlib.pyplot as pltfrom sklearn.cross_validation import train_test_splitfrom sklearn import neighborsfrom sklearn.preprocessing import scalefrom sklearn.metrics import classification_report # Set the the number of neighbors for k-NNn_neig = 5# Set sc = True if you want to scale your featuressc = False# Load datadf = pd.read_csv('http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv ' , sep = ';')X = df.drop('quality' , 1).values# drop target variable# Here we scale, if desiredif sc == True: X = scale(X)# Target valuey1 = df['quality'].values# original target variabley = y1 <= 5# new target variable: is the rating <= 5?# Split the data into a test set and a training setX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# Train k-NN model and print performance on the test setknn = neighbors.KNeighborsClassifier(n_neighbors = n_neig)knn_model = knn.fit(X_train, y_train)y_true, y_pred = y_test, knn_model.predict(X_test)print('k-NN accuracy for test set: %f' % knn_model.score(X_test, y_test))print(classification_report(y_true, y_pred))
\n
\n
\n
\n

Glossar

\n
\n
\n
\n

Überwachtes Lernen (Supervised Learning): Die Aufgabe, aus Prädiktorvariablen eine Zielvariable abzuleiten. Beispiel: Die Zielvariable „Vorhandensein von Herzkrankheit“ aus Prädiktoren wie „Alter“, „Geschlecht“ und „Raucherstatus“ vorhersagen.

\n

Klassifikationsaufgabe: Eine Aufgabe des überwachten Lernens ist eine Klassifikation, wenn die Zielvariable aus Kategorien besteht (z. B. „Klick“ oder „kein Klick“, „bösartiger“ oder „gutartiger“ Tumor).

\n

Regressionsaufgabe: Eine Aufgabe des überwachten Lernens ist eine Regression, wenn die Zielvariable stetig ist (z. B. Hauspreis) oder eine geordnete kategoriale Variable wie die „Qualitätsbewertung von Wein“.

\n

k-Nearest Neighbors: Ein Algorithmus für Klassifikationsaufgaben, bei dem ein Datenpunkt das Label erhält, das die Mehrheit seiner k nächsten Nachbarn trägt.

\n

Preprocessing: Alle Schritte, mit denen Data Scientists Daten in eine geeignetere Form für die geplante Analyse bringen. Beispiel: Vor einer Sentimentanalyse von Twitter-Daten entfernst du HTML-Tags und Leerzeichen, schreibst Abkürzungen aus und zerlegst Tweets in Wortlisten.

\n

Zentrieren und Skalieren: Formen des Preprocessings für numerische Daten, also Zahlenwerte statt Kategorien oder Strings. Zentrieren heißt, vom jeweiligen Wert den Mittelwert abzuziehen, sodass der neue Mittelwert 0 ist. Skalieren heißt, jeden Wert mit einer Konstante zu multiplizieren, um den Wertebereich zu verändern. Warum das wichtig ist, zeigen Beispiele im Artikel.

\n
\n
\n
\n
\n
\n
\n

Dieser Artikel wurde aus einem Jupyter Notebook generiert. Du kannst das Notebook hier herunterladen.

\n
\n
\n
Themen
Python
Datenwissenschaft
Maschinelles Lernen