Weiter zum Inhalt

Explorative Datenanalyse von Craft Beers: Datenprofiling

In diesem Tutorial lernst du EDA in Python kennen – und speziell Datenprofiling mit pandas.
Aktualisiert 18. Sept. 2026  · 14 Min. lesen

Mit KI erkunden

ChatGPTClaudePerplexity

Hinweis der Redaktion: Jean-Nicholas Hould ist Data Scientist bei Intel Security in Montreal und zeigt auf seinem Blog, wie du mit Data Science durchstartest.

Explorative Datenanalyse (EDA) ist ein statistischer Ansatz, um einen Datensatz zu erkunden und zusammenzufassen. In diesem Schritt des Data-Science-Prozesses willst du die Struktur deines Datensatzes, die Variablen und ihre Beziehungen verstehen.

In diesem Beitrag konzentrierst du dich auf einen Aspekt der explorativen Datenanalyse: Datenprofiling.

Beim Datenprofiling geht es darum, deinen Datensatz anhand beschreibender Statistiken zusammenzufassen. Du nutzt eine Reihe von Kennzahlen, um dein Dataset besser zu verstehen. Datentypen, fehlende Werte, Mittelwert, Median und Standardabweichung sind nur einige der Elemente, die du beim Profiling erfassen solltest. Ziel des Datenprofilings ist ein belastbares Verständnis deiner Daten, damit du anschließend gezielt Abfragen stellen und Visualisierungen in verschiedenen Varianten erstellen kannst.

Woher stammen deine Daten?

Bevor du in eine EDA einsteigst, solltest du so viel wie möglich über die Herkunft der analysierten Daten wissen. Verstehe, wie die Daten erhoben und wie sie aufbereitet wurden. Gab es frühere Transformationen, die deine Analyse beeinflussen könnten?

Auf diese Fragen solltest du für deinen Datensatz eine Antwort haben:

  • Wie wurden die Daten erhoben?
  • Handelt es sich um eine Stichprobe?
  • Wurde korrekt gesampelt?
  • Wurde der Datensatz in irgendeiner Form transformiert?
  • Sind bekannte Probleme mit dem Datensatz dokumentiert?

Wenn du die Herkunft der Daten nicht verstehst, fällt es schwer, belastbare Schlüsse zu ziehen. Außerdem riskierst du gravierende Analysefehler.

Zusätzlich solltest du sicherstellen, dass der Datensatz in einem standardisierten Format strukturiert ist. Empfohlen wird die Third Normal Form, auch tidy data genannt. Ein „tidy“ Datensatz hat folgende Eigenschaften:

  • Jede Variable bildet eine Spalte und enthält Werte
  • Jede Beobachtung bildet eine Zeile
  • Jeder Typ von Beobachtungseinheit bildet eine Tabelle

Dieses Standardformat beschleunigt deine Analyse, da es mit vielen Tools und Bibliotheken kompatibel ist.

Datenprofiling

In diesem Beitrag nutzt du einen Datensatz zu Craft-Beers von der Website CraftCans. Der Datensatz enthält ausschließlich Daten zu dosenbier aus Brauereien in den USA. Aus der Website geht nicht klar hervor, ob wirklich jedes Dosenbier in den USA erfasst wurde. Zur Sicherheit betrachten wir den Datensatz als Stichprobe, die Verzerrungen enthalten kann.

So sind die Datensätze aufgebaut, die du verwendest:

Beers:

  • ID: Eindeutige Kennung des Biers.
  • Name: Name des Biers.
  • ABV: Alkoholgehalt in Volumenprozent.
  • IBU: International Bitterness Units des Biers.
  • Style: Bierstil.
  • Ounces: Füllmenge in Unzen.

Breweries:

  • ID: Eindeutige Kennung der Brauerei.
  • Name: Name der Brauerei.
  • City: Stadt, in der die Brauerei liegt.
  • State: Bundesstaat, in dem die Brauerei liegt.

Datentypen

Der erste Schritt ist, die Zusammensetzung deines Datensatzes zu verstehen.

Mit welchen Variablen hast du es zu tun?

In der Regel lassen sich Daten in folgende Kategorien einordnen:

  • Numerisch
  • Kategorisch
  • Text
  • Datum

Zunächst importierst du die Datensätze aus diesem Repository mit der pandas-Funktion from_csv. Außerdem verbindest du die Datensätze beers und breweries, um die spätere Analyse zu erleichtern.

import pandas as pd

