Weiter zum Inhalt

Anomalien mit Anomalize in R erkennen

Lerne, Anomalien in großen Zeitreihen-Datensätzen zu erkennen und Erkenntnisse deutlich einfacher zu präsentieren.
Aktualisiert 18. Sept. 2026  · 9 Min. lesen

Mit KI erkunden

ChatGPTClaudePerplexity

Anomalize: Kurzüberblick

Wenn wir von Anomalien sprechen, meinen wir Ausreißer oder außergewöhnliche Ereignisse in den Daten. In kleinen Datensätzen lassen sie sich leicht mit einfachen Visualisierungen wie Boxplots identifizieren. In großen Datensätzen, vor allem bei Zeitreihen, wird es jedoch schnell komplex. Eine Zeitreihe erfasst Daten in festen Intervallen über einen Zeitraum und zeigt bei der Analyse oft Trend- und Saisoneffekte. Anomalien in solchen Fällen zu erkennen, ist knifflig.

Hier setzt das Paket anomalize zur Anomalieerkennung in Zeitreihen an: ein tidy, zeitbasiertes Verfahren, das von einer bis zu vielen Zeitreihen skalierbar ist.

Es nutzt bestehende Pakete und Methoden und kombiniert diese zu einem skalierbaren Ansatz.

Diese Open-Source-Arbeiten haben dazu beigetragen:

  • Twitters AnomalyDetection-Paket: Verfügbar auf Github (cran anomalyDetection ist ein anderes Projekt).
  • Rob Hyndmans Funktion forecast::tsoutliers() aus dem Paket forecast.
  • Javier Lopez-de-lacalles Paket tsoutliers auf CRAN.

Alle diese Pakete und Funktionen fließen in einen skalierbaren Workflow ein.

Der Workflow von anomalize gliedert sich in drei Schritte:

  • Zeitreihenzerlegung mit time_decompose().
  • Anomalieerkennung im Restanteil mit anomalize().
  • Transformation der unteren und oberen Anomaliegrenzen mit time_recompose().

Workflow der Anomalieerkennung

Zerlegung der Zeitreihe

Der erste Schritt ist die Zerlegung der Zeitreihe mit time_decompose(). Der Messwert, auf dem die Erkennung für eine bestimmte Gruppe erfolgen soll, wird in vier Spalten zerlegt: observed, season, trend und remainder. Standardmäßig wird stl verwendet, eine saisonale Zerlegung mit Loess-Glättung.

Loess-Regression ist die gängigste Methode, um volatile Zeitreihen zu glätten. Sie passt in lokalen Nachbarschaften mehrere Regressionen an, sprich, die Daten werden in Abschnitte geteilt und jeweils regressiert. Das ist in Zeitreihen hilfreich, da die Zeit als X-Variable begrenzt ist. Diese Methode funktioniert gut, wenn der Trend die Saisonalität überwiegt.

Trend steht hier für langfristige Entwicklung über viele Beobachtungen, Saisonalität für wiederkehrende Muster, z. B. minütlich, stündlich oder wöchentlich.

Als zweite Technik zur saisonalen Zerlegung gibt es die auf Mediane basierende Twitter-Methode, die auch das Paket AnomalyDetection nutzt. Sie entfernt die saisonale Komponente wie STL. Der Unterschied liegt im Trend: Statt einer Glättung wird ein stückweiser Median der Daten (ein oder mehrere Mediansplits in festen Intervallen) verwendet. Diese Methode ist vorteilhaft, wenn die Saisonalität den Trend dominiert.

Zum Output von time_decompose(): Wie beschrieben entstehen vier Spalten:

  • observed: Die Ist-Werte.
  • season: Die saisonale bzw. zyklische Komponente. Standard ist wöchentliche Saisonalität.
  • trend: Der langfristige Trend. Standard ist eine Spanne von 3 Monaten.
  • remainder: Dient zur Ausreißeranalyse. Es ist einfach observed minus season und trend.

Die Funktion time_decompose() hat ein Argument merge. Mit TRUE bleibt der Originaldatensatz zusammen mit den erzeugten Spalten erhalten.

# Using data package provided in the anomalize package and taking single time series of package purrr

purrr_package = tidyverse_cran_downloads%>%
  filter(package == "purrr")%>%
  ungroup()

purrr_anomaly  = purrr_package %>%
  time_decompose(count)

purrr_anomaly%>% glimpse()
 ## Observations: 425
## Variables: 5
## $ date      <date> 2017-01-01, 2017-01-02, 2017-01-03, 2017-01-04, 201...
## $ observed  <dbl> 550, 1012, 1515, 1702, 1696, 1613, 860, 796, 2008, 2...
## $ season    <dbl> -2158.8893, 692.6571, 1087.5708, 1052.3294, 939.9377...
## $ trend     <dbl> 1496.712, 1511.009, 1525.307, 1539.604, 1553.901, 15...
## $ remainder <dbl> 1212.1777, -1191.6661, -1097.8773, -889.9334, -797.8...

