: Das Mitternachtsparadoxon

Stellen Sie sich das vor. Sie erstellen ein Modell zur Vorhersage des Strombedarfs oder der Taxiabholung. Sie geben ihm additionally ab Mitternacht Zeit (z. B. Minuten) ein. Sauber und einfach. Rechts?

Jetzt sieht Ihr Modell 23:59 (Minute 1439 des Tages) Und 00:01 (Minute 1 des Tages). Für Sie liegen sie zwei Minuten auseinander. Für Ihr Modell sind sie sehr weit voneinander entfernt. Das ist das Mitternachtsparadoxon. Und ja, Ihr Modell ist wahrscheinlich zeitblind.

Warum passiert das?

Weil die meisten Modelle des maschinellen Lernens Zahlen als gerade Linien und nicht als Kreise behandeln.

Lineare Regression, KNN, SVMs und sogar neuronale Netze behandeln Zahlen logisch, vorausgesetzt, höhere Zahlen sind „mehr“ als niedrigere. Sie wissen nicht, dass die Zeit vergeht. Mitternacht ist der Grenzfall, den sie nie verzeihen.

Wenn Sie Ihrem Modell schon einmal erfolglos stündliche Informationen hinzugefügt haben und sich später fragen, warum Ihr Modell mit Tagesgrenzen zu kämpfen hat, ist dies wahrscheinlich der Grund.

Das Versagen der Standardkodierung

Lassen Sie uns über die üblichen Vorgehensweisen sprechen. Sie haben wahrscheinlich mindestens eines davon verwendet.

Sie kodieren Stunden als Zahlen von 0 bis 23. Jetzt gibt es eine künstliche Klippe zwischen Stunde 23 und Stunde 0. Daher geht dieses Modell davon aus, dass Mitternacht der größte Sprung des Tages ist. Unterscheidet sich Mitternacht jedoch wirklich stärker von 23:00 Uhr als 22:00 Uhr von 21:00 Uhr?

Natürlich nicht. Aber Ihr Modell weiß das nicht.

Hier ist die Stundendarstellung im „linearen“ Modus.

# Generate knowledge
date_today = pd.to_datetime('right now').normalize()
datetime_24_hours = pd.date_range(begin=date_today, intervals=24, freq='h')
df = pd.DataFrame({'dt': datetime_24_hours})
df('hour') = df('dt').dt.hour	

# Calculate Sin and Cosine
df("hour_sin") = np.sin(2 * np.pi * df("hour") / 24)
df("hour_cos") = np.cos(2 * np.pi * df("hour") / 24)

# Plot the Hours in Linear mode
plt.determine(figsize=(15, 5))
plt.plot(df('hour'), (1)*24, linewidth=3)
plt.title('Hours in Linear Mode')
plt.xlabel('Hour')
plt.xticks(np.arange(0, 24, 1))
plt.ylabel('Worth')
plt.present()
Stunden im linearen Modus. Bild vom Autor.

Was wäre, wenn wir die Stunden im One-Sizzling-Verfahren kodieren würden? Vierundzwanzig Binärspalten. Downside gelöst, oder? Nun ja… teilweise. Sie haben die künstliche Lücke repariert, aber die Nähe verloren. 2 Uhr morgens ist nicht mehr näher an 3 Uhr morgens als an 22 Uhr.
Sie haben auch die Dimensionalität explodiert. Für Bäume ist das ärgerlich. Für lineare Modelle ist es wahrscheinlich ineffizient.

Kommen wir additionally zu einer praktikablen Various.

  • Die Lösung: Trigonometrische Kartierung

Hier ist die Änderung der Denkweise:

Hören Sie auf, die Zeit als eine Linie zu betrachten. Betrachten Sie es als einen Kreis.

Ein 24-Stunden-Tag kehrt zu sich selbst zurück. Daher sollte auch Ihre Codierung eine Schleife bilden und im Kreis denken. Jede Stunde ist ein gleichmäßig verteilter Punkt auf einem Kreis. Um nun einen Punkt auf einem Kreis darzustellen, verwenden Sie nicht eine Zahl, sondern verwenden zwei Koordinaten: X Und j.

Hier kommen Sinus und Cosinus ins Spiel.

Die Geometrie dahinter

Jeder Winkel auf einem Kreis kann mithilfe von Sinus und Cosinus einem eindeutigen Punkt zugeordnet werden. Dadurch erhält Ihr Modell eine reibungslose, kontinuierliche Darstellung der Zeit.

