Lücken in den Daten
Echte Preistabellen haben Lücken: Eine Aktie wurde an dem Tag nicht gehandelt, ein Feed hat eine Notierung verloren, ein Markt hatte Feiertag. pandas markiert sie als NaN („not a number“). Bevor Sie entscheiden, was zu tun ist, schauen Sie hin: df.isna() liefert eine Wahr/Falsch-Tabelle, .sum() zählt die Lücken je Spalte, und .mean() gibt ihren Anteil. Eine zu 40 % leere Spalte ist ein anderes Problem als eine, der ein einziger Wert fehlt.
import pandas as pd
nan = float("nan")
df = pd.DataFrame(
{"AAPL": [184.0, nan, 186.5, 187.0, nan], "MSFT": [410.0, 411.0, nan, nan, 415.0]},
index=pd.bdate_range("2026-03-02", periods=5),
)
print(df.isna().sum().to_dict()) # {'AAPL': 2, 'MSFT': 2} holes per column
print(df.isna().mean().round(2).to_dict()) # {'AAPL': 0.4, 'MSFT': 0.4} share of holesFortschreiben oder entfernen
Bei Preisen ist die natürliche Füllung der letzte bekannte Preis: Bis eine neue Notierung eintrifft, steht der Markt noch beim alten. Das ist ffill() (Vorwärtsfüllung). Eine lange Lücke bedeutet wohl veraltete Daten, daher füllt ffill(limit=2) höchstens zwei Tage in Folge. NaN ganz am Anfang bleiben NaN, weil es keinen früheren Preis zum Fortschreiben gibt. Die Alternative ist das Entfernen: dropna() löscht jede Zeile mit einer Lücke, und dropna(subset=["AAPL"]) betrachtet nur die Spalten, die Ihnen wichtig sind. Entfernen ist sicher, verkleinert aber die Daten und ändert die Abstände zwischen den Daten.
msft = df["MSFT"]
print(msft.ffill().tolist()) # [410.0, 411.0, 411.0, 411.0, 415.0]
print(msft.ffill(limit=1).tolist()) # [410.0, 411.0, 411.0, nan, 415.0] only one day carried
print(len(df.dropna())) # 1 only one row is complete
print(len(df.dropna(subset=["AAPL"]))) # 3 rows where AAPL is knownInterpolation und was man nie füllt
interpolate() füllt eine Lücke mit einer Geraden zwischen den bekannten Werten beiderseits. Es passt zu glatten Größen (Zinskurve, Volatilitätsniveau) und selten zu Preisen, die springen. Vorsicht an den Rändern: Standardmäßig kopiert interpolate() den letzten Wert auch in nachlaufende NaN, was Daten erfindet. limit_area="inside" beschränkt es auf Lücken zwischen zwei bekannten Werten. Füllen Sie nie blind mit 0: Ein Preis von 0 ist ein Crash, eine Rendite von 0 ein flacher Tag, und fillna(0) auf der falschen Tabelle verändert still jeden später berechneten Durchschnitt.
gappy = pd.Series([nan, nan, 10.0, nan, nan, 16.0, nan])
print(gappy.interpolate().tolist())
# [nan, nan, 10.0, 12.0, 14.0, 16.0, 16.0] the last 16.0 is invented
print(gappy.interpolate(limit_area="inside").tolist())
# [nan, nan, 10.0, 12.0, 14.0, 16.0, nan] only between known values# Filling with 0 is a decision, not a default: it changes the statistics
print(gappy.fillna(0).tolist()) # [0.0, 0.0, 10.0, 0.0, 0.0, 16.0, 0.0]
print(gappy.mean()) # 13.0 NaN are skipped
print(gappy.fillna(0).mean()) # 3.7142857142857144 the zeros drag the average downbfill() und interpolate() nutzen Werte nach der Lücke und verwenden damit am Datum der Lücke Informationen, die es noch nicht gab. In einem Backtest ist das Look-ahead-Bias. Verwenden Sie ffill() für alles, was eine Strategie in Echtzeit sieht, und heben Sie sich die Interpolation für die Bereinigung historischer Daten auf, die als Ganzes analysiert werden.df.isna().sum()zählt die Lücken je Spalte; schauen Sie sich die Daten an, bevor Sie über die Behandlung entscheiden.ffill(limit=n)schreibt den letzten bekannten Wert fort (die richtige Wahl für Preise);dropna(subset=...)entfernt unvollständige Zeilen.interpolate(limit_area="inside")überbrückt nur innere Lücken; füllen Sie nie aus Gewohnheit mit 0 oder mit der Zukunft.
Als Nächstes: Ausreißer erkennen, die vorhandenen Werte finden, die nicht stimmen können.
Lab: Was bewertet wird
- Mit
count_missingdie Lücken jeder Spalte zählen25 Pkt. - Mit
forward_fillden letzten Preis fortschreiben25 Pkt. - Mit
complete_rowsnur die verlässlichen Zeilen behalten25 Pkt. - Mit
fill_gapsdie Lücken innerhalb der Daten überbrücken25 Pkt.