Anomalien im Restanteil erkennen

Nach der Zerlegung und sobald der remainder die gewünschten Eigenschaften hat, wird die Anomalieerkennung durchgeführt. Dabei entstehen drei neue Spalten.

  • remainder_l1: Die Untergrenze des remainder.
  • remainder_l2: Die Obergrenze des remainder.
  • anomaly: Gibt an, ob eine Beobachtung eine Anomalie ist.

Anomalien sind Hebelpunkte mit starkem Einfluss, die die Verteilung verzerren. anomalize implementiert zwei robuste Methoden gegenüber solchen Punkten:

  • IQR: Interquartilsabstand
  • GESD: Generalized Extreme Studentized Deviate Test

IQR

Dieses Verfahren ähnelt der Methode in tsoutliers() aus dem forecast-Paket. Beim IQR wird die Verteilung anhand des 25%- und 75%-Quartils beschrieben. Standardmäßig werden die Grenzen mit dem Faktor 3 ober- und unterhalb des Interquartilsabstands gesetzt. Jeder remainder außerhalb dieser Grenzen gilt als Anomalie.

GESD

Bei GESD werden Anomalien schrittweise bewertet: Die stärksten Ausreißer werden entfernt und Teststatistik sowie kritische Werte neu berechnet. Vereinfacht: Nach jeder Identifikation wird der Bereich iterativ neu bestimmt.

Beide, IQR und GESD, haben Vor- und Nachteile. IQR ist schneller, da keine Schleifen nötig sind, aber weniger präzise als GESD, weil Ausreißer die Medianlage verzerren, was GESD gezielt adressiert.

purrr_anomaly = purrr_anomaly%>%
  anomalize(remainder)

purrr_anomaly%>% glimpse()
## Observations: 425
## Variables: 8
## $ date         <date> 2017-01-01, 2017-01-02, 2017-01-03, 2017-01-04, ...
## $ observed     <dbl> 550, 1012, 1515, 1702, 1696, 1613, 860, 796, 2008...
## $ season       <dbl> -2158.8893, 692.6571, 1087.5708, 1052.3294, 939.9...
## $ trend        <dbl> 1496.712, 1511.009, 1525.307, 1539.604, 1553.901,...
## $ remainder    <dbl> 1212.1777, -1191.6661, -1097.8773, -889.9334, -79...
## $ remainder_l1 <dbl> -4330.511, -4330.511, -4330.511, -4330.511, -4330...
## $ remainder_l2 <dbl> 4400.459, 4400.459, 4400.459, 4400.459, 4400.459,...
## $ anomaly      <chr> "No", "No", "No", "No", "No", "No", "No", "No", "...

Transformation der unteren und oberen Anomaliegrenzen

Im letzten Schritt werden mit time_recompose untere und obere Grenzen um die beobachteten Werte gelegt. Saison, Trend, remainder_l1 und remainder_l2 werden zu neuen Schranken rekombiniert:

  • recomposed_l1: Untere Grenze der Ausreißer um die beobachteten Werte.
  • recomposed_l2: Obere Grenze der Ausreißer um die beobachteten Werte.
purrr_anomaly = purrr_anomaly%>%
  time_recompose()

purrr_anomaly%>% glimpse()
## Observations: 425
## Variables: 10
## $ date          <date> 2017-01-01, 2017-01-02, 2017-01-03, 2017-01-04,...
## $ observed      <dbl> 550, 1012, 1515, 1702, 1696, 1613, 860, 796, 200...
## $ season        <dbl> -2158.8893, 692.6571, 1087.5708, 1052.3294, 939....
## $ trend         <dbl> 1496.712, 1511.009, 1525.307, 1539.604, 1553.901...
## $ remainder     <dbl> 1212.1777, -1191.6661, -1097.8773, -889.9334, -7...
## $ remainder_l1  <dbl> -4330.511, -4330.511, -4330.511, -4330.511, -433...
## $ remainder_l2  <dbl> 4400.459, 4400.459, 4400.459, 4400.459, 4400.459...
## $ anomaly       <chr> "No", "No", "No", "No", "No", "No", "No", "No", ...
## $ recomposed_l1 <dbl> -4992.689, -2126.845, -1717.634, -1738.578, -183...
## $ recomposed_l2 <dbl> 3738.281, 6604.125, 7013.336, 6992.392, 6894.298...

Anomalien visualisieren

purrr_anomaly%>%
  plot_anomaly_decomposition()+
  ggtitle("Plotting Anomalies")
plotting anomalies

Parameter-Feintuning

Ein Anomaliedetektor ist ohne Parametertuning unvollständig — und die passenden Werte hängen immer von den Daten ab.

Schauen wir uns die Parameter der drei Workflow-Ebenen an. Jede Ebene erfüllt eine eigene Aufgabe und hat entsprechend eigene Stellschrauben.

Parameter für die Zerlegung anpassen