beers = pd.DataFrame.from_csv("https://raw.githubusercontent.com/nickhould/craft-beers-dataset/master/data/craftcans_beers.csv")
breweries = pd.DataFrame.from_csv("https://raw.githubusercontent.com/nickhould/craft-beers-dataset/master/data/craftcans_breweries.csv")

beers_and_breweries = pd.merge(beers, 
                               breweries, 
                               how='inner', 
                               left_on="brewery_id", 
                               right_on="id", 
                               sort=True,
                               suffixes=('_beer', '_brewery'))

Mit pandas kannst du die Funktion dtypes ausführen, um jede Spalte und ihren Datentyp aufzulisten.

beers.dtypes

Das liefert dir folgendes Ergebnis:

abv           float64
ibu           float64
id              int64
name           object
style          object
brewery_id      int64
ounces        float64
dtype: object

Wie du siehst, gruppiert diese Funktion die verschiedenen Datentypen nicht übersichtlich. Die numerischen Typen (float64 und int64) werden nicht zu einer Kategorie zusammengefasst, wie wir es uns wünschen würden. Außerdem sind einige Spalten als Objekte gelistet – das ist wenig aussagekräftig.

Um das zu umgehen, kannst du eine eigene Funktion schreiben, die die Kategorie jeder Spalte in einem DataFrame bestimmt.

def get_var_category(series):
    unique_count = series.nunique(dropna=False)
    total_count = len(series)
    if pd.api.types.is_numeric_dtype(series):
        return 'Numerical'
    elif pd.api.types.is_datetime64_dtype(series):
        return 'Date'
    elif unique_count==total_count:
        return 'Text (Unique)'
    else:
        return 'Categorical'

def print_categories(df):
    for column_name in df.columns:
        print(column_name, ": ", get_var_category(df[column_name]))

Beers-Variablen

print_categories(beers)

Der Befehl oben liefert dir folgendes Ergebnis:

abv :  Numerical
ibu :  Numerical
id :  Numerical
name :  Categorical
style :  Categorical
brewery_id :  Numerical
ounces :  Numerical

Breweries-Variablen

print_categories(breweries)

Das ergibt folgendes:

name :  Categorical
city :  Categorical
state :  Categorical
id :  Numerical

Mit diesen Informationen verstehst du den Datensatz bereits besser. Du weißt, dass du nur mit kategorischen und numerischen Daten arbeitest. Numerische Variablen erlauben viele Kennzahlen wie Mittelwert, Standardabweichung usw. Kategorische Variablen eignen sich in der Regel gut zur Segmentierung und Gruppierung der Daten. Du könntest zum Beispiel untersuchen, wie sich die IBU je nach Bierstil unterscheiden.

Beschreibende Statistiken

In diesem Abschnitt gehst du verschiedene beschreibende Statistiken durch, um die Daten besser zu verstehen. Jede Kennzahl für sich ist nur bedingt hilfreich – die Kombination liefert den größten Erkenntnisgewinn.

Du konzentrierst dich auf die Variable IBU, weil sie numerisch ist. Dieser Variablentyp bietet mehr Auswertungsmöglichkeiten als kategorische Variablen. Auch auf Kategorisches kannst du Kennzahlen anwenden, bist dort aber deutlich eingeschränkter.

Länge

Die Funktion len zählt die Anzahl der Beobachtungen in einer Series. Sie zählt alle Beobachtungen, unabhängig von fehlenden bzw. Null-Werten.

length = len(beers["ibu"])
print(length)

Diese Series umfasst insgesamt 2410 Beobachtungen.

Anzahl

Die Funktion count gibt die Anzahl der nicht-NA/nicht-null Beobachtungen in einer Series zurück.

count = beers["ibu"].count()
print(count)

Wie du siehst, gibt es 1405 nicht-leere Beobachtungen in der Series.

Fehlende Werte

Mit Length und Count kannst du nun die Anzahl fehlender Werte berechnen. Sie ist die Differenz aus Length und Count.

number_of_missing_values = length - count
pct_of_missing_values = float(number_of_missing_values / length)
pct_of_missing_values = "{0:.1f}%".format(pct_of_missing_values*100)
print(pct_of_missing_values)

Um fehlende Werte als Prozentsatz auszugeben, teilst du die Anzahl fehlender Werte durch die Gesamtzahl der Beobachtungen, also die Länge. float stellt sicher, dass Dezimalstellen in der Division berücksichtigt werden. Mit format formatierst du den Wert ansprechend als Prozentzahl.