plt.determine(figsize=(5, 5))
plt.scatter(df('hour_sin'), df('hour_cos'), linewidth=3)
plt.title('Hours in Cyclical Mode')
plt.xlabel('Hour')
Stunden im zyklischen Modus nach Sinus und Cosinus. Bild vom Autor.

Hier ist die mathematische Formel zur Berechnung der Zyklen für Stunden des Tages:

  • Erste, 2 * π * hour / 24 rechnet jede Stunde in einen Winkel um. Mitternacht und 23 Uhr landen quick an derselben Place im Kreis.
  • Dann Sinus Und Kosinus Projizieren Sie diesen Winkel in zwei Koordinaten.
  • Diese beiden Werte zusammen definieren eindeutig die Stunde. Jetzt sind 23:00 und 00:00 Uhr im Characteristic-Bereich nahe beieinander. Genau das, was Sie schon immer wollten.

Die gleiche Idee funktioniert für Minuten, Wochentage oder Monate im Jahr.

Code

Lassen Sie uns mit diesem Datensatz experimentieren Energieprognose für Haushaltsgeräte (4). Wir werden versuchen, die Vorhersage mithilfe eines Random Forest Regressor-Modells (einem baumbasierten Modell) zu verbessern.

Candanedo, L. (2017). Energieprognose für Haushaltsgeräte (Datensatz). UCI-Repository für maschinelles Lernen. https://doi.org/10.24432/C5VC8G. Artistic Commons 4.0-Lizenz.

# Imports
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import root_mean_squared_error
from ucimlrepo import fetch_ucirepo 

Holen Sie sich Daten.

# fetch dataset 
appliances_energy_prediction = fetch_ucirepo(id=374) 
  
# knowledge (as pandas dataframes) 
X = appliances_energy_prediction.knowledge.options 
y = appliances_energy_prediction.knowledge.targets 
  
# To Pandas
df = pd.concat((X, y), axis=1)
df('date') = df('date').apply(lambda x: x(:10) + ' ' + x(11:))
df('date') = pd.to_datetime(df('date'))
df('month') = df('date').dt.month
df('day') = df('date').dt.day
df('hour') = df('date').dt.hour
df.head(3)

Lassen Sie uns schnell ein Modell mit dem erstellen linear Zeit zuerst, als unsere Vergleichsbasis.

# X and y
# X = df.drop(('Home equipment', 'rv1', 'rv2', 'date'), axis=1)
X = df(('hour', 'day', 'T1', 'RH_1', 'T_out', 'Press_mm_hg', 'RH_out', 'Windspeed', 'Visibility', 'Tdewpoint'))
y = df('Home equipment')

# Practice Take a look at Cut up
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Match the mannequin
lr = RandomForestRegressor().match(X_train, y_train)

# Rating
print(f'Rating: {lr.rating(X_train, y_train)}')

# Take a look at RMSE
y_pred = lr.predict(X_test)
rmse = root_mean_squared_error(y_test, y_pred)
print(f'RMSE: {rmse}')

Die Ergebnisse gibt es hier.

Rating: 0.9395797670166536
RMSE: 63.60964667197874

Als nächstes kodieren wir die zyklischen Zeitkomponenten (day Und hour) und trainieren Sie das Modell neu.

# Add cyclical hours sin and cosine
df('hour_sin') = np.sin(2 * np.pi * df('hour') / 24)
df('hour_cos') = np.cos(2 * np.pi * df('hour') / 24)
df('day_sin') = np.sin(2 * np.pi * df('day') / 31)
df('day_cos') = np.cos(2 * np.pi * df('day') / 31)

# X and y
X = df(('hour_sin', 'hour_cos', 'day_sin', 'day_cos','T1', 'RH_1', 'T_out', 'Press_mm_hg', 'RH_out', 'Windspeed', 'Visibility', 'Tdewpoint'))
y = df('Home equipment')

# Practice Take a look at Cut up
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Match the mannequin
lr_cycle = RandomForestRegressor().match(X_train, y_train)

# Rating
print(f'Rating: {lr_cycle.rating(X_train, y_train)}')

# Take a look at RMSE
y_pred = lr_cycle.predict(X_test)
rmse = root_mean_squared_error(y_test, y_pred)
print(f'RMSE: {rmse}')

Und die Ergebnisse. Wir sehen eine Verbesserung um 1 % beim Rating und 1 Punkt beim RMSE.

Rating: 0.9416365489096074
RMSE: 62.87008070927842

Ich bin sicher, das sieht nicht nach viel aus, aber bedenken Sie, dass dieses Spielzeugbeispiel ein einfaches, sofort einsatzbereites Modell ohne jegliche Datenverarbeitung oder -bereinigung verwendet. Wir sehen hauptsächlich den Effekt der Sinus- und Kosinustransformation.