Trend und Saisonalität sind die Grundlagen der Zeitreihenz­erlegung. Entsprechend solltest du in time_decompose Frequenz und Trend anpassen. Standardmäßig werden Werte automatisch gesetzt: 7 Tage Frequenz (für STL und Twitter), für den Trend 91 Tage bei STL und 85 Tage bei Twitter.

Du kannst beide oder einzelne Argumente anpassen. Beobachte die Effekte genau, sonst riskierst du Overfitting oder Underfitting der Zerlegung.

purrr_package %>%
  time_decompose(count, frequency = "auto", trend = "2 weeks")%>%
  anomalize(remainder)%>%
  plot_anomaly_decomposition()+
  ggtitle("Trend = 2 Weeks / Frequency = auto ")
time series

Parameter für die Anomalieerkennung anpassen

Wie oben beschrieben werden Anomalien anhand der remainder-Werte und daraus berechneter Grenzen bestimmt. Die Parameter alpha und max_anoms steuern die Funktion anomalize(). Vereinfacht gesagt bestimmt alpha die Breite des Intervalls. Standard ist 0,05. Ein kleineres alpha verbreitert das Band und macht es für Punkte schwieriger, als Anomalie zu gelten.

purrr_package%>%
  time_decompose(count)%>%
  anomalize(remainder, alpha = 0.05)%>%
  time_recompose()%>%
  plot_anomalies(time_recompose = T)+
  ggtitle("alpha = 0.05")
time series
purrr_package%>%
  time_decompose(count)%>%
  anomalize(remainder, alpha = 0.025)%>%
  time_recompose()%>%
  plot_anomalies(time_recompose = T)+
  ggtitle("alpha = 0.025")
time series

Der Parameter max_anoms steuert, welcher prozentuale Anteil der Daten als Anomalie markiert werden darf. Das ist hilfreich, wenn sich alpha schwer abstimmen lässt und du die auffälligsten Anomalien priorisieren willst.

purrr_package%>%
  time_decompose(count)%>%
  anomalize(remainder, alpha = 0.2, max_anoms = 0.2)%>%
  time_recompose()%>%
  plot_anomalies(time_recompose = T)+
  ggtitle("20% anomaly Allowed")
time series
purrr_package%>%
  time_decompose(count)%>%
  anomalize(remainder, alpha = 0.2, max_anoms = 0.05)%>%
  time_recompose()%>%
  plot_anomalies(time_recompose = T)+
  ggtitle("5% anomaly Allowed")
time series

Referenzen

Wenn du mehr über R lernen möchtest, schau dir den DataCamp-Kurs Introduction to Time Series Analysis an.

Sieh dir auch unser Time Series Analysis using R: Tutorial an.

Themen
R
Datenwissenschaft

R-Kurse

Kurs

Einführung in R

4 Std.
3.1M
Beherrsche die Grundlagen der Datenanalyse in R, einschließlich Vektoren, Listen und Datenrahmen, und übe R mit echten Datensätzen.
Details anzeigenRight Arrow
Kurs Starten
Mehr anzeigenRight Arrow
Verwandt

Tutorial

Fibonacci-Folge in Python: Lerne und entdecke Programmiertechniken

Finde raus, wie die Fibonacci-Folge funktioniert. Schau dir die mathematischen Eigenschaften und die Anwendungen in der echten Welt an.
Laiba Siddiqui's photo

Laiba Siddiqui

6 Min.

Tutorial

Python Datenstrukturen Tutorial

Mach dich mit Python-Datenstrukturen vertraut: Lerne mehr über Datentypen und primitive sowie nicht-primitive Datenstrukturen wie Strings, Listen, Stapel usw.
Sejal Jaiswal's photo

Sejal Jaiswal

24 Min.

Tutorial

Python-Arrays

Python-Arrays mit Code-Beispielen. Lerne noch heute, wie du mit Python NumPy Arrays erstellen und ausdrucken kannst!
DataCamp Team's photo

DataCamp Team

3 Min.

Tutorial

Python Switch Case Statement: Ein Leitfaden für Anfänger

Erforsche Pythons match-case: eine Anleitung zu seiner Syntax, Anwendungen in Data Science und ML sowie eine vergleichende Analyse mit dem traditionellen switch-case.
Matt Crabtree's photo

Matt Crabtree

5 Min.

Tutorial

Python-Tutorial zum Verknüpfen von Zeichenfolgen

Lerne verschiedene Methoden zum Verknüpfen von Zeichenfolgen in Python kennen, mit Beispielen, die jede Technik zeigen.
DataCamp Team's photo

DataCamp Team

5 Min.

Tutorial

Python NaN: 4 Möglichkeiten, um in Python nach fehlenden Werten zu suchen

Schau dir 4 Möglichkeiten an, wie du NaN-Werte in Python mit NumPy und Pandas erkennen kannst. Lerne die wichtigsten Unterschiede zwischen NaN und None kennen, um Daten effizient zu bereinigen und zu analysieren.
Adel Nehme's photo

Adel Nehme

5 Min.

Mehr AnzeigenMehr Anzeigen