In diesem Fall fehlen fast 42% der IBU-Werte. Das ist wichtig, weil es deine Analyse beeinflusst. Die meisten beschreibenden Statistiken ignorieren fehlende Werte – das führt zwangsläufig zu Verzerrungen.

Minimum/Maximum

Minimal- und Maximalwert eines Datensatzes erhältst du mit den Funktionen min und max auf einer Series.

print("Minimum value: ", beers["ibu"].min())
print("Maximum value: ", beers["ibu"].max())

Min/Max helfen, die Spannweite einer Variable zu verstehen. Hier reicht IBU von 4 bis 138.

Modus

Der Modus ist der am häufigsten auftretende Wert in einem Datensatz. Er lässt sich mit der Funktion mode auf einer Series bestimmen.

print(beers["ibu"].mode())

In einer Normalverteilung entspricht der Modus dem mean und dem median.

Hier ist der Modus der Variable IBU gleich 20. Das ist der häufigste IBU-Wert im Datensatz.

Mittelwert

Der Mittelwert ist ein Maß der zentralen Tendenz. Er ist die Summe aller Werte geteilt durch die Anzahl nicht fehlender Beobachtungen.

Er lässt sich mit der Funktion mean auf einer Series berechnen.

mean = beers["ibu"].mean()

Der Mittelwert ist anfällig für Ausreißer. Einige extreme Werte können ihn stark nach oben oder unten ziehen.

Median

Auch der Median ist ein Maß der zentralen Tendenz. Er ist der Wert genau in der Mitte einer geordneten Liste numerischer Werte.

median = beers["ibu"].median()

Bei schiefen Verteilungen ist der Median oft das bessere Lagemaß als der Mittelwert.

Bei der Verteilung von IBU liegen Mittelwert und Median in derselben Größenordnung.

Standardabweichung

Die Standardabweichung ist ein Streuungsmaß. Eine hohe Standardabweichung zeigt, dass die Daten über einen weiten Wertebereich verteilt sind. Sie hat dieselbe Einheit wie die Werte selbst.

standarddev = beers["ibu"].std()

Hier beträgt die Standardabweichung rund 26 – genau 25.954065911259324. Wäre die Verteilung von IBU normalverteilt, lägen etwa 68% der Beobachtungen innerhalb einer Standardabweichung um den Mittelwert.

Quantile

Quantile sind Schnittpunkte, die eine Verteilung in gleich große Teile teilen. Viele Quantile haben eigene Namen. Teilt man eine Verteilung in vier gleich große Gruppen, spricht man von quartiles. Du kannst Quantile mit der Funktion quantile auf einer Series berechnen. Übergebe dazu ein Array der gewünschten Quantile. Im Beispiel unten teilen wir die Verteilung in vier gleich große Gruppen.

quantile = beers["ibu"].quantile([.25, .5, .75])
0.25 21.0
0.50 35.0
0.75 64.0
Name: ibu, dtype: float64

Wie du siehst, entspricht das 50%-Quantil dem Median. Es ist der Wert, der den Datensatz halbiert. Außerdem liegen 75% der Beobachtungen bei höchstens 64 IBU. 50% der Verteilung liegen zwischen 21 und 64 IBU. Beachte: Fehlende Werte gehen in diese Kennzahlen nicht ein.

Verteilungsdiagramme

Visualisierungen sind in der explorativen Datenanalyse extrem hilfreich. In diesem Beitrag vertiefen wir das Thema Visualisierung nicht, aber ohne die Bedeutung eines Häufigkeitsdiagramms geht es beim Datenprofiling nicht. Es ist eine der einfachsten und gleichzeitig aussagekräftigsten Visualisierungen und zeigt, wie oft jeder Wert im Datensatz vorkommt.

Für diese Visualisierung nutzen wir die Bibliothek seaborn`` mit der Funktion displot. Diese Funktion erwartet eine Series ohne fehlende Werte.

import seaborn as sns
sns.set(color_codes=True)
sns.set_palette(sns.color_palette("muted"))

sns.distplot(beers["ibu"].dropna());

distribution plot

In diesem Verteilungsdiagramm erkennst du einige der zuvor berechneten Werte deutlich. Der Minimalwert liegt nahe bei 0 IBU, der Maximalwert nahe bei 140 IBU. Der häufigste Wert liegt klar bei rund 20 IBU. Zusätzlich sehen wir einen Peak bei etwa 60 IBU.

Warum gibt es zwei Peaks in dieser Verteilung?