Was hier wirklich passiert, ist, dass der Strombedarf im wirklichen Leben nicht um Mitternacht zurückgeht. Und jetzt erkennt Ihr Modell endlich diese Kontinuität.

Warum Sie sowohl Sinus als auch Cosinus benötigen

Erliegen Sie nicht der Versuchung, etwas zu verwenden nur Sinusda es sich genug anfühlt. Eine Spalte statt zwei. Sauberer, oder?

Leider bricht es die Symmetrie. Im 24-Stunden-Format können 6 Uhr morgens und 18 Uhr abends denselben Sinuswert erzeugen. Unterschiedliche Zeiten bei identischer Kodierung können schlecht sein, da das Modell nun die morgendliche Hauptverkehrszeit mit der abendlichen Hauptverkehrszeit verwechselt. Daher nicht very best, es sei denn, Sie mögen verwirrende Vorhersagen.

Die Verwendung von Sinus und Cosinus behebt dieses Downside. Zusammen verleihen sie jeder Stunde einen einzigartigen Fingerabdruck auf dem Kreis. Stellen Sie sich das wie Breiten- und Längengrad vor. Sie brauchen beides, um zu wissen, wo Sie sind.

Auswirkungen und Ergebnisse in der Praxis

Hilft das additionally tatsächlich Fashions? Ja. Vor allem bestimmte.

Distanzbasierte Modelle

KNN und SVMs sind stark auf Entfernungsberechnungen angewiesen. Die zyklische Kodierung verhindert vorgetäuschte „große Distanzen“ an Grenzen. Ihre Nachbarn werden tatsächlich wieder Nachbarn.

Neuronale Netze

Neuronale Netze lernen schneller mit glatten Merkmalsräumen. Durch die zyklische Kodierung werden scharfe Diskontinuitäten um Mitternacht entfernt. Das bedeutet normalerweise eine schnellere Konvergenz und eine bessere Stabilität.

Baumbasierte Modelle

Gradient Boosted Timber wie XGBoost oder LightGBM können diese Muster schließlich lernen. Die zyklische Kodierung verschafft ihnen einen Vorsprung. Wenn Ihnen Leistung und Interpretierbarkeit wichtig sind, lohnt es sich.

7. Wann sollten Sie es verwenden?

Stellen Sie sich immer die Frage: Wiederholt sich diese Funktion in einem Zyklus? Wenn ja, ziehen Sie eine zyklische Codierung in Betracht.

Gängige Beispiele sind:

  • Stunde des Tages
  • Wochentag
  • Monat des Jahres
  • Windrichtung (Grad)
  • Wenn es eine Schleife gibt, können Sie versuchen, es wie eine Schleife zu kodieren.

Bevor Sie gehen

Zeit ist nicht nur eine Zahl. Es ist eine Koordinate auf einem Kreis.

Wenn Sie sie wie eine gerade Linie behandeln, kann Ihr Modell an Grenzen stoßen und es fällt Ihnen schwer, diese Variable als Zyklus zu verstehen, als etwas, das sich wiederholt und ein Muster aufweist.

Die zyklische Codierung mit Sinus und Cosinus behebt dieses Downside auf elegante Weise, indem die Nähe erhalten bleibt, Artefakte reduziert werden und Modelle schneller lernen.

Wenn Ihre Vorhersagen additionally das nächste Mal bei Tageswechseln seltsam aussehen, probieren Sie dieses neue Instrument aus, das Sie gelernt haben, und lassen Sie es Ihr Modell so erstrahlen, wie es sollte.

Wenn Ihnen dieser Inhalt gefallen hat, finden Sie mehr über meine Arbeit und meine Kontakte auf meiner Web site.

https://gustavorsantos.me

GitHub-Repository

Hier ist der gesamte Code dieser Übung.

https://github.com/gurezende/Time-Collection/tree/predominant/Sinepercent20Cosinepercent20Timepercent20Encode

Referenzen und weiterführende Literatur

(1. Codierungsstunden-Stack-Austausch): https://stats.stackexchange.com/questions/451295/encoding-symmetrical-feature-minutes-and-hours

(2. NumPy trigonometrische Funktionen): https://numpy.org/doc/steady/reference/routines.math.html

(3. Praktische Diskussion über zyklische Merkmale):
https://www.kaggle.com/code/avanwyk/encoding-symmetrical-features-for-deep-learning

(4. Energievorhersagedatensatz für Geräte) https://archive.ics.uci.edu/dataset/374/home equipment+power+prediction

Von admin

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert