{"id":595827,"date":"2025-09-01T04:34:09","date_gmt":"2025-09-01T03:34:09","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=pycharm&#038;p=595827"},"modified":"2025-09-01T04:34:18","modified_gmt":"2025-09-01T03:34:18","slug":"detection-des-anomalies-dans-les-series-chronologiques","status":"publish","type":"pycharm","link":"https:\/\/blog.jetbrains.com\/fr\/pycharm\/2025\/09\/detection-des-anomalies-dans-les-series-chronologiques\/","title":{"rendered":"D\u00e9tection des anomalies dans les s\u00e9ries chronologiques"},"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\/09\/PC-social-BlogFeatured-1280x720-2x-1.png\" alt=\"D\u00e9tection des anomalies dans les s\u00e9ries chronologiques\" width=\"2560\" height=\"1440\" \/><\/figure>\n<p>Comment identifier les sch\u00e9mas inhabituels qui peuvent r\u00e9v\u00e9ler des probl\u00e8mes critiques ou des opportunit\u00e9s cach\u00e9es\u00a0? La <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\/\">d\u00e9tection des anomalies<\/a> permet d&#8217;identifier les donn\u00e9es qui d\u00e9vient de fa\u00e7on significative par rapport \u00e0 la norme. Les donn\u00e9es de s\u00e9ries chronologiques, qui consistent en donn\u00e9es collect\u00e9es au cours d&#8217;une p\u00e9riode donn\u00e9e, refl\u00e8tent souvent les tendances et les sch\u00e9mas saisonniers. Les anomalies dans les s\u00e9ries chronologiques se produisent lorsque ces sch\u00e9mas sont perturb\u00e9s, ce qui fait de la d\u00e9tection des anomalies un outil pr\u00e9cieux dans des domaines tels que la vente, la finance, la fabrication ou la sant\u00e9.<\/p>\n<p>Les s\u00e9ries chronologiques pr\u00e9sentant des caract\u00e9ristiques uniques, telles que la saisonnalit\u00e9 et les tendances, des m\u00e9thodes sp\u00e9cialis\u00e9es sont requises pour d\u00e9tecter les anomalies efficacement. Dans cet article de blog, nous allons explorer les principales m\u00e9thodes de d\u00e9tection des anomalies dans les s\u00e9ries chronologiques, avec notamment la d\u00e9composition STL et la pr\u00e9diction LSTM, avec des exemples d\u00e9taill\u00e9s de code pour vous aider \u00e0 commencer.<\/p>\n<h2 class=\"wp-block-heading\">D\u00e9tection des anomalies dans les s\u00e9ries chronologiques dans les entreprises<\/h2>\n<p>Les donn\u00e9es de s\u00e9ries chronologiques sont vitales pour de nombreuses activit\u00e9s et services. La plupart des entreprises appliquent un horodatage aux donn\u00e9es enregistr\u00e9es, afin d&#8217;en analyser les changements et de pouvoir les comparer au fil du temps. Les s\u00e9ries chronologiques sont utiles lors de la comparaison d&#8217;une certaine quantit\u00e9 pendant une p\u00e9riode donn\u00e9e comme cela est le cas lors d&#8217;une comparaison annuelle des donn\u00e9es pour mettre en \u00e9vidence leur caract\u00e8re saisonnier.<\/p>\n<p><strong>Suivi des ventes<\/strong><\/p>\n<p>L&#8217;un des exemples les plus courants de s\u00e9ries chronologiques saisonni\u00e8res est les donn\u00e9es commerciales. En effet, de nombreuses ventes sont affect\u00e9es par des cong\u00e9s annuels et la p\u00e9riode de l&#8217;ann\u00e9e, qui constituent des facteurs incontournables d&#8217;analyse. Pour cette raison, la d\u00e9composition STL repr\u00e9sente une m\u00e9thode tr\u00e8s r\u00e9pandue d&#8217;analyse et de d\u00e9tection des anomalies, que nous allons couvrir en d\u00e9tail <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\">plus bas dans cet article de blog<\/a>.<\/p>\n<p><strong>Finance<\/strong><\/p>\n<p>Les donn\u00e9es financi\u00e8res, telles que les transactions et les prix des actions, constituent des exemples typiques de donn\u00e9es de s\u00e9ries chronologiques. Dans le secteur financier, l&#8217;analyse et la d\u00e9tection des anomalies dans ces donn\u00e9es constituent une pratique courante. Par exemple, les mod\u00e8les de pr\u00e9diction des s\u00e9ries chronologiques peuvent \u00eatre utilis\u00e9s lors du trading algorithmique. Nous allons utiliser une pr\u00e9diction de s\u00e9rie temporelle pour identifier les anomalies dans les donn\u00e9es boursi\u00e8res <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\">plus bas dans cet article de blog<\/a>.<\/p>\n<p><strong>Fabrication<\/strong><\/p>\n<p>Un autre cas d&#8217;utilisation de la d\u00e9tection des anomalies de s\u00e9ries chronologiques r\u00e9side dans la d\u00e9tection des d\u00e9fauts sur les lignes de production. Les machines sont \u00e9galement souvent contr\u00f4l\u00e9es, fournissant ainsi des donn\u00e9es de s\u00e9ries chronologiques. Il est essentiel de pouvoir avertir la direction en cas de pannes potentielles, et la d\u00e9tection des anomalies joue pour cela un r\u00f4le cl\u00e9.<\/p>\n<p><strong>M\u00e9decine et sant\u00e9<\/strong><\/p>\n<p>Dans les domaines de la m\u00e9decine et de la sant\u00e9, les signes vitaux des patients sont suivis afin de d\u00e9tecter les anomalies. Cela est important pour la recherche m\u00e9dicale et vital pour les diagnostics. Si les signes vitaux d&#8217;un patient hospitalis\u00e9 pr\u00e9sentent des anomalies et ne sont pas trait\u00e9s imm\u00e9diatement, les cons\u00e9quences peuvent \u00eatre fatales.<\/p>\n<h2 class=\"wp-block-heading\">Pourquoi est-il important d&#8217;utiliser des m\u00e9thodes sp\u00e9ciales lors de la d\u00e9tection d&#8217;anomalies dans les s\u00e9ries chronologiques\u00a0?<\/h2>\n<p>Les donn\u00e9es de s\u00e9ries chronologiques sont sp\u00e9ciales dans la mesure o\u00f9 elles ne peuvent pas toujours \u00eatre trait\u00e9es comme les autres types de donn\u00e9es. Par exemple, lorsque nous appliquons une fonction \u00ab\u00a0train test split\u00a0\u00bb (division en ensembles d&#8217;entra\u00eenement) aux donn\u00e9es de s\u00e9ries chronologiques, la nature s\u00e9quentielle des donn\u00e9es signifie que nous ne pouvons pas en changer l&#8217;ordre. Cela se v\u00e9rifie \u00e9galement lors de l&#8217;application de donn\u00e9es de s\u00e9ries chronologiques \u00e0 un mod\u00e8le de deep learning. Un r\u00e9seau neuronal r\u00e9current (RNN) est g\u00e9n\u00e9ralement utilis\u00e9 pour prendre la relation s\u00e9quentielle en compte, et les donn\u00e9es d&#8217;entra\u00eenement sont entr\u00e9es sous forme de fen\u00eatres temporelles, ce qui pr\u00e9serve la s\u00e9quence des \u00e9v\u00e9nements qu&#8217;elles contiennent.<\/p>\n<p>Les donn\u00e9es de s\u00e9ries chronologiques sont \u00e9galement sp\u00e9ciales dans la mesure o\u00f9 elles sont soumises \u00e0 des facteurs saisonniers et des tendances que nous ne pouvons pas ignorer. Ce caract\u00e8re saisonnier peut prendre la forme d&#8217;un cycle de 24\u00a0heures, de 7\u00a0jours ou de 12\u00a0mois, pour ne citer que les cas les plus courants. Les anomalies ne peuvent \u00eatre d\u00e9termin\u00e9es qu&#8217;une fois les facteurs saisonniers et les tendances pris en compte, comme vous pourrez le voir dans <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\">notre exemple ci-dessous<\/a>.<\/p>\n<h2 class=\"wp-block-heading\">M\u00e9thodes utilis\u00e9es pour la d\u00e9tection des anomalies dans les s\u00e9ries chronologiques<\/h2>\n<p>Dans la mesure o\u00f9 les donn\u00e9es de s\u00e9ries chronologiques sont sp\u00e9ciales, des m\u00e9thodes sp\u00e9cifiques sont n\u00e9cessaires pour y d\u00e9tecter des anomalies. Selon le type de donn\u00e9es, une partie des m\u00e9thodes et des algorithmes que nous avons mentionn\u00e9s dans le pr\u00e9c\u00e9dent <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\/\">article sur la d\u00e9tection des anomalies<\/a> peut \u00eatre utilis\u00e9e sur les donn\u00e9es de s\u00e9ries chronologiques. Toutefois, avec ces m\u00e9thodes, la d\u00e9tection des anomalies peut ne pas \u00eatre aussi robuste qu&#8217;avec celles qui ont \u00e9t\u00e9 con\u00e7ues sp\u00e9cifiquement pour les donn\u00e9es de s\u00e9ries chronologiques. Dans certains cas, une combinaison de m\u00e9thodes de d\u00e9tection peut \u00eatre utilis\u00e9e pour confirmer \u00e0 nouveau le r\u00e9sultat de la d\u00e9tection et \u00e9viter les faux positifs ou n\u00e9gatifs.<\/p>\n<h3 class=\"wp-block-heading\">D\u00e9composition STL<\/h3>\n<p>L&#8217;une des solutions les plus populaires d&#8217;utilisation des donn\u00e9es de s\u00e9ries chronologiques saisonni\u00e8res est la d\u00e9composition STL, la d\u00e9composition de tendance saisonni\u00e8re appliquant la r\u00e9gression locale ou LOESS (locally estimated scatterplot smoothing). Dans cette m\u00e9thode, une s\u00e9rie chronologique est d\u00e9compos\u00e9e en utilisant une estimation de la saisonnalit\u00e9 (la p\u00e9riode \u00e9tant fournie ou d\u00e9termin\u00e9e par un algorithme), une tendance (estim\u00e9e) et la composante r\u00e9siduelle (le bruit dans les donn\u00e9es). <a href=\"https:\/\/www.statsmodels.org\/stable\/index.html\" target=\"_blank\" rel=\"noopener\">Statsmodels<\/a> est l&#8217;une des biblioth\u00e8ques <a href=\"https:\/\/www.jetbrains.com\/help\/pycharm\/python.html\" target=\"_blank\" rel=\"noopener\">Python<\/a> qui fournit des <a href=\"https:\/\/www.statsmodels.org\/stable\/examples\/notebooks\/generated\/stl_decomposition.html\" target=\"_blank\" rel=\"noopener\">outils de d\u00e9composition STL<\/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=\"D\u00e9composition STL\" width=\"1600\" height=\"900\" \/><\/figure>\n<p>Une anomalie est d\u00e9tect\u00e9e lorsque le r\u00e9sidu d\u00e9passe un certain seuil.<\/p>\n<h3 id=\"stl-beehive\" class=\"wp-block-heading\">Application de la d\u00e9composition STL aux donn\u00e9es d&#8217;une ruche<\/h3>\n<p>Dans un <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\/\">article de blog<\/a> pr\u00e9c\u00e9dent, nous avons parl\u00e9 de la d\u00e9tection des anomalies dans les ruches au moyen des m\u00e9thodes <a href=\"https:\/\/scikit-learn.org\/stable\/modules\/generated\/sklearn.svm.OneClassSVM.html\" target=\"_blank\" rel=\"noopener\">OneClassSVM<\/a> et <a href=\"https:\/\/scikit-learn.org\/stable\/modules\/generated\/sklearn.ensemble.IsolationForest.html\" target=\"_blank\" rel=\"noopener\">IsolationForest<\/a>.<\/p>\n<p>Dans ce tutoriel, nous allons analyser les <a href=\"https:\/\/www.kaggle.com\/datasets\/vivovinco\/beehives\" target=\"_blank\" rel=\"noopener\">donn\u00e9es d&#8217;une ruche<\/a> en tant que s\u00e9rie chronologique avec la classe <code>STL<\/code> fournie par la biblioth\u00e8que statsmodels. Pour commencer, configurez votre environnement en utilisant le fichier suivant\u00a0: <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. Installer la biblioth\u00e8que<\/strong><\/h4>\n<p>Dans la mesure o\u00f9 nous avons uniquement utilis\u00e9 le mod\u00e8le fourni par Scikit-learn, nous devons installer la biblioth\u00e8que statsmodels fournie par PyPI. Cela est simple \u00e0 faire dans <a href=\"https:\/\/www.jetbrains.com\/fr-fr\/pycharm\/data-science\/\" target=\"_blank\" rel=\"noreferrer noopener\">PyCharm<\/a>.<\/p>\n<div class=\"buttons\">\n<div class=\"buttons__row\"><a class=\"btn\" href=\"https:\/\/www.jetbrains.com\/fr-fr\/pycharm\/data-science\/\" target=\"\" rel=\"noopener\">Essayer PyCharm Pro gratuitement<\/a><\/div>\n<\/div>\n<p>Ouvrez la fen\u00eatre <em><a href=\"https:\/\/www.jetbrains.com\/help\/pycharm\/installing-uninstalling-and-upgrading-packages.html\" target=\"_blank\" rel=\"noopener\">Python Packages<\/a><\/em> (choisissez l&#8217;ic\u00f4ne en bas \u00e0 gauche de l&#8217;IDE) et tapez statsmodels dans la zone de recherche.<\/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 dans PyCharm\" width=\"1600\" height=\"630\" \/><\/figure>\n<p>Vous trouverez toutes les informations sur le paquet dans la partie droite. Pour l&#8217;installer, cliquez simplement sur <em>Install package<\/em>.<\/p>\n<h4 class=\"wp-block-heading\"><strong>2. Cr\u00e9er un notebook Jupyter<\/strong><\/h4>\n<p>Pour analyser plus en d\u00e9tail l&#8217;ensemble de donn\u00e9es, nous allons cr\u00e9er un <a href=\"https:\/\/www.jetbrains.com\/help\/pycharm\/jupyter-notebook-support.html\" target=\"_blank\" rel=\"noopener\">notebook Jupyter<\/a> pour profiter des outils fournis par l&#8217;environnement de notebook Jupyter de PyCharm.<\/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=\"Cr\u00e9er un notebook Jupyter dans PyCharm\" width=\"1098\" height=\"410\" \/><\/figure>\n<p>Nous allons importer <a href=\"https:\/\/blog.jetbrains.com\/pycharm\/2024\/10\/data-exploration-with-pandas\/\">pandas<\/a> et charger le fichier <code>.csv<\/code>.<\/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=\"Importer pandas dans PyCharm\" width=\"1600\" height=\"930\" \/><\/figure>\n<h4 class=\"wp-block-heading\"><strong>3. Inspecter les donn\u00e9es sous forme de graphiques<\/strong><\/h4>\n<p>Nous allons maintenant inspecter les donn\u00e9es sous forme de graphiques. Dans cet exemple, nous voulons voir l&#8217;\u00e9volution de la temp\u00e9rature de la ruche 17. Cliquez sur <em>Chart view<\/em> dans l&#8217;inspecteur de dataframe, puis choisissez <em>T17<\/em> en tant qu&#8217;axe y dans les param\u00e8tres de s\u00e9rie.<\/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=\"Inspecter les donn\u00e9es sous forme de graphiques dans PyCharm\" width=\"720\" height=\"290\" \/><\/figure>\n<p>Lorsqu&#8217;elle est exprim\u00e9e sous forme chronologique, la temp\u00e9rature pr\u00e9sente de nombreuses variations. Cela indique un comportement p\u00e9riodique, probablement d\u00fb au cycle jours\/nuits, ce qui permet d&#8217;affirmer qu&#8217;il s&#8217;agit de mesures de temp\u00e9rature sur une p\u00e9riode de 24\u00a0heures.<\/p>\n<p>Ensuite, il y a une tendance de baisse des temp\u00e9ratures dans le temps. Si vous examinez la colonne <em>DateTime<\/em>, vous pouvez voir la plage de dates d&#8217;ao\u00fbt \u00e0 novembre. Dans la mesure o\u00f9 la <a href=\"https:\/\/www.kaggle.com\/datasets\/vivovinco\/beehives\/data\" target=\"_blank\" rel=\"noopener\">page Kaggle de l&#8217;ensemble de donn\u00e9es<\/a> indique que les donn\u00e9es ont \u00e9t\u00e9 collect\u00e9es en Turquie, la transition de l&#8217;\u00e9t\u00e9 \u00e0 l&#8217;automne explique la baisse observ\u00e9e des temp\u00e9ratures dans le temps.<\/p>\n<h4 class=\"wp-block-heading\"><strong>4. D\u00e9composition de la s\u00e9rie chronologique<\/strong><\/h4>\n<p>Pour comprendre la s\u00e9rie chronologique et d\u00e9tecter les anomalies, nous allons effectuer une d\u00e9composition STL, en important la classe <code>STL<\/code> depuis statsmodels et en l&#8217;adaptant \u00e0 nos donn\u00e9es de temp\u00e9rature.<\/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>Nous devons fournir une p\u00e9riode pour r\u00e9aliser la d\u00e9composition. Comme nous l&#8217;avons mentionn\u00e9 plus t\u00f4t, il s&#8217;agit bien d&#8217;un cycle de 24\u00a0heures.<\/p>\n<p>Selon la documentation, <code>STL<\/code> d\u00e9compose une s\u00e9rie chronologique en trois composants\u00a0: tendance, saisonnalit\u00e9 et r\u00e9sidu. Pour avoir une vue plus claire du r\u00e9sultat d\u00e9compos\u00e9, nous pouvons utiliser la m\u00e9thode <code>plot<\/code>\u00a0:<\/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=\"D\u00e9composition de la s\u00e9rie chronologique\" width=\"1600\" height=\"1100\" \/><\/figure>\n<p>Vous pouvez voir que les graphiques <em>Trend<\/em> et <em>Season<\/em> semblent corroborer nos hypoth\u00e8ses ci-dessus. Toutefois, nous sommes int\u00e9ress\u00e9s par la courbe r\u00e9siduelle en bas, qui repr\u00e9sente la s\u00e9rie d&#8217;origine sans les changements propres \u00e0 la tendance et la saisonnalit\u00e9. Toute valeur extr\u00eamement haute ou basse dans la composante r\u00e9siduelle d\u00e9note une anomalie.<\/p>\n<h4 id=\"anomaly-threshold\" class=\"wp-block-heading\"><strong>5. Seuil d&#8217;anomalie<\/strong><\/h4>\n<p>Ensuite, nous devons d\u00e9terminer quelles valeurs de la composante r\u00e9siduelle doivent \u00eatre consid\u00e9r\u00e9es comme anormales. Pour cela, nous allons examiner l&#8217;histogramme de la composante r\u00e9siduelle.<\/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=\"Seuil d'anomalie dans PyCharm\" width=\"1328\" height=\"1048\" \/><\/figure>\n<p>Cela peut \u00eatre consid\u00e9r\u00e9 comme une distribution normale autour de 0, avec une queue longue au-dessus de 5 et en dessous de -5, ce qui nous am\u00e8ne \u00e0 d\u00e9finir le seuil sur\u00a05.<\/p>\n<p>Pour afficher les anomalies des s\u00e9ries chronologiques d&#8217;origine, nous pouvons les colorer toutes en rouge dans le graphique, de la fa\u00e7on suivante\u00a0:<\/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=\"Anomalies dans les s\u00e9ries chronologiques d'origine dans PyCharm\" width=\"1600\" height=\"976\" \/><\/figure>\n<p>En l&#8217;absence de d\u00e9composition STL, il est tr\u00e8s difficile d&#8217;identifier ces anomalies dans une s\u00e9rie chronologique comprenant des p\u00e9riodes et des tendances.<\/p>\n<h3 class=\"wp-block-heading\">Pr\u00e9vision LSTM<\/h3>\n<p>Une autre possibilit\u00e9 de d\u00e9tection des anomalies dans les s\u00e9ries chronologiques consiste \u00e0 faire des pr\u00e9visions sur ces s\u00e9ries en appliquant des m\u00e9thodes de deep learning pour estimer le r\u00e9sultat des points de donn\u00e9es. Si une estimation est tr\u00e8s diff\u00e9rente du point de donn\u00e9es r\u00e9el, cela peut \u00eatre le signe de donn\u00e9es anormales.<\/p>\n<p>L&#8217;un des algorithmes de deep learning les plus populaires pour pr\u00e9dire les donn\u00e9es s\u00e9quentielles est le mod\u00e8le LSTM (Long short-term memory &#8211; m\u00e9moire long-court terme), qui est un type de r\u00e9seau neuronal r\u00e9current (RNN). Le mod\u00e8le LSTM a des portes d&#8217;entr\u00e9e, d&#8217;oubli et de sortie, qui sont des matrices de nombres. Cela permet de transf\u00e9rer des informations importantes lors de l&#8217;it\u00e9ration suivante des donn\u00e9es.<\/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=\"Cellule de m\u00e9moire LSTM\" width=\"1600\" height=\"900\" \/><\/figure>\n<p>Les s\u00e9ries chronologiques sont des donn\u00e9es s\u00e9quentielles, ce qui veut dire que l&#8217;ordre des points de donn\u00e9es ne doit pas \u00eatre modifi\u00e9. Par cons\u00e9quent, le mod\u00e8le LSTM est un mod\u00e8le efficace de deep learning pour pr\u00e9dire le r\u00e9sultat \u00e0 un moment donn\u00e9. Cette pr\u00e9vision peut ensuite \u00eatre compar\u00e9e aux donn\u00e9es r\u00e9elles et il est possible de d\u00e9finir un seuil pour d\u00e9terminer si les donn\u00e9es r\u00e9elles constituent une anomalie.<\/p>\n<h3 id=\"lstm-stock\" class=\"wp-block-heading\">Application des pr\u00e9visions LSTM aux cotations en bourse<\/h3>\n<p>Nous allons cr\u00e9er un projet Jupyter pour d\u00e9tecter les anomalies de cotation des actions Apple au cours des 5\u00a0derni\u00e8res ann\u00e9es. L&#8217;<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\">ensemble de donn\u00e9es sur le prix des actions<\/a> offre les donn\u00e9es les plus r\u00e9centes. Si vous souhaitez essayer cet exemple tout en lisant l&#8217;article, vous pouvez <a href=\"https:\/\/github.com\/Cheukting\/lstm_anomaly_detection\/tree\/main\/data\" target=\"_blank\" rel=\"noopener\">t\u00e9l\u00e9charger l&#8217;ensemble de donn\u00e9es<\/a> que nous utilisons.<\/p>\n<h4 class=\"wp-block-heading\"><strong>1. Cr\u00e9er un projet Jupyter<\/strong><\/h4>\n<p>Lors de la cr\u00e9ation d&#8217;un projet, vous pouvez opter pour une version Jupyter, car elle est optimis\u00e9e pour la science des donn\u00e9es. Dans la fen\u00eatre <em>New Project<\/em>, vous pouvez cr\u00e9er un r\u00e9f\u00e9rentiel Git et d\u00e9terminer quelle installation conda utiliser pour g\u00e9rer votre environnement.<\/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=\"Cr\u00e9er un projet Jupyter dans PyCharm\" width=\"1592\" height=\"1282\" \/><\/figure>\n<p>Une fois le projet cr\u00e9\u00e9, un exemple de notebook s&#8217;affiche. Vous pouvez alors cr\u00e9er un notebook Jupyter pour cet exercice.<\/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=\"Un exemple de notebook dans PyCharm\" width=\"716\" height=\"382\" \/><\/figure>\n<p>Ensuite, nous allons configurer <code>requirements.txt<\/code>. Nous aurons besoin de pandas, matplotlib et PyTorch, qui est appel\u00e9 torch dans PyPI. Dans la mesure o\u00f9 PyTorch n&#8217;est pas inclus dans l&#8217;environnement conda, PyCharm nous indique que ce paquet est manquant. Pour l&#8217;installer, cliquez sur l&#8217;ic\u00f4ne d&#8217;ampoule et s\u00e9lectionnez <em>Install all missing packages<\/em>.<\/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=\"Installer tous les paquets manquants dans PyCharm\" width=\"1358\" height=\"762\" \/><\/figure>\n<h4 class=\"wp-block-heading\"><strong>2. Chargement et inspection des donn\u00e9es<\/strong><\/h4>\n<p>Ensuite, nous allons placer notre ensemble de donn\u00e9es <a href=\"https:\/\/github.com\/Cheukting\/lstm_anomaly_detection\/tree\/main\/data\" target=\"_blank\" rel=\"noopener\">apple_stock_5y.csv<\/a> dans le dossier de donn\u00e9es et le charger en tant que DataFrame pandas pour l&#8217;inspecter.<\/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>La table interactive permet de d\u00e9terminer facilement si des donn\u00e9es sont manquantes.<\/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>Il n&#8217;y a pas de donn\u00e9es manquantes, mais nous avons un probl\u00e8me, nous voulons utiliser le prix <em>Close\/Last<\/em>, mais il ne s&#8217;agit pas d&#8217;un type de donn\u00e9es num\u00e9rique. Nous allons op\u00e9rer une conversion et inspecter nos donn\u00e9es \u00e0 nouveau\u00a0:<\/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>\u00c0 pr\u00e9sent, nous pouvons inspecter le prix avec le tableau interactif. Cliquez sur l&#8217;ic\u00f4ne de tra\u00e7age \u00e0 gauche pour cr\u00e9er un trac\u00e9. Par d\u00e9faut, il utilise <em>Date<\/em> comme axe des x et <em>Volume <\/em>comme axe des y. Dans la mesure o\u00f9 nous devons inspecter le prix <em>Close\/Last<\/em>, allez dans la section des param\u00e8tres en cliquant sur l&#8217;ic\u00f4ne d&#8217;engrenage \u00e0 droite et choisissez <em>Close\/Last<\/em> comme axe des y.<\/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. Pr\u00e9paration des donn\u00e9es d&#8217;entra\u00eenement pour LSTM<\/strong><\/h4>\n<p>Ensuite, nous devons pr\u00e9parer les donn\u00e9es d&#8217;entra\u00eenement \u00e0 utiliser dans le mod\u00e8le LSTM. Nous devons pr\u00e9parer une s\u00e9quence de vecteurs (feature X), chacun repr\u00e9sentant une fen\u00eatre de temps, pour pr\u00e9dire le prix suivant. Le prix suivant formera une autre s\u00e9quence (target\u00a0y). Ici, nous pouvons d\u00e9finir la taille de cette fen\u00eatre de temps avec la variable <code>lookback<\/code>. Le code suivant cr\u00e9e les s\u00e9quences X et y qui seront converties en tenseurs PyTorch\u00a0:<\/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>De mani\u00e8re g\u00e9n\u00e9rale, plus la fen\u00eatre est large, plus notre mod\u00e8le sera grand, car le vecteur d&#8217;entr\u00e9e est plus grand. Toutefois, avec une plus grande fen\u00eatre, la s\u00e9quence d&#8217;entr\u00e9es sera plus courte. Par cons\u00e9quent, la d\u00e9finition de cette fen\u00eatre d&#8217;ant\u00e9c\u00e9dent est une question d&#8217;\u00e9quilibre. Nous allons commencer par 5, mais n&#8217;h\u00e9sitez pas \u00e0 essayer d&#8217;autres valeurs pour voir la diff\u00e9rence.<\/p>\n<h4 class=\"wp-block-heading\"><strong>4. Cr\u00e9ation et entra\u00eenement du mod\u00e8le<\/strong><\/h4>\n<p>Nous allons cr\u00e9er le mod\u00e8le en utilisant une classe avec le <a href=\"https:\/\/pytorch.org\/docs\/stable\/nn.html\" target=\"_blank\" rel=\"noopener\">module nn<\/a> de PyTorch avant de l&#8217;entra\u00eener. Le module nn fournit les diff\u00e9rentes briques, qui correspondent aux diff\u00e9rentes couches d&#8217;un r\u00e9seau neuronal. Dans cet exercice, nous allons cr\u00e9er une <a href=\"https:\/\/pytorch.org\/docs\/stable\/generated\/torch.nn.LSTM.html\" target=\"_blank\" rel=\"noopener\">couche LSTM<\/a> simple, suivie par une <a href=\"https:\/\/pytorch.org\/docs\/stable\/generated\/torch.nn.Linear.html\" target=\"_blank\" rel=\"noopener\">couche lin\u00e9aire<\/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>Ensuite, nous allons entra\u00eener notre mod\u00e8le. Avant cela, nous devons cr\u00e9er un optimiseur, une <a href=\"https:\/\/pytorch.org\/docs\/stable\/nn.html#loss-functions\" target=\"_blank\" rel=\"noopener\">fonction de perte<\/a> permettant de calculer la perte entre les valeurs y pr\u00e9vues et r\u00e9elles, et un <a href=\"https:\/\/pytorch.org\/docs\/stable\/data.html#data-loading-order-and-sampler\" target=\"_blank\" rel=\"noopener\">chargeur de donn\u00e9es<\/a> pour entrer nos donn\u00e9es d&#8217;entra\u00eenement\u00a0:<\/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>Le chargeur de donn\u00e9es peut changer l&#8217;ordre des entr\u00e9es, car nous avons d\u00e9j\u00e0 cr\u00e9\u00e9 les fen\u00eatres de temps. Cela permet de pr\u00e9server la relation s\u00e9quentielle dans chaque fen\u00eatre.<\/p>\n<p>L&#8217;entra\u00eenement se fait en utilisant une boucle <code>for<\/code> pour chaque \u00e9poque. Toutes les 100 \u00e9poques, nous imprimons la perte et observons la convergence du mod\u00e8le\u00a0:<\/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>Nous commen\u00e7ons \u00e0 1\u00a0000 \u00e9poques, mais le mod\u00e8le converge tr\u00e8s rapidement. N&#8217;h\u00e9sitez pas \u00e0 essayer un autre nombre d&#8217;\u00e9poques lors de l&#8217;entra\u00eenement pour obtenir le meilleur r\u00e9sultat possible.<\/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=\"\u00c9poques pour l'entra\u00eenement\" width=\"1346\" height=\"1046\" \/><\/figure>\n<p>Dans PyCharm, une cellule qui demande un temps d&#8217;ex\u00e9cution donne une indication du temps restant et un raccourci vers la cellule. Cela est particuli\u00e8rement pratique lors de l&#8217;entra\u00eenement des mod\u00e8les de machine learning, notamment pour le deep learning, dans les notebooks Jupyter.<\/p>\n<h4 class=\"wp-block-heading\"><strong>5. Tracer la pr\u00e9vision et trouver les erreurs<\/strong><\/h4>\n<p>Ensuite, nous allons cr\u00e9er la pr\u00e9vision et la tracer en utilisant les s\u00e9ries chronologiques r\u00e9elles. Nous allons cependant devoir cr\u00e9er une s\u00e9rie np 2D qui devra correspondre avec la s\u00e9rie chronologique r\u00e9elle. La s\u00e9rie chronologique r\u00e9elle sera en bleu, tandis que la s\u00e9rie pr\u00e9dite sera en rouge.<\/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=\"Tracer la pr\u00e9vision et trouver les erreurs\" width=\"1180\" height=\"856\" \/><\/figure>\n<p>Si vous observez attentivement, vous verrez que les valeurs de la pr\u00e9vision et les valeurs r\u00e9elles ne correspondent pas exactement. Toutefois, la plupart des pr\u00e9visions sont remarquablement proches.<\/p>\n<p>Pour inspecter les erreurs de fa\u00e7on plus pr\u00e9cise, nous allons cr\u00e9er une s\u00e9rie d&#8217;erreurs et utiliser le tableau interactif pour les observer. Nous utilisons l&#8217;erreur absolue cette fois-ci.<\/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>Utilisez les param\u00e8tres pour cr\u00e9er un histogramme avec la valeur de l&#8217;erreur absolue comme axe des x et le nombre d&#8217;occurrences comme axe des y.<\/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. D\u00e9cider du seuil d&#8217;anomalie et visualiser<\/strong><\/h4>\n<p>La plupart des points auront une erreur absolue inf\u00e9rieure \u00e0 6, ce que nous allons utiliser comme seuil d&#8217;anomalie. Comme <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\">nous l&#8217;avons fait pour les anomalies de la ruche<\/a>, nous pouvons tracer les points de donn\u00e9es anormaux dans le graphique.<\/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=\"Tra\u00e7age des points de donn\u00e9es anormaux dans le graphique\" width=\"1600\" height=\"963\" \/><\/figure>\n<h2 class=\"wp-block-heading\">En r\u00e9sum\u00e9<\/h2>\n<p>Les s\u00e9ries chronologiques sont tr\u00e8s fr\u00e9quentes dans de nombreuses applications, notamment commerciales ou de recherche scientifique. En raison de la nature s\u00e9quentielle des s\u00e9ries chronologiques, des m\u00e9thodes et des algorithmes sp\u00e9ciaux sont employ\u00e9s pour y d\u00e9terminer les anomalies. Dans cet article de blog, nous avons vu comment identifier les anomalies avec la d\u00e9composition STL pour \u00e9liminer la saisonnalit\u00e9 et les tendances. Nous avons \u00e9galement vu comment utiliser le deep learning et le mod\u00e8le LSTM pour comparer l&#8217;estimation pr\u00e9vue et les donn\u00e9es r\u00e9elles pour d\u00e9terminer les anomalies.<\/p>\n<h2 class=\"wp-block-heading\">D\u00e9tecter les anomalies avec PyCharm<\/h2>\n<p>Le projet Jupyter de PyCharm Professional permet d&#8217;organiser facilement votre projet de d\u00e9tection d&#8217;anomalie avec de nombreux fichiers de donn\u00e9es et notebooks. La g\u00e9n\u00e9ration de graphiques permet d&#8217;inspecter les anomalies, d&#8217;autant plus que les trac\u00e9s sont tr\u00e8s accessibles dans PyCharm. D&#8217;autres fonctionnalit\u00e9s, telles que les suggestions de saisie semi-automatique, permettent de naviguer tous les mod\u00e8les Scikit-learn et les param\u00e8tres de tra\u00e7age Matplotlib tr\u00e8s facilement.<\/p>\n<p>Boostez vos projets de science des donn\u00e9es en utilisant PyCharm et <a href=\"https:\/\/www.jetbrains.com\/fr-fr\/pycharm\/data-science\/\" target=\"_blank\" rel=\"noopener\">d\u00e9couvrez les fonctionnalit\u00e9s de science des donn\u00e9es offertes<\/a> pour simplifier votre workflow de science des donn\u00e9es.<\/p>\n<div class=\"buttons\">\n<div class=\"buttons__row\"><a class=\"btn\" href=\"https:\/\/www.jetbrains.com\/fr-fr\/pycharm\/data-science\/\" target=\"\" rel=\"noopener\">Essayer PyCharm Pro gratuitement<\/a><\/div>\n<\/div>\n<p>\u00a0<\/p>\n<p><em>Auteur de l\u2019article original en anglais :<\/em><\/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":813,"featured_media":595829,"comment_status":"closed","ping_status":"closed","template":"","categories":[952,1401,2347],"tags":[8670],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/pycharm\/595827"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/pycharm"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/types\/pycharm"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/users\/813"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/comments?post=595827"}],"version-history":[{"count":4,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/pycharm\/595827\/revisions"}],"predecessor-version":[{"id":595854,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/pycharm\/595827\/revisions\/595854"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/media\/595829"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/media?parent=595827"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/categories?post=595827"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/tags?post=595827"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/cross-post-tag?post=595827"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}