Wodurch lässt sich das erklären? Das ist ein Aspekt für die zweite Phase der explorativen Datenanalyse.

Korrelationen

Korrelationen helfen, Beziehungen zwischen numerischen Variablen aufzudecken. Es gibt verschiedene Verfahren zur Berechnung der Korrelation. Der Pearson-Korrelationskoeffizient ist weit verbreitet und misst die lineare Abhängigkeit zwischen zwei Variablen. Er liegt zwischen -1 und 1: 1 bedeutet perfekte positive, -1 perfekte negative und 0 keine lineare Korrelation. Wir können diese Berechnung mit der Funktion corr auf einer Series durchführen. Standardmäßig wird die Pearson-Korrelation verwendet, du kannst aber auch andere Methoden angeben.

beers[["abv", "ibu", "ounces"]].corr()
  abv ibu ounces
abv 1 0.670621 0.172529
ibu 0.670621 1 0.054691
ounces 0.172529 0.054691 1

Wie erwartet, ist die Korrelation von IBU mit sich selbst 1. Interessanter ist, dass die Korrelation zwischen ABV und IBU 0.670621 beträgt. Das ist zwar keine perfekte, aber eine starke positive Korrelation – ein spannender Punkt für eine vertiefte Analyse.

Ein paar Hinweise zu nicht-numerischen Variablen

Die bisher betrachteten Kennzahlen gelten vor allem für numerische Werte. Bei anderen Datentypen wie kategorischen Daten kannst du dennoch interessante Größen berechnen, zum Beispiel die Häufigkeit einzelner Ausprägungen.

DataFrame-Objekte haben eine Funktion describe, die den Datensatz zusammenfasst. Besteht dein DataFrame nur aus kategorischen oder Textwerten, passt sich die Zusammenfassung entsprechend an.

beers[["name", "style"]].describe()
  name style
count 2410 2405
unique 2305 99
top Nonstop Hef Hop American IPA
freq 12 424

Profiling-Bibliotheken

Wie du gesehen hast, kann das Sammeln beschreibender Statistiken mühsam sein. Zum Glück gibt es Bibliotheken, die diese Arbeit abnehmen und ein klares Datenprofil ausgeben. pandas-profiling ist eine davon. Diese Bibliothek bietet statistisches Profiling deines Datensatzes out of the box. Da unser Datensatz tidy und standardisiert ist, können wir die Bibliothek direkt darauf anwenden.

import pandas_profiling 

pandas_profiling.ProfileReport(beers_and_breweries)

Weitere Fragen

Nach dem Profiling deines Datensatzes hast du in der Regel mehr Fragen als zuvor. Perfekt – genau diese Fragen treiben deine explorative Datenanalyse an.

Hier sind einige Fragen, die beim Profiling aufgekommen sind:

  • 41,7% der IBU-Werte fehlen. Warum? Wie beeinflusst das unsere Analyse?
  • Die IBU-Verteilung zeigt zwei Peaks. Was erklärt das?
  • Wodurch erklärt sich die Korrelation zwischen IBU und ABV? Welchen Einfluss hat der Bierstil auf diese Korrelation?
  • Gibt es Unterschiede bei IBU, ABV oder Style zwischen Regionen? Und wie sieht es an der Ost- vs. Westküste aus?

Datenprofiling ist kein linearer Prozess. Wenn du deinen Datensatz filterst und segmentierst, wirst du immer wieder darauf zurückkommen und beschreibende Statistiken für Untergruppen ermitteln.

Nächste Schritte

In diesem Beitrag hast du gesehen, wie man einen Datensatz profiliert. Du weißt nun, wie du Variablen bestimmten Datentyp-Gruppen zuordnest. Außerdem hast du verschiedene beschreibende Statistiken berechnet und weißt, wie du sie interpretierst. Und du kennst Bibliotheken, die dir beim Profiling die Rechenarbeit abnehmen. Vor allem aber hast du neue Fragen generiert, die deine explorative Datenanalyse voranbringen.

Sieh dir DataCamps Python Exploratory Data Analysis Tutorial an.

Themen
Datenanalyse
Datenwissenschaft
Python

Erfahre mehr über Python

Kurs

Bayesianische Datenanalyse in Python

4 Std.
16.1K
Lerne alles über die Vorteile der Bayesschen Datenanalyse und probier sie in verschiedenen echten Anwendungsfällen aus!
Details anzeigenRight Arrow
Kurs Starten
Mehr anzeigenRight Arrow