{"id":573886,"date":"2025-06-10T07:56:11","date_gmt":"2025-06-10T06:56:11","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=pycharm&#038;p=573886"},"modified":"2025-06-10T07:56:20","modified_gmt":"2025-06-10T06:56:20","slug":"anomalieerkennung-in-zeitreihen","status":"publish","type":"pycharm","link":"https:\/\/blog.jetbrains.com\/de\/pycharm\/2025\/06\/anomalieerkennung-in-zeitreihen\/","title":{"rendered":"Anomalieerkennung in Zeitreihen"},"content":{"rendered":"<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539495\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/06\/PC-social-BlogFeatured-1280x720-2x-13.png\" alt=\"Anomalieerkennung in Zeitreihen\" width=\"2560\" height=\"1440\" \/><\/figure>\n<p>Wie erkennen Sie ungew\u00f6hnliche Muster in Daten, die kritische Probleme oder verborgene Chancen aufzeigen k\u00f6nnten? Die <a href=\"https:\/\/blog.jetbrains.com\/pycharm\/2025\/01\/anomaly-detection-in-machine-learning\/\" data-type=\"link\" data-id=\"https:\/\/blog.jetbrains.com\/pycharm\/2025\/01\/anomaly-detection-in-machine-learning\/\">Anomalieerkennung<\/a> hilft bei der Identifizierung von Daten, die erheblich von der Norm abweichen. Zeitreihendaten, die aus Daten bestehen, welche im Laufe der Zeit gesammelt wurden, beinhalten oft Trends und saisonale Muster. Anomalien in Zeitreihendaten treten auf, wenn diese Muster unterbrochen werden. Dies macht die Anomalieerkennung zu einem wertvollen Tool in zahlreichen Branchen, z. B. Vertrieb, Finanzen, Fertigung und Gesundheitswesen.<\/p>\n<p>Da Zeitreihendaten einzigartige Merkmale wie Saisonalit\u00e4t und Trends aufweisen, sind spezielle Methoden erforderlich, um Anomalien effektiv zu erkennen. In diesem Blogbeitrag stellen wir Ihnen einige beliebte Methoden zur Anomalieerkennung in Zeitreihen vor, darunter STL-Zerlegung und LSTM-Vorhersage \u2013 samt detaillierten Codebeispielen, um Ihnen den Einstieg zu erleichtern.<\/p>\n<h2 class=\"wp-block-heading\">Zeitreihen-Anomalieerkennung in Unternehmen<\/h2>\n<p>Zeitreihendaten sind f\u00fcr viele Unternehmen und Dienstleistungen unerl\u00e4sslich. Zahlreiche Unternehmen halten Daten im Laufe der Zeit mit Zeitstempeln fest. Das erm\u00f6glicht es, Ver\u00e4nderungen zu analysieren und Daten im Zeitverlauf zu vergleichen. Zeitreihen sind n\u00fctzlich, wenn Sie eine bestimmte Menge \u00fcber einen gewissen Zeitraum hinweg vergleichen, z. B. bei einem Jahresvergleich, im Rahmen dessen die Daten Merkmale von Saisonalit\u00e4ten aufweisen.<\/p>\n<p><strong>Umsatz\u00fcberwachung<\/strong><\/p>\n<p>Eines der h\u00e4ufigsten Beispiele f\u00fcr Zeitreihendaten mit Saisonalit\u00e4t sind Umsatzdaten. Da viele Verk\u00e4ufe von den j\u00e4hrlichen Feiertagen und der Jahreszeit beeinflusst werden, ist es schwierig, R\u00fcckschl\u00fcsse auf die Umsatzdaten zu ziehen, ohne die Saisonalit\u00e4t zu ber\u00fccksichtigen. Aus diesem Grund ist eine g\u00e4ngige Methode zur Analyse und Anomalieerkennung in Umsatzdaten die STL-Zerlegung, die wir <a href=\"https:\/\/blog.jetbrains.com\/pycharm\/2025\/01\/anomaly-detection-in-time-series\/#stl-beehive\" data-type=\"link\" data-id=\"https:\/\/blog.jetbrains.com\/pycharm\/2025\/01\/anomaly-detection-in-time-series\/#stl-beehive\">sp\u00e4ter in diesem Blogbeitrag<\/a> ausf\u00fchrlich behandeln werden.<\/p>\n<p><strong>Finanzen<\/strong><\/p>\n<p>Finanzdaten, etwa Transaktionen und Aktienkurse, sind typische Beispiele f\u00fcr Zeitreihendaten. In der Finanzbranche ist die Analyse und Anomalieerkennung in Bezug auf diese Daten eine g\u00e4ngige Praxis. Zeitreihen-Vorhersagemodelle k\u00f6nnen zum Beispiel beim automatischen Handel eingesetzt werden. Wir werden <a href=\"https:\/\/blog.jetbrains.com\/pycharm\/2025\/01\/anomaly-detection-in-time-series\/#lstm-stock\" data-type=\"link\" data-id=\"https:\/\/blog.jetbrains.com\/pycharm\/2025\/01\/anomaly-detection-in-time-series\/#lstm-stock\">sp\u00e4ter in diesem Blogbeitrag<\/a> eine Zeitreihenvorhersage verwenden, um Anomalien in Aktiendaten zu identifizieren.<\/p>\n<p><strong>Verarbeitendes Gewerbe \/ Fertigungsindustrie<\/strong><\/p>\n<p>Ein weiterer Anwendungsfall f\u00fcr die Erkennung von Anomalien in Zeitreihen ist die \u00dcberwachung von Defekten in Produktionslinien. Maschinen fungieren h\u00e4ufig als \u00dcberwachungsger\u00e4te, die Zeitreihendaten bereitstellen. Die M\u00f6glichkeit, das Management \u00fcber m\u00f6gliche Ausf\u00e4lle zu informieren, ist von entscheidender Bedeutung, und die Anomalieerkennung spielt dabei eine Schl\u00fcsselrolle.<\/p>\n<p><strong>Medizin und Gesundheitswesen<\/strong><\/p>\n<p>In der Medizin und im Gesundheitswesen werden die menschlichen Vitalfunktionen \u00fcberwacht und Anomalien k\u00f6nnen erkannt werden. Das ist in der medizinischen Forschung wichtig, aber in der Diagnostik entscheidend. Wenn ein Patient in einem Krankenhaus Anomalien in Bezug auf seine Vitalfunktionen aufweist und nicht sofort behandelt wird, kann das t\u00f6dlich enden.<\/p>\n<h2 class=\"wp-block-heading\">Warum ist es wichtig, spezielle Methoden zur Anomalieerkennung bei Zeitreihen zu verwenden?<\/h2>\n<p>Zeitreihendaten sind besonders, da sie manchmal anders behandelt werden m\u00fcssen als andere Datentypen. Wenn wir zum Beispiel einen Train-Test-Split auf Zeitreihendaten anwenden, d\u00fcrfen wir die Daten aufgrund ihrer sequenziellen Verkn\u00fcpfung nicht mischen. Dies gilt auch f\u00fcr die Anwendung von Zeitreihendaten auf ein Deep-Learning-Modell. Ein rekurrentes neuronales Netz (RNN) wird \u00fcblicherweise verwendet, um die sequenzielle Verkn\u00fcpfung zu ber\u00fccksichtigen. Die Trainingsdaten werden als Zeitfenster eingegeben, in denen die Abfolge der Ereignisse erhalten bleibt.<\/p>\n<p>Zeitreihendaten sind auch deshalb etwas Besonderes, weil sie oft Saisonalit\u00e4t und Trends aufweisen, die wir nicht ignorieren d\u00fcrfen. Diese Saisonalit\u00e4t kann sich mitunter in einem 24-Stunden-Zyklus, einem 7-Tage-Zyklus oder einem 12-Monats-Zyklus manifestieren. Anomalien k\u00f6nnen erst bestimmt werden, nachdem die Saisonalit\u00e4t und die Trends ber\u00fccksichtigt wurden, wie Sie in <a href=\"https:\/\/blog.jetbrains.com\/pycharm\/2025\/01\/anomaly-detection-in-time-series\/#stl-beehive\" data-type=\"link\" data-id=\"https:\/\/blog.jetbrains.com\/pycharm\/2025\/01\/anomaly-detection-in-time-series\/#stl-beehive\">unserem Beispiel unten<\/a> sehen werden.<\/p>\n<h2 class=\"wp-block-heading\">Methoden zur Anomalieerkennung in Zeitreihen<\/h2>\n<p>Da Zeitreihendaten etwas Besonderes sind, gibt es spezielle Methoden, um Anomalien in ihnen zu erkennen. Je nach Art der Daten k\u00f6nnen einige der Methoden und Algorithmen, die wir im vorherigen <a href=\"https:\/\/blog.jetbrains.com\/pycharm\/2025\/01\/anomaly-detection-in-machine-learning\/\" data-type=\"link\" data-id=\"https:\/\/blog.jetbrains.com\/pycharm\/2025\/01\/anomaly-detection-in-machine-learning\/\">Blogbeitrag zur Anomalieerkennung<\/a> erw\u00e4hnt haben, auf Zeitreihendaten angewendet werden. Bei diesen Methoden ist die Anomalieerkennung jedoch m\u00f6glicherweise nicht so zuverl\u00e4ssig wie bei Ans\u00e4tzen, die speziell f\u00fcr Zeitreihendaten entwickelt wurden. In einigen F\u00e4llen kann eine Kombination von Erkennungsmethoden verwendet werden, um das Ergebnis zu best\u00e4tigen und Irrt\u00fcmer zu vermeiden.<\/p>\n<h3 class=\"wp-block-heading\">STL-Zerlegung<\/h3>\n<p>Eine der beliebtesten Methoden zur Verwendung von Zeitreihendaten, die Saisonalit\u00e4t aufweisen, ist die STL-Zerlegung \u2013 die Zerlegung saisonaler Trends unter Verwendung von LOESS (lokal gesch\u00e4tzte Streudiagramm-Gl\u00e4ttung). Bei dieser Methode wird eine Zeitreihe unter Verwendung einer Sch\u00e4tzung der Saisonalit\u00e4t (mit der bereitgestellten oder mit einem Algorithmus bestimmten Periode), eines (gesch\u00e4tzten) Trends und des Restwerts (das Rauschen in den Daten) zerlegt. Eine <a href=\"https:\/\/www.jetbrains.com\/help\/pycharm\/python.html\" target=\"_blank\" rel=\"noopener\">Python<\/a>-Bibliothek, die <a href=\"https:\/\/www.statsmodels.org\/stable\/examples\/notebooks\/generated\/stl_decomposition.html\" target=\"_blank\" rel=\"noopener\">STL-Zerlegungstools<\/a> bereitstellt, ist <a href=\"https:\/\/www.statsmodels.org\/stable\/index.html\" target=\"_blank\" rel=\"noopener\">statsmodels<\/a>.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539263\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/image-70.png\" alt=\"STL-Zerlegung\" width=\"1600\" height=\"900\" \/><\/figure>\n<p>Eine Anomalie wird erkannt, wenn der Restwert \u00fcber einem bestimmten Schwellenwert liegt.<\/p>\n<h3 id=\"stl-beehive\" class=\"wp-block-heading\">Verwendung von STL-Zerlegung bei Bienenstockdaten<\/h3>\n<p>In einem fr\u00fcheren <a href=\"https:\/\/blog.jetbrains.com\/pycharm\/2025\/01\/anomaly-detection-in-machine-learning\/\" data-type=\"link\" data-id=\"https:\/\/blog.jetbrains.com\/pycharm\/2025\/01\/anomaly-detection-in-machine-learning\/\">Blogbeitrag<\/a> haben wir die Anomalieerkennung in Bienenst\u00f6cken mithilfe der Methoden <a href=\"https:\/\/scikit-learn.org\/stable\/modules\/generated\/sklearn.svm.OneClassSVM.html\" target=\"_blank\" rel=\"noopener\">OneClassSVM<\/a> und <a href=\"https:\/\/scikit-learn.org\/stable\/modules\/generated\/sklearn.ensemble.IsolationForest.html\" target=\"_blank\" rel=\"noopener\">IsolationForest<\/a> untersucht.<\/p>\n<p>In diesem Tutorial werden wir <a href=\"https:\/\/www.kaggle.com\/datasets\/vivovinco\/beehives\" target=\"_blank\" rel=\"noopener\">Bienenstockdaten<\/a> als Zeitreihe analysieren. Dazu verwenden wir die <code>STL<\/code>-Klasse, die von der statsmodels-Bibliothek bereitgestellt wird. Um zu beginnen, richten Sie Ihre Umgebung mit dieser Datei ein: <a href=\"https:\/\/github.com\/Cheukting\/anomaly-detection\/blob\/main\/requirements.txt\" target=\"_blank\" rel=\"noopener\">requirements.txt<\/a>.<\/p>\n<h4 class=\"wp-block-heading\"><strong>1. Bibliothek installieren<\/strong><\/h4>\n<p>Da wir nur das von Scikit-learn bereitgestellte Modell verwendet haben, m\u00fcssen wir statsmodels von PyPI installieren. Dies ist in <a href=\"https:\/\/www.jetbrains.com\/de-de\/pycharm\/data-science\/\" target=\"_blank\" rel=\"noreferrer noopener\">PyCharm<\/a> leicht zu bewerkstelligen.<\/p>\n<div class=\"buttons\">\n<div class=\"buttons__row\"><a class=\"btn\" href=\"https:\/\/www.jetbrains.com\/de-de\/pycharm\/data-science\/\" target=\"\" rel=\"noopener\">Starten Sie mit PyCharm Pro kostenlos durch<\/a><\/div>\n<\/div>\n<p>Rufen Sie das Fenster <em>Python <\/em><a href=\"https:\/\/www.jetbrains.com\/help\/pycharm\/installing-uninstalling-and-upgrading-packages.html\" target=\"_blank\" rel=\"noopener\"><em>Package<\/em> <\/a>auf (w\u00e4hlen Sie das Symbol unten links in der IDE aus) und geben Sie statsmodels in das Suchfeld ein.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539351\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/image-76.png\" alt=\"Statsmodels in PyCharm\" width=\"1600\" height=\"630\" \/><\/figure>\n<p>Auf der rechten Seite sehen Sie alle Informationen \u00fcber das Paket. Um es zu installieren, klicken Sie einfach auf <em>Install package<\/em> (Paket installieren).<\/p>\n<h4 class=\"wp-block-heading\"><strong>2. Jupyter Notebook erstellen<\/strong><\/h4>\n<p>Um den Datensatz weiter zu untersuchen, erstellen wir ein <a href=\"https:\/\/www.jetbrains.com\/help\/pycharm\/jupyter-notebook-support.html\" target=\"_blank\" rel=\"noopener\">Jupyter Notebook<\/a>. So k\u00f6nnen wir die Vorteile der Tools nutzen, welche die Jupyter-Notebook-Umgebung von PyCharm bietet.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539362\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/image-77.png\" alt=\"Jupyter Notebook in PyCharm erstellen\" width=\"1098\" height=\"410\" \/><\/figure>\n<p>Wir werden <a href=\"https:\/\/blog.jetbrains.com\/pycharm\/2024\/10\/data-exploration-with-pandas\/\">pandas<\/a> importieren und die <code>.csv<\/code>-Datei laden.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import pandas as pd\n\ndf = pd.read_csv('..\/data\/Hive17.csv', sep=\";\")\ndf = df.dropna()\ndf<\/pre>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539310\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/image-73.png\" alt=\"pandas in PyCharm importieren\" width=\"1600\" height=\"930\" \/><\/figure>\n<h4 class=\"wp-block-heading\"><strong>3. Daten als Diagramme untersuchen<\/strong><\/h4>\n<p>Jetzt k\u00f6nnen wir die Daten als Diagramme betrachten. Hier w\u00fcrden wir gerne die Temperatur des Bienenstocks 17 im Laufe der Zeit sehen. Klicken Sie auf <em>Chart view<\/em> (Diagrammansicht) im Dataframe-Inspektor und w\u00e4hlen Sie dann <em>T17<\/em> als y-Achse in den Reiheneinstellungen.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539299\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/image-2.gif\" alt=\"Daten als Diagramme in PyCharm untersuchen\" width=\"720\" height=\"290\" \/><\/figure>\n<p>Wenn die Temperatur als Zeitreihe dargestellt wird, zeigt sie viele Schwankungen. Dies deutet auf ein periodisches Verhalten hin, das wahrscheinlich auf den Tag-Nacht-Zyklus zur\u00fcckzuf\u00fchren ist, sodass man davon ausgehen kann, dass es einen 24-Stunden-Zeitraum f\u00fcr die Temperatur gibt.<\/p>\n<p>Weiterhin ist ein Trend hin zum Temperaturr\u00fcckgang im Laufe der Zeit zu erkennen. Wenn Sie sich die Spalte <em>DateTime<\/em> ansehen, k\u00f6nnen Sie feststellen, dass die Daten von August bis November reichen. Da die <a href=\"https:\/\/www.kaggle.com\/datasets\/vivovinco\/beehives\/data\" target=\"_blank\" rel=\"noopener\">Kaggle-Seite des Datensatzes<\/a> angibt, dass die Daten in der T\u00fcrkei erhoben wurden, erkl\u00e4rt der \u00dcbergang vom Sommer zum Herbst unsere Beobachtung, dass die Temperatur im Laufe der Zeit sinkt.<\/p>\n<h4 class=\"wp-block-heading\"><strong>4. Zerlegung von Zeitreihen<\/strong><\/h4>\n<p>Um die Zeitreihen zu verstehen und Anomalien zu erkennen, f\u00fchren wir eine STL-Zerlegung durch, indem wir die Klasse <code>STL<\/code> von statsmodels importieren und sie auf unsere Temperaturdaten anpassen.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from statsmodels.tsa.seasonal import STL\n\nstl = STL(df[\"T17\"], period=24, robust=True) \nresult = stl.fit()<\/pre>\n<p>Wir m\u00fcssen einen Zeitraum angeben, damit die Zerlegung funktioniert. Wie bereits erw\u00e4hnt, k\u00f6nnen wir von einem 24-Stunden-Zyklus ausgehen.<\/p>\n<p>Der Dokumentation zufolge zerlegt <code>STL<\/code> eine Zeitreihe in drei Komponenten: Trend, Saison und Restwert. Um einen genaueren Blick auf das zerlegte Ergebnis zu erhalten, k\u00f6nnen wir die integrierte <code>plot<\/code>-Methode verwenden:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">result.plot()<\/pre>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539541\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/Time-series-decomposition.png\" alt=\"Zerlegung von Zeitreihen\" width=\"1600\" height=\"1100\" \/><\/figure>\n<p>Sie k\u00f6nnen sehen, dass die <em>Trend<\/em>&#8211; und <em>Saison<\/em>-Diagramme mit unseren obigen Annahmen \u00fcbereinzustimmen scheinen. Wir interessieren uns jedoch f\u00fcr das Restwertdiagramm unten, das die urspr\u00fcngliche Serie ohne den Trend und die saisonalen Ver\u00e4nderungen darstellt. Jeder extrem hohe oder niedrige Restwert weist auf eine Anomalie hin.<\/p>\n<h4 id=\"anomaly-threshold\" class=\"wp-block-heading\"><strong>5. Schwellenwert f\u00fcr Anomalien<\/strong><\/h4>\n<p>Als N\u00e4chstes m\u00f6chten wir festlegen, welche Restwerte wir als abnormal erachten. Dazu k\u00f6nnen wir uns das Restwerthistogramm ansehen.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">result.resid.plot.hist()<\/pre>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539375\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/image-78.png\" alt=\"Schwellenwert f\u00fcr Anomalien in PyCharm\" width=\"1328\" height=\"1048\" \/><\/figure>\n<p>Wir betrachten dies als Normalverteilung um 0 mit langen Ausl\u00e4ufern \u00fcber 5 und unter \u20135, weshalb wir den Schwellenwert auf 5 festlegen.<\/p>\n<p>Um die Anomalien in der urspr\u00fcnglichen Zeitreihe zu zeigen, k\u00f6nnen wir sie im Diagramm wie folgt rot einf\u00e4rben:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import matplotlib.pyplot as plt\n\nthreshold = 5\nanomalies_filter = result.resid.apply(lambda x: True if abs(x) &gt; threshold else False)\nanomalies = df[\"T17\"][anomalies_filter]\n\nplt.figure(figsize=(14, 8))\nplt.scatter(x=anomalies.index, y=anomalies, color=\"red\", label=\"anomalies\")\nplt.plot(df.index, df['T17'], color='blue')\nplt.title('Temperatures in Hive 17')\nplt.xlabel('Hours')\nplt.ylabel('Temperature')\nplt.legend()\nplt.show()<\/pre>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539386\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/image-79.png\" alt=\"Anomalien in der urspr\u00fcnglichen Zeitreihe in PyCharm\" width=\"1600\" height=\"976\" \/><\/figure>\n<p>Ohne STL-Zerlegung ist es \u00e4u\u00dferst schwer, diese Anomalien in einer Zeitreihe, die aus Zeitr\u00e4umen und Trends besteht, zu erkennen.<\/p>\n<h3 class=\"wp-block-heading\">LSTM-Vorhersage<\/h3>\n<p>Eine andere M\u00f6glichkeit, Anomalien in Zeitreihendaten zu erkennen, besteht darin, eine Zeitreihenvorhersage mithilfe von Deep-Learning-Methoden durchzuf\u00fchren, um das Ergebnis der Datenpunkte zu sch\u00e4tzen. Wenn eine Sch\u00e4tzung stark vom tats\u00e4chlichen Datenpunkt abweicht, k\u00f6nnte dies ein Anzeichen f\u00fcr anomale Daten sein.<\/p>\n<p>Einer der beliebtesten Deep-Learning-Algorithmen f\u00fcr die Vorhersage von sequenziellen Daten ist das LSTM-Modell (langes Kurzzeitged\u00e4chtnis), eine Art rekurrentes neuronales Netz (RNN). Das LSTM-Modell hat Eingabe-, Vergessens- und Ausgabetore, die Zahlenmatrizen sind. Dadurch wird sichergestellt, dass wichtige Informationen bei der n\u00e4chsten Iteration der Daten weitergegeben werden.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539580\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/LSTM-memory-cell.png\" alt=\"LSTM-Ged\u00e4chtniszelle\" width=\"1600\" height=\"900\" \/><\/figure>\n<p>Da es sich bei Zeitreihendaten um sequenzielle Daten handelt (d.\u00a0h. die Reihenfolge der Datenpunkte ist sequenziell und sollte nicht gemischt werden), ist das LSTM-Modell ein effektives Deep-Learning-Modell, um das Ergebnis zu einem bestimmten Zeitpunkt vorherzusagen. Diese Prognose l\u00e4sst sich mit den realen Daten abgleichen und es kann ein Schwellenwert definiert werden, um festzustellen, ob die realen Daten eine Anomalie darstellen.<\/p>\n<h3 id=\"lstm-stock\" class=\"wp-block-heading\">Verwendung von LSTM-Vorhersagen f\u00fcr Aktienkurse<\/h3>\n<p>Lassen Sie uns nun ein neues Jupyter-Projekt starten, um Anomalien im Apple-Aktienkurs der letzten 5 Jahre zu erkennen. Der <a href=\"https:\/\/www.nasdaq.com\/market-activity\/stocks\/aapl\/historical?page=1&amp;rows_per_page=25&amp;timeline=y5\" target=\"_blank\" rel=\"noopener\">\u201estock price\u201c-Datensatz<\/a> zeigt die aktuellsten Daten. Wenn Sie den Blogbeitrag mitverfolgen m\u00f6chten, k\u00f6nnen Sie den von uns verwendeten <a href=\"https:\/\/github.com\/Cheukting\/lstm_anomaly_detection\/tree\/main\/data\" target=\"_blank\" rel=\"noopener\">Datensatz herunterladen<\/a>.<\/p>\n<h4 class=\"wp-block-heading\"><strong>1. Jupyter-Projekt einrichten<\/strong><\/h4>\n<p>Wenn Sie ein neues Projekt beginnen, k\u00f6nnen Sie ein Jupyter-Projekt erstellen, das f\u00fcr datenwissenschaftliche Vorg\u00e4nge optimiert ist. Im Fenster <em>New Project<\/em> (Neues Projekt) k\u00f6nnen Sie ein Git-Repository anlegen und bestimmen, welche conda-Installation Sie f\u00fcr die Verwaltung Ihrer Umgebung verwenden m\u00f6chten.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539627\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/Jupyter-project-in-PyCharm.png\" alt=\"Jupyter-Projekt in PyCharm einrichten\" width=\"1592\" height=\"1282\" \/><\/figure>\n<p>Nachdem Sie das Projekt begonnen haben, sehen Sie ein Beispiel-Notebook. Richten Sie ein neues Jupyter Notebook f\u00fcr diese \u00dcbung ein.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539604\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/image-4.gif\" alt=\"Ein Beispiel-Notebook in PyCharm\" width=\"716\" height=\"382\" \/><\/figure>\n<p>Danach setzen wir die Datei <code>requirements.txt<\/code> auf. Wir ben\u00f6tigen pandas, matplotlib und PyTorch, das bei PyPI torch hei\u00dft. Da PyTorch nicht in der conda-Umgebung enthalten ist, meldet PyCharm, dass uns das Paket fehlt. Um das Paket zu installieren, klicken Sie auf die Gl\u00fchbirne und w\u00e4hlen Sie <em>Install all missing packages<\/em> (Alle fehlenden Pakete installieren).<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539615\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/image-5.gif\" alt=\"Alle fehlenden Pakete in PyCharm installieren\" width=\"1358\" height=\"762\" \/><\/figure>\n<h4 class=\"wp-block-heading\"><strong>2. Laden und Pr\u00fcfen der Daten<\/strong><\/h4>\n<p>Als N\u00e4chstes verschieben wir unseren Datensatz <a href=\"https:\/\/github.com\/Cheukting\/lstm_anomaly_detection\/tree\/main\/data\" target=\"_blank\" rel=\"noopener\">apple_stock_5y.csv<\/a> in den data-Ordner und laden ihn als pandas-DataFrame, um ihn zu untersuchen.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import pandas as pd\n \ndf = pd.read_csv('data\/apple_stock_5y.csv')\ndf<\/pre>\n<p>Anhand der interaktiven Tabelle k\u00f6nnen wir leicht erkennen, ob Daten fehlen.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539640\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/image-6.gif\" alt=\"\" width=\"824\" height=\"442\" \/><\/figure>\n<p>Es fehlen keine Daten, aber wir haben ein Problem: Wir w\u00fcrden gerne den <em>Close\/Last<\/em>-Preis verwenden, aber es handelt sich nicht um einen numerischen Datentyp. Wir sollten eine Konvertierung vornehmen und unsere Daten noch einmal untersuchen:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">df[\"Close\/Last\"] = df[\"Close\/Last\"].apply(lambda x: float(x[1:]))\ndf<\/pre>\n<p>Jetzt k\u00f6nnen wir den Preis anhand der interaktiven Tabelle \u00fcberpr\u00fcfen. Klicken Sie auf das Diagrammsymbol auf der linken Seite \u2013 es wird dann ein Diagramm erstellt. Standardm\u00e4\u00dfig wird <em>Date<\/em> als x-Achse und <em>Volume<\/em> als y-Achse verwendet. Wir m\u00f6chten den <em>Close\/Last<\/em>-Preis untersuchen; gehen Sie also zu den Einstellungen, indem Sie auf das Zahnradsymbol auf der rechten Seite klicken, und w\u00e4hlen Sie <em>Close\/Last<\/em> als y-Achse aus.<\/p>\n<figure class=\"wp-block-image size-full is-resized\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539652\" style=\"aspect-ratio: 1.8662790697674418; width: 642px; height: auto;\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/image-7.gif\" alt=\"\" width=\"642\" height=\"344\" \/><\/figure>\n<h4 class=\"wp-block-heading\"><strong>3. Aufbereitung der Trainingsdaten f\u00fcr LSTM<\/strong><\/h4>\n<p>Als N\u00e4chstes m\u00fcssen wir die Trainingsdaten vorbereiten, die im LSTM-Modell verwendet werden sollen. Wir m\u00fcssen eine Sequenz von Vektoren (Feature X) vorbereiten, die jeweils ein Zeitfenster repr\u00e4sentieren, um den n\u00e4chsten Preis vorherzusagen. Der n\u00e4chste Kurs wird eine weitere Sequenz bilden (Ziel y). Hier k\u00f6nnen wir mit der Variable <code>lookback<\/code> festlegen, wie gro\u00df dieses Zeitfenster ist. Der folgende Code erstellt die Sequenzen X und y, die dann in PyTorch-Tensoren umgewandelt werden:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import torch\n\nlookback = 5\ntimeseries = df[[\"Close\/Last\"]].values.astype('float32')\n\nX, y = [], []\nfor i in range(len(timeseries)-lookback):\n    feature = timeseries[i:i+lookback]\n    target = timeseries[i+1:i+lookback+1]\n    X.append(feature)\n    y.append(target)\n    \nX = torch.tensor(X)\ny = torch.tensor(y)\n\nprint(X.shape, y.shape)<\/pre>\n<p>Im Allgemeinen gilt: Je gr\u00f6\u00dfer das Fenster, desto gr\u00f6\u00dfer wird unser Modell, da der Eingabevektor gr\u00f6\u00dfer ist. Bei einem gr\u00f6\u00dferen Fenster wird die Sequenz der Eingaben jedoch k\u00fcrzer, sodass die Festlegung dieses lookback-Fensters ein Balanceakt ist. Wir beginnen mit 5, aber Sie k\u00f6nnen gerne andere Werte ausprobieren, um die Unterschiede zu sehen.<\/p>\n<h4 class=\"wp-block-heading\"><strong>4. Modell erstellen und trainieren<\/strong><\/h4>\n<p>Wir k\u00f6nnen das Modell erstellen, indem wir eine Klasse mit dem <a href=\"https:\/\/pytorch.org\/docs\/stable\/nn.html\" target=\"_blank\" rel=\"noopener\">nn-Modul<\/a> in PyTorch anlegen, bevor wir es trainieren. Das nn-Modul liefert Bausteine, z.\u00a0B. verschiedene Ebenen neuronaler Netze. Im Rahmen dieser \u00dcbung erstellen wir eine einfache <a href=\"https:\/\/pytorch.org\/docs\/stable\/generated\/torch.nn.LSTM.html\" target=\"_blank\" rel=\"noopener\">LSTM-Ebene<\/a> gefolgt von einer <a href=\"https:\/\/pytorch.org\/docs\/stable\/generated\/torch.nn.Linear.html\" target=\"_blank\" rel=\"noopener\">linearen Ebene<\/a>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import torch.nn as nn\n\nclass StockModel(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.lstm = nn.LSTM(input_size=1, hidden_size=50, num_layers=1, batch_first=True)\n        self.linear = nn.Linear(50, 1)\n    def forward(self, x):\n        x, _ = self.lstm(x)\n        x = self.linear(x)\n        return x<\/pre>\n<p>Als N\u00e4chstes werden wir unser Modell trainieren. Vor dem Training m\u00fcssen wir einen Optimierer, eine <a href=\"https:\/\/pytorch.org\/docs\/stable\/nn.html#loss-functions\" target=\"_blank\" rel=\"noopener\">Loss-Funktion<\/a> zur Berechnung des Verlusts zwischen den vorhergesagten und den tats\u00e4chlichen y-Werten sowie einen <a href=\"https:\/\/pytorch.org\/docs\/stable\/data.html#data-loading-order-and-sampler\" target=\"_blank\" rel=\"noopener\">Data Loader<\/a> zur Einspeisung unserer Trainingsdaten erstellen:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import numpy as np\nimport torch.optim as optim\nimport torch.utils.data as data\n\nmodel = StockModel()\noptimizer = optim.Adam(model.parameters())\nloss_fn = nn.MSELoss()\nloader = data.DataLoader(data.TensorDataset(X, y), shuffle=True, batch_size=8)<\/pre>\n<p>Der Data Loader kann die Eingabe mischen, da wir die Zeitfenster bereits erstellt haben. Dadurch bleibt die sequenzielle Verkn\u00fcpfung in jedem Fenster erhalten.<\/p>\n<p>Das Training wird mit einer <code>for<\/code>-Schleife durchgef\u00fchrt, die jede Epoche durchl\u00e4uft. Alle 100 Epochen geben wir den Verlust aus und beobachten, wie das Modell konvergiert:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">n_epochs = 1000\nfor epoch in range(n_epochs):\n    model.train()\n    for X_batch, y_batch in loader:\n        y_pred = model(X_batch)\n        loss = loss_fn(y_pred, y_batch)\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n    if epoch % 100 != 0:\n        continue\n    model.eval()\n    with torch.no_grad():\n        y_pred = model(X)\n        rmse = np.sqrt(loss_fn(y_pred, y))\n    print(f\"Epoch {epoch}: RMSE {rmse:.4f}\")<\/pre>\n<p>Wir beginnen mit 1000 Epochen, aber das Modell konvergiert recht schnell. Probieren Sie ruhig eine andere Anzahl von Epochen f\u00fcr das Training aus, um das beste Ergebnis zu erzielen.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539664\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/Epochs-for-training.png\" alt=\"Epochen f\u00fcr das Training\" width=\"1346\" height=\"1046\" \/><\/figure>\n<p>In PyCharm zeigt eine Zelle, die etwas Zeit zum Ausf\u00fchren ben\u00f6tigt, eine Benachrichtigung dar\u00fcber an, wie viel Zeit noch verbleibt, sowie eine entsprechende Verkn\u00fcpfung. Das ist sehr praktisch, wenn Sie Machine-Learning- und insbesondere Deep-Learning-Modelle in Jupyter Notebooks trainieren.<\/p>\n<h4 class=\"wp-block-heading\"><strong>5. Vorhersage als Diagramm darstellen und Fehler finden<\/strong><\/h4>\n<p>Als N\u00e4chstes erstellen wir die Vorhersage und bilden sie zusammen mit der tats\u00e4chlichen Zeitreihe als Diagramm ab. Beachten Sie, dass wir eine 2-D-np-Reihe erstellen m\u00fcssen, die mit der tats\u00e4chlichen Zeitreihe \u00fcbereinstimmt. Die tats\u00e4chliche Zeitreihe wird blau dargestellt, w\u00e4hrend die vorhergesagte Zeitreihe rot abgebildet wird.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import matplotlib.pyplot as plt\n\nwith torch.no_grad():\n    pred_series = np.ones_like(timeseries) * np.nan\n    pred_series[lookback:] = model(X)[:, -1, :]\n\nplt.plot(timeseries, c='b')\nplt.plot(pred_series, c='r')\nplt.show()<\/pre>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539687\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/Plot-the-prediction-and-find-the-errors.png\" alt=\"Vorhersage als Diagramm darstellen und Fehler finden\" width=\"1180\" height=\"856\" \/><\/figure>\n<p>Wenn Sie genau hinsehen, werden Sie feststellen, dass die Vorhersage und die tats\u00e4chlichen Werte nicht perfekt \u00fcbereinstimmen. Die meisten Vorhersagen sind jedoch gut.<\/p>\n<p>Um die Fehler genau zu untersuchen, k\u00f6nnen wir eine Fehlerserie erstellen und die interaktive Tabelle verwenden, um sie zu beobachten. Wir verwenden dieses Mal den absoluten Fehler.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">error = abs(timeseries-pred_series)\nerror<\/pre>\n<p>Verwenden Sie die Einstellungen, um ein Histogramm mit dem Wert des absoluten Fehlers als x-Achse und der Anzahl des Wertes als y-Achse zu erstellen.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539434\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/image-3.gif\" alt=\"\" width=\"452\" height=\"362\" \/><\/figure>\n<h4 class=\"wp-block-heading\"><strong>6. Anomalie-Schwellenwert festlegen und visualisieren<\/strong><\/h4>\n<p>Die meisten Punkte werden einen absoluten Fehler von weniger als 6 haben, sodass wir dies als Schwellenwert f\u00fcr die Anomalie festlegen k\u00f6nnen. \u00c4hnlich wie <a href=\"https:\/\/blog.jetbrains.com\/pycharm\/2025\/01\/anomaly-detection-in-time-series\/#anomaly-threshold\" data-type=\"link\" data-id=\"https:\/\/blog.jetbrains.com\/pycharm\/2025\/01\/anomaly-detection-in-time-series\/#anomaly-threshold\">bei den Bienenstockanomalien<\/a> k\u00f6nnen wir die anomalen Datenpunkte in das Diagramm einzeichnen.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">threshold = 6\nerror_series = pd.Series(error.flatten())\nprice_series = pd.Series(timeseries.flatten())\n\nanomalies_filter = error_series.apply(lambda x: True if x &gt; threshold else False)\nanomalies = price_series[anomalies_filter]\n\nplt.figure(figsize=(14, 8))\nplt.scatter(x=anomalies.index, y=anomalies, color=\"red\", label=\"anomalies\")\nplt.plot(df.index, timeseries, color='blue')\nplt.title('Closing price')\nplt.xlabel('Days')\nplt.ylabel('Price')\nplt.legend()\nplt.show()<\/pre>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-539699\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/Plot-the-anomalous-data-points-in-the-graph.png\" alt=\"Anomale Datenpunkte in das Diagramm einzeichnen\" width=\"1600\" height=\"963\" \/><\/figure>\n<h2 class=\"wp-block-heading\">Zusammenfassung<\/h2>\n<p>Zeitreihendaten sind eine g\u00e4ngige Datenform, die in vielen Anwendungsbereichen, einschlie\u00dflich der Gesch\u00e4ftswelt und der wissenschaftlichen Forschung, eingesetzt wird. Aufgrund des sequenziellen Charakters von Zeitreihendaten werden spezielle Methoden und Algorithmen verwendet, um Anomalien in diesen Daten zu ermitteln. In diesem Blogbeitrag haben wir Ihnen gezeigt, wie Sie Anomalien mithilfe der STL-Zerlegung identifizieren k\u00f6nnen, um saisonale Schwankungen und Trends zu eliminieren. Wir haben au\u00dferdem demonstriert, wie man Deep Learning und das LSTM-Modell verwendet, um die gesch\u00e4tzten Werte mit den tats\u00e4chlichen Daten zu vergleichen und Anomalien zu identifizieren.<\/p>\n<h2 class=\"wp-block-heading\">Anomalien mit PyCharm erkennen<\/h2>\n<p>Mit dem Jupyter-Projekt in PyCharm Professional l\u00e4sst sich Ihr Projekt zur Anomalieerkennung m\u00fchelos mit zahlreichen Datendateien und Notebooks strukturieren. Sie k\u00f6nnen Graphen erstellen, um Anomalien zu untersuchen, und Diagramme sind in PyCharm \u00e4u\u00dferst benutzerfreundlich. Weitere Funktionen, wie etwa Auto-Vervollst\u00e4ndigungsvorschl\u00e4ge, gestalten das Navigieren durch die Scikit-learn-Modelle und die Matplotlib-Diagrammeinstellungen besonders angenehm.<\/p>\n<p>Verbessern Sie Ihre Data-Science-Projekte mit PyCharm und <a href=\"https:\/\/www.jetbrains.com\/de-de\/pycharm\/data-science\/\" target=\"_blank\" rel=\"noopener\">sehen Sie sich die verf\u00fcgbaren Data-Science-Features an<\/a>, um Ihren Data-Science-Workflow zu optimieren.<\/p>\n<div class=\"buttons\">\n<div class=\"buttons__row\"><a class=\"btn\" href=\"https:\/\/www.jetbrains.com\/de-de\/pycharm\/data-science\/\" target=\"\" rel=\"noopener\">Starten Sie mit PyCharm Pro kostenlos durch<\/a><\/div>\n<\/div>\n<p>\u00a0<\/p>\n<p><strong>Autorin des urspr\u00fcnglichen Blogposts<\/strong><\/p>\n\n    <div class=\"about-author \">\n        <div class=\"about-author__box\">\n            <div class=\"row\">\n                <div class=\"about-author__box-img\">\n                    <img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/CheukTingHo-Kimono-e1738750639162-200x200.jpg\" width=\"200\" height=\"200\" alt=\"Cheuk Ting Ho\" loading=\"lazy\"  class=\"avatar avatar-200 wp-user-avatar wp-user-avatar-200 photo avatar-default\">\n                <\/div>\n                <div class=\"about-author__box-text\">\n                                            <h4>Cheuk Ting Ho<\/h4>\n                                                        <\/div>\n            <\/div>\n        <\/div>\n    <\/div>\n","protected":false},"author":811,"featured_media":573889,"comment_status":"closed","ping_status":"closed","template":"","categories":[952,1401],"tags":[8670],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/pycharm\/573886"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/pycharm"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/types\/pycharm"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/users\/811"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/comments?post=573886"}],"version-history":[{"count":5,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/pycharm\/573886\/revisions"}],"predecessor-version":[{"id":573913,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/pycharm\/573886\/revisions\/573913"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/media\/573889"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/media?parent=573886"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/categories?post=573886"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/tags?post=573886"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/cross-post-tag?post=573886"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}