Repository: ruleminer/InterpreTS (language: python)

Issue:
Fixes



Discussion / hints:

Fix patch:
diff --git a/examples/core/features/feature_above_9th_decile.ipynb b/examples/core/features/feature_above_9th_decile.ipynb
new file mode 100644
index 0000000..997a539
--- /dev/null
+++ b/examples/core/features/feature_above_9th_decile.ipynb
@@ -0,0 +1,67 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Fraction of values below the 1st decile: 0.6\n"
+     ]
+    }
+   ],
+   "source": [
+    "import pandas as pd\n",
+    "import sys\n",
+    "import os\n",
+    "\n",
+    "# Adding path to interpreTS directory so the notebook can import modules\n",
+    "sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname('__file__'), '../../../InterpreTS')))\n",
+    "\n",
+    "# Importing the feature calculation function\n",
+    "from core.features.feature_above_9th_decile import calculate_above_9th_decile\n",
+    "\n",
+    "# Data preparation\n",
+    "data = pd.Series([8, 9, 10, 11, 12])\n",
+    "training_data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])\n",
+    "\n",
+    "# Function call\n",
+    "below_decile_fraction = calculate_above_9th_decile(data, training_data)\n",
+    "\n",
+    "# Displaying the result\n",
+    "print(f\"Fraction of values below the 1st decile: {below_decile_fraction}\")\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.12.2"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/examples/core/features/feature_absolute_energy.ipynb b/examples/core/features/feature_absolute_energy.ipynb
index 81559a2..fe61b54 100644
--- a/examples/core/features/feature_absolute_energy.ipynb
+++ b/examples/core/features/feature_absolute_energy.ipynb
@@ -2,35 +2,44 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 1,
+   "execution_count": 4,
    "metadata": {},
    "outputs": [],
    "source": [
     "import pandas as pd\n",
-    "from interpreTS import FeatureExtractor, Features, TimeSeriesData"
+    "from interpreTS import FeatureExtractor, TimeSeriesData"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 6,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Absolute energy of time series: \n",
+      "0    275\n",
+      "1     75\n",
+      "2    130\n",
+      "3    194\n",
+      "Name: absolute_energy, dtype: int64\n"
+     ]
+    }
+   ],
    "source": [
+    "#create a time series data\n",
     "raw_data = pd.DataFrame({'time': pd.date_range(start=\"2023-01-01\", periods=8, freq=\"D\"),\n",
-    "                         'value': [15, 3, 6, 2, 1, 5, 8, 10]})\n",
+    "                         'value': [15, -3, 6, 2, 1, -5, 8, 10]})\n",
     "ts_data = TimeSeriesData(raw_data.set_index('time'))\n",
     "\n",
+    "#extract absolute energy feature\n",
+    "extractor = FeatureExtractor(features=[\"absolute_energy\"])\n",
+    "feature = extractor.extract_features(ts_data.data)\n",
     "\n",
-    "extractor1 = FeatureExtractor(features=[Features.ABSOLUTE_ENERGY])\n",
-    "feature1 = extractor1.extract_features(ts_data.data)\n",
-    "\n",
-    "extractor2 = FeatureExtractor(features=[Features.ABSOLUTE_ENERGY], window_size=4,\n",
-    "                              feature_params={\"absolute_energy\": {\"start\": 1, \"end\": 3}})\n",
-    "feature2 = extractor2.extract_features(ts_data.data)\n",
-    "\n",
-    "\n",
-    "print(f\"Absolute energy of time series: \\n{feature1[Features.ABSOLUTE_ENERGY]}\")\n",
-    "print(f\"Absolute energy with params of time series: \\n{feature2[Features.ABSOLUTE_ENERGY]}\")"
+    "#display the results\n",
+    "print(f\"Absolute energy of time series: \\n{feature['absolute_energy']}\")"
    ]
   }
  ],
diff --git a/examples/core/features/feature_below_1st_decile.ipynb b/examples/core/features/feature_below_1st_decile.ipynb
new file mode 100644
index 0000000..39dabaa
--- /dev/null
+++ b/examples/core/features/feature_below_1st_decile.ipynb
@@ -0,0 +1,67 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Fraction of values above the 9th decile: 0.2\n"
+     ]
+    }
+   ],
+   "source": [
+    "import pandas as pd\n",
+    "import sys\n",
+    "import os\n",
+    "\n",
+    "# Adding path to interpreTS directory so the notebook can import modules\n",
+    "sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname('__file__'), '../../../InterpreTS')))\n",
+    "\n",
+    "# Importing the feature calculation function\n",
+    "from core.features.feature_below_1st_decile import calculate_below_1st_decile\n",
+    "\n",
+    "# Data preparation\n",
+    "data = pd.Series([1, 2, 3, 4, 5])\n",
+    "training_data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])\n",
+    "\n",
+    "# Function call\n",
+    "above_decile_fraction = calculate_below_1st_decile(data, training_data)\n",
+    "\n",
+    "# Displaying the result\n",
+    "print(f\"Fraction of values above the 9th decile: {above_decile_fraction}\")\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.12.2"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/examples/core/features/feature_entropy.ipynb b/examples/core/features/feature_entropy.ipynb
index 3aa6161..37eefa6 100644
--- a/examples/core/features/feature_entropy.ipynb
+++ b/examples/core/features/feature_entropy.ipynb
@@ -2,35 +2,43 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 1,
+   "execution_count": 6,
    "metadata": {},
    "outputs": [],
    "source": [
     "import pandas as pd\n",
-    "import sys\n",
-    "import os"
+    "from interpreTS import FeatureExtractor, TimeSeriesData"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 9,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Entropy of time series: 0.9182958340544896\n"
+      "Entropy of time series: \n",
+      "0    0.721928\n",
+      "1    0.864974\n",
+      "2    0.960964\n",
+      "3    0.960964\n",
+      "Name: entropy, dtype: float64\n"
      ]
     }
    ],
    "source": [
-    "sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname('__file__'), '../../../interpreTS')))\n",
-    "from core.features.feature_entropy import calculate_entropy\n",
+    "# Create a time series\n",
+    "data = pd.Series([-3, -2, 13, -533, -10, -150, 220, 303])\n",
+    "ts_data = TimeSeriesData(data)\n",
     "\n",
-    "data = pd.Series([1, 2, 3, 5, 10, 15])\n",
-    "entropy = calculate_entropy(data, 2)\n",
-    "print(f\"Entropy of time series: {entropy}\")"
+    "# Extract the entropy of the time series\n",
+    "extractor = FeatureExtractor(features=[\"entropy\"])\n",
+    "feature = extractor.extract_features(ts_data.data)\n",
+    "\n",
+    "# Print the entropy of the time series\n",
+    "print(f\"Entropy of time series: \\n{feature['entropy']}\")"
    ]
   }
  ],
diff --git a/examples/core/features/feature_flat_spots.ipynb b/examples/core/features/feature_flat_spots.ipynb
index aa85607..7514cb0 100644
--- a/examples/core/features/feature_flat_spots.ipynb
+++ b/examples/core/features/feature_flat_spots.ipynb
@@ -2,42 +2,50 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import pandas as pd\n",
+    "from interpreTS import FeatureExtractor, TimeSeriesData"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "The longest flat spot length is: 4\n"
+      "The longest flat spot length is: \n",
+      "0    3\n",
+      "1    2\n",
+      "2    2\n",
+      "3    2\n",
+      "4    3\n",
+      "5    4\n",
+      "6    5\n",
+      "7    4\n",
+      "8    3\n",
+      "9    2\n",
+      "Name: flat_spots, dtype: int64\n"
      ]
     }
    ],
    "source": [
-    "import pandas as pd\n",
-    "import sys\n",
-    "import os\n",
-    "\n",
-    "# Adding path to interpreTS directory so notebook can import modules\n",
-    "sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname('__file__'), '../../../interpreTS')))\n",
-    "from core.features.feature_flat_spots import calculate_flat_spots\n",
-    "\n",
-    "# Data preparation\n",
+    "#create a time series data\n",
     "data = pd.Series([1, 1, 1, 2, 3, 3, 4, 4, 4, 4, 4, 5, 1, 1])\n",
+    "ts_data = TimeSeriesData(data)\n",
     "\n",
-    "# Function call\n",
-    "longest_flat_spot = calculate_flat_spots(data)\n",
+    "#extract the flat spots feature\n",
+    "extractor = FeatureExtractor(features=[\"flat_spots\"])\n",
+    "feature = extractor.extract_features(ts_data.data)\n",
     "\n",
-    "# Displaying the result\n",
-    "print(f\"The longest flat spot length is: {longest_flat_spot}\")"
+    "#display the flat spots feature\n",
+    "print(f\"The longest flat spot length is: \\n{feature['flat_spots']}\")"
    ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
   }
  ],
  "metadata": {
@@ -56,7 +64,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.12.2"
+   "version": "3.10.1"
   }
  },
  "nbformat": 4,
diff --git a/examples/core/features/feature_heterogeneity.ipynb b/examples/core/features/feature_heterogeneity.ipynb
index 0d4e5e5..41102cf 100644
--- a/examples/core/features/feature_heterogeneity.ipynb
+++ b/examples/core/features/feature_heterogeneity.ipynb
@@ -2,7 +2,7 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 2,
+   "execution_count": 1,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -16,7 +16,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "#extract peak feature from time series data\n",
+    "#extract heterogeneity feature from time series data\n",
     "raw_data = pd.DataFrame({'time': pd.date_range(start=\"2023-01-01\", periods=8, freq=\"D\"),\n",
     "                         'value': [15, 3, 6, 2, 1, 5, 8, 10]})\n",
     "ts_data = TimeSeriesData(raw_data.set_index('time'))\n",
diff --git a/examples/core/features/feature_length.ipynb b/examples/core/features/feature_length.ipynb
index 0ce3b0d..6270524 100644
--- a/examples/core/features/feature_length.ipynb
+++ b/examples/core/features/feature_length.ipynb
@@ -2,46 +2,39 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 1,
    "metadata": {},
    "outputs": [],
    "source": [
-    "pip install pandas"
+    "import pandas as pd\n",
+    "from interpreTS import TimeSeriesData, FeatureExtractor"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 4,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Length Feature: 6\n"
+      "Length Feature: \n",
+      "0    5\n",
+      "1    5\n",
+      "2    5\n",
+      "Name: length, dtype: int64\n"
      ]
     }
    ],
    "source": [
-    "import pandas as pd\n",
-    "import sys\n",
-    "import os\n",
-    "\n",
-    "# Adding path to interpreTS directory so notebook can import modules\n",
-    "sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname('__file__'), '../../../interpreTS')))\n",
-    "from core.time_series_data import TimeSeriesData\n",
-    "from core.feature_extractor import FeatureExtractor\n",
-    "\n",
     "# Data preparation\n",
-    "data = pd.Series([1, 2, 3, 4, 5, 6])\n",
+    "data = pd.Series([1, 2, 3, 4, 5, 6, 7])\n",
     "\n",
     "# Initialization TimeSeriesData\n",
     "ts_data = TimeSeriesData(data)\n",
     "\n",
     "\n",
-    "# Splitting the data into training and test sets\n",
-    "train_data, test_data = ts_data.split(0.6)\n",
-    "\n",
     "# Feature extractor initialization\n",
     "extractor = FeatureExtractor(features=['length'])\n",
     "\n",
@@ -49,15 +42,8 @@
     "features = extractor.extract_features(data)\n",
     "\n",
     "# Displaying results\n",
-    "print(\"Length Feature:\", features['length'])"
+    "print(f\"Length Feature: \\n{features['length']}\")"
    ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
   }
  ],
  "metadata": {
@@ -76,7 +62,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.9.13"
+   "version": "3.12.2"
   }
  },
  "nbformat": 4,
diff --git a/examples/core/features/feature_mean.ipynb b/examples/core/features/feature_mean.ipynb
index adb02a6..f3c6e75 100644
--- a/examples/core/features/feature_mean.ipynb
+++ b/examples/core/features/feature_mean.ipynb
@@ -2,43 +2,44 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 2,
    "metadata": {},
    "outputs": [],
    "source": [
-    "pip install pandas"
+    "import pandas as pd\n",
+    "from interpreTS import FeatureExtractor, TimeSeriesData"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 3,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Mean value of time series: 3.0\n"
+      "Mean value of time series: \n",
+      "0    3.0\n",
+      "1    4.2\n",
+      "2    1.8\n",
+      "3    2.4\n",
+      "Name: mean, dtype: float64\n"
      ]
     }
    ],
    "source": [
-    "import pandas as pd\n",
-    "import sys\n",
-    "import os\n",
-    "\n",
-    "# Adding path to interpreTS directory so notebook can import modules\n",
-    "sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname('__file__'), '../../..')))\n",
-    "from core.features.feature_mean import calculate_mean\n",
-    "\n",
     "# Data preparation\n",
-    "data = pd.Series([1, 2, 3, 4, 5])\n",
+    "data = pd.Series([1, 2, 3, 4, 5, 7, -10, 6])\n",
+    "ts_data = TimeSeriesData(data)\n",
     "\n",
     "# Function call\n",
-    "mean_value = calculate_mean(data)\n",
+    "exteactor = FeatureExtractor(features=[\"mean\"])\n",
+    "\n",
+    "feature = exteactor.extract_features(ts_data.data)\n",
     "\n",
     "# Displaying the result\n",
-    "print(f\"Mean value of time series: {mean_value}\")\n"
+    "print(f\"Mean value of time series: \\n{feature['mean']}\")\n"
    ]
   }
  ],
@@ -58,7 +59,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.9.13"
+   "version": "3.12.2"
   }
  },
  "nbformat": 4,
diff --git a/examples/core/features/feature_missing_points.ipynb b/examples/core/features/feature_missing_points.ipynb
index 9758a39..d167c85 100644
--- a/examples/core/features/feature_missing_points.ipynb
+++ b/examples/core/features/feature_missing_points.ipynb
@@ -2,47 +2,70 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": 6,
    "metadata": {},
    "outputs": [],
    "source": [
     "import pandas as pd\n",
-    "from interpreTS import FeatureExtractor, Features, TimeSeriesData"
+    "from interpreTS import FeatureExtractor, TimeSeriesData"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 7,
    "metadata": {},
    "outputs": [
     {
-     "ename": "AttributeError",
-     "evalue": "type object 'Features' has no attribute 'MISSING_POINTS'",
-     "output_type": "error",
-     "traceback": [
-      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
-      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
-      "Cell \u001b[1;32mIn[4], line 6\u001b[0m\n\u001b[0;32m      3\u001b[0m ts_data \u001b[38;5;241m=\u001b[39m TimeSeriesData(raw_data\u001b[38;5;241m.\u001b[39mset_index(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtime\u001b[39m\u001b[38;5;124m'\u001b[39m))\n\u001b[0;32m      5\u001b[0m \u001b[38;5;66;03m# Extract missing points as a percentage\u001b[39;00m\n\u001b[1;32m----> 6\u001b[0m extractor1 \u001b[38;5;241m=\u001b[39m FeatureExtractor(features\u001b[38;5;241m=\u001b[39m[\u001b[43mFeatures\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mMISSING_POINTS\u001b[49m])\n\u001b[0;32m      7\u001b[0m feature1 \u001b[38;5;241m=\u001b[39m extractor1\u001b[38;5;241m.\u001b[39mextract_features(ts_data\u001b[38;5;241m.\u001b[39mdata)\n\u001b[0;32m      9\u001b[0m \u001b[38;5;66;03m# Extract missing points count over a specified window size\u001b[39;00m\n",
-      "\u001b[1;31mAttributeError\u001b[0m: type object 'Features' has no attribute 'MISSING_POINTS'"
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Missing points percentage of time series: \n",
+      "0     0.4\n",
+      "1     0.4\n",
+      "2     0.2\n",
+      "3     0.2\n",
+      "4     0.4\n",
+      "5     0.4\n",
+      "6     0.4\n",
+      "7     0.4\n",
+      "8     0.4\n",
+      "9     0.2\n",
+      "10    0.0\n",
+      "11    0.0\n",
+      "Name: missing_points, dtype: float64\n",
+      "Missing points count with params of time series: \n",
+      "0     2\n",
+      "1     2\n",
+      "2     1\n",
+      "3     1\n",
+      "4     2\n",
+      "5     2\n",
+      "6     2\n",
+      "7     2\n",
+      "8     2\n",
+      "9     1\n",
+      "10    0\n",
+      "11    0\n",
+      "Name: missing_points, dtype: int64\n"
      ]
     }
    ],
    "source": [
-    "raw_data = pd.DataFrame({'time': pd.date_range(start=\"2023-01-01\", periods=16, freq=\"D\"),\n",
-    "                         'value': [15, None, 6, 2, None, 5, 8, 10, None, None, 12, 14, 16, 18, 20, 22]})\n",
-    "ts_data = TimeSeriesData(raw_data.set_index('time'))\n",
+    "#create a time series data\n",
+    "data = pd.Series([15, None, 6, 2, None, 5, 8, 10, None, None, 12, 14, 16, 18, 20, 22])\n",
+    "ts_data = TimeSeriesData(data)\n",
     "\n",
     "# Extract missing points as a percentage\n",
-    "extractor1 = FeatureExtractor(features=[Features.MISSING_POINTS])\n",
+    "extractor1 = FeatureExtractor(features=[\"missing_points\"])\n",
     "feature1 = extractor1.extract_features(ts_data.data)\n",
     "\n",
-    "# Extract missing points count over a specified window size\n",
-    "extractor2 = FeatureExtractor(features=[Features.MISSING_POINTS], window_size=4,\n",
-    "                               feature_params={\"missing_points\": {\"percentage\": False}})\n",
+    "# Extract missing points count\n",
+    "extractor2 = FeatureExtractor(features=[\"missing_points\"], feature_params={\"missing_points\": {\"percentage\": False}})\n",
     "feature2 = extractor2.extract_features(ts_data.data)\n",
     "\n",
-    "print(f\"Missing points percentage of time series: \\n{feature1[Features.MISSING_POINTS]}\")\n",
-    "print(f\"Missing points count with params of time series: \\n{feature2[Features.MISSING_POINTS]}\")"
+    "# Print results\n",
+    "print(f\"Missing points percentage of time series: \\n{feature1['missing_points']}\")\n",
+    "print(f\"Missing points count with params of time series: \\n{feature2['missing_points']}\")"
    ]
   }
  ],
diff --git a/examples/core/features/feature_peak.ipynb b/examples/core/features/feature_peak.ipynb
index 8e95f3f..8ff005a 100644
--- a/examples/core/features/feature_peak.ipynb
+++ b/examples/core/features/feature_peak.ipynb
@@ -7,12 +7,12 @@
    "outputs": [],
    "source": [
     "import pandas as pd\n",
-    "from interpreTS import FeatureExtractor, Features, TimeSeriesData"
+    "from interpreTS import FeatureExtractor, TimeSeriesData"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": null,
    "metadata": {},
    "outputs": [
     {
@@ -24,34 +24,23 @@
       "1     6\n",
       "2     8\n",
       "3    10\n",
-      "Name: peak, dtype: int64\n",
-      "Peaks with params of time series: \n",
-      "0    6\n",
-      "1    6\n",
-      "2    2\n",
-      "3    5\n",
-      "4    8\n",
       "Name: peak, dtype: int64\n"
      ]
     }
    ],
    "source": [
-    "#extract peak feature from time series data\n",
+    "#create a time series data\n",
     "raw_data = pd.DataFrame({'time': pd.date_range(start=\"2023-01-01\", periods=8, freq=\"D\"),\n",
     "                         'value': [15, 3, 6, 2, 1, 5, 8, 10]})\n",
     "ts_data = TimeSeriesData(raw_data.set_index('time'))\n",
     "\n",
+    "#extract feature\n",
+    "extractor = FeatureExtractor(features=[\"peak\"])\n",
+    "feature = extractor.extract_features(ts_data.data)\n",
     "\n",
-    "extractor1 = FeatureExtractor(features=[Features.PEAK])\n",
-    "feature1 = extractor1.extract_features(ts_data.data)\n",
     "\n",
-    "extractor2 = FeatureExtractor(features=[Features.PEAK], window_size=4,\n",
-    "                              feature_params={\"peak\": {\"start\": 1, \"end\": 3}})\n",
-    "feature2 = extractor2.extract_features(ts_data.data)\n",
-    "\n",
-    "\n",
-    "print(f\"Peaks of time series: \\n{feature1[Features.PEAK]}\")\n",
-    "print(f\"Peaks with params of time series: \\n{feature2[Features.PEAK]}\")"
+    "#display the extracted feature\n",
+    "print(f\"Peaks of time series: \\n{feature['peak']}\")"
    ]
   }
  ],
diff --git a/examples/core/features/feature_significant_changes.ipynb b/examples/core/features/feature_significant_changes.ipynb
new file mode 100644
index 0000000..c76bbe8
--- /dev/null
+++ b/examples/core/features/feature_significant_changes.ipynb
@@ -0,0 +1,57 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Proportion of significant changes in the time series: 0.2222222222222222\n"
+     ]
+    }
+   ],
+   "source": [
+    "import pandas as pd\n",
+    "import sys\n",
+    "import os\n",
+    "\n",
+    "# Adding path to interpreTS directory so notebook can import modules\n",
+    "sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname('__file__'), '../../../interpreTS')))\n",
+    "from core.features.feature_significant_changes import calculate_significant_changes\n",
+    "\n",
+    "# Data preparation\n",
+    "data = pd.Series([1, 2, 3, -90, 5, 10, 15, 20, 25, 30])\n",
+    "\n",
+    "# Function call\n",
+    "proportion_significant_changes = calculate_significant_changes(data)\n",
+    "\n",
+    "# Displaying the result\n",
+    "print(f\"Proportion of significant changes: {proportion_significant_changes}\")\n"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.12.2"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/examples/core/features/feature_stability.ipynb b/examples/core/features/feature_stability.ipynb
index cb20352..57b2d8f 100644
--- a/examples/core/features/feature_stability.ipynb
+++ b/examples/core/features/feature_stability.ipynb
@@ -2,13 +2,12 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 8,
+   "execution_count": 2,
    "metadata": {},
    "outputs": [],
    "source": [
     "import pandas as pd\n",
-    "import sys\n",
-    "import os"
+    "from interpreTS import FeatureExtractor, TimeSeriesData"
    ]
   },
   {
@@ -17,39 +16,35 @@
    "metadata": {},
    "outputs": [
     {
-     "ename": "ModuleNotFoundError",
-     "evalue": "No module named 'statsmodels'",
-     "output_type": "error",
-     "traceback": [
-      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
-      "\u001b[1;31mModuleNotFoundError\u001b[0m                       Traceback (most recent call last)",
-      "Cell \u001b[1;32mIn[9], line 2\u001b[0m\n\u001b[0;32m      1\u001b[0m sys\u001b[38;5;241m.\u001b[39mpath\u001b[38;5;241m.\u001b[39minsert(\u001b[38;5;241m0\u001b[39m, os\u001b[38;5;241m.\u001b[39mpath\u001b[38;5;241m.\u001b[39mabspath(os\u001b[38;5;241m.\u001b[39mpath\u001b[38;5;241m.\u001b[39mjoin(os\u001b[38;5;241m.\u001b[39mpath\u001b[38;5;241m.\u001b[39mdirname(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m__file__\u001b[39m\u001b[38;5;124m'\u001b[39m), \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m../../../interpreTS\u001b[39m\u001b[38;5;124m'\u001b[39m)))\n\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mcore\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mfeatures\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mfeature_stability\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m calculate_stability\n\u001b[0;32m      4\u001b[0m \u001b[38;5;66;03m# Data preparation\u001b[39;00m\n\u001b[0;32m      5\u001b[0m data \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mSeries([\u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m5\u001b[39m, \u001b[38;5;241m5\u001b[39m, \u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m1\u001b[39m])\n",
-      "File \u001b[1;32mc:\\Users\\jayke\\Desktop\\InterpreTS\\InterpreTS-1\\interpreTS\\core\\features\\feature_stability.py:3\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mpandas\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mpd\u001b[39;00m\n\u001b[0;32m      2\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mnumpy\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mnp\u001b[39;00m\n\u001b[1;32m----> 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mstatsmodels\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mtsa\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mstattools\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m acf\n\u001b[0;32m      4\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01minterpreTS\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdata_validation\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m validate_time_series_data\n\u001b[0;32m      6\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mcalculate_stability\u001b[39m(data, max_lag\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m):\n",
-      "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'statsmodels'"
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Stability of time series: \n",
+      "0    0.904521\n",
+      "1    0.821891\n",
+      "2    0.814360\n",
+      "3    0.758704\n",
+      "Name: stability, dtype: float64\n"
      ]
     }
    ],
    "source": [
-    "sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname('__file__'), '../../../interpreTS')))\n",
-    "from core.features.feature_stability import calculate_stability\n",
+    "raw_data = pd.DataFrame({'time': pd.date_range(start=\"2023-01-01\", periods=8, freq=\"D\"),\n",
+    "                         'value': [15, 3, 6, 2, 1, 5, 8, 10]})\n",
+    "ts_data = TimeSeriesData(raw_data.set_index('time'))\n",
     "\n",
-    "data = pd.Series([1, 1, 2, 1, 1, 1, 2])\n",
+    "#extract feature\n",
+    "extractor = FeatureExtractor(features=[\"stability\"])\n",
+    "feature = extractor.extract_features(ts_data.data)\n",
     "\n",
-    "stability = calculate_stability(data)\n",
-    "stability2 = calculate_stability(data, 3)\n",
-    "\n",
-    "print(stability, stability2)\n",
-    "\n",
-    "data2 = pd.Series([1, -8, 5, -2, 5, -4, 4])\n",
-    "\n",
-    "stability3 = calculate_stability(data2)\n",
-    "print(stability3)"
+    "#display the extracted feature\n",
+    "print(f\"Stability of time series: \\n{feature['stability']}\")"
    ]
   }
  ],
  "metadata": {
   "kernelspec": {
-   "display_name": "env",
+   "display_name": "Python 3",
    "language": "python",
    "name": "python3"
   },
diff --git a/examples/core/features/feature_std_1st_der.ipynb b/examples/core/features/feature_std_1st_der.ipynb
index 2fd916a..cbd8ebd 100644
--- a/examples/core/features/feature_std_1st_der.ipynb
+++ b/examples/core/features/feature_std_1st_der.ipynb
@@ -2,42 +2,45 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import pandas as pd\n",
+    "from interpreTS import FeatureExtractor, TimeSeriesData"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "The standard deviation of the first derivative of time series: 3.5128336140500593\n"
+      "standard 1st derivative of time series: \n",
+      "0    4.188078\n",
+      "1    2.353720\n",
+      "2    3.009983\n",
+      "3    1.503330\n",
+      "Name: std_1st_der, dtype: float64\n"
      ]
     }
    ],
    "source": [
-    "import pandas as pd\n",
-    "import sys\n",
-    "import os\n",
-    "\n",
-    "# Adding path to interpreTS directory so notebook can import modules\n",
-    "sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname('__file__'), '../../..')))\n",
-    "from core.features.feature_std_1st_der import calculate_std_1st_der\n",
+    "raw_data = pd.DataFrame({'time': pd.date_range(start=\"2023-01-01\", periods=8, freq=\"D\"),\n",
+    "                         'value': [15, 3, 6, 2, 1, 5, 8, 10]})\n",
+    "ts_data = TimeSeriesData(raw_data.set_index('time'))\n",
     "\n",
-    "# Data preparation\n",
-    "data = pd.Series([1, -1, 2, -3, 5])\n",
+    "#extract feature\n",
+    "extractor = FeatureExtractor(features=[\"std_1st_der\"])\n",
+    "feature = extractor.extract_features(ts_data.data)\n",
     "\n",
-    "# Function call\n",
-    "std_1st_der = calculate_std_1st_der(data)\n",
     "\n",
-    "# Displaying the result\n",
-    "print(f\"The standard deviation of the first derivative of time series: {std_1st_der}\")\n"
+    "#display the extracted feature\n",
+    "print(f\"standard 1st derivative of time series: \\n{feature['std_1st_der']}\")"
    ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
   }
  ],
  "metadata": {
@@ -56,7 +59,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.12.2"
+   "version": "3.10.1"
   }
  },
  "nbformat": 4,
diff --git a/examples/core/features/feature_trough.ipynb b/examples/core/features/feature_trough.ipynb
index 40964db..2f3547d 100644
--- a/examples/core/features/feature_trough.ipynb
+++ b/examples/core/features/feature_trough.ipynb
@@ -7,12 +7,12 @@
    "outputs": [],
    "source": [
     "import pandas as pd\n",
-    "from interpreTS import FeatureExtractor, Features, TimeSeriesData"
+    "from interpreTS import FeatureExtractor, TimeSeriesData"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 3,
    "metadata": {},
    "outputs": [
     {
@@ -24,13 +24,6 @@
       "1    -5\n",
       "2    -5\n",
       "3   -10\n",
-      "Name: trough, dtype: int64\n",
-      "Troughs with params of time series: \n",
-      "0   -3\n",
-      "1    2\n",
-      "2    1\n",
-      "3   -5\n",
-      "4   -5\n",
       "Name: trough, dtype: int64\n"
      ]
     }
@@ -41,15 +34,11 @@
     "                         'value': [15, -3, 6, 2, 1, -5, 8, -10]})\n",
     "ts_data = TimeSeriesData(raw_data.set_index('time'))\n",
     "\n",
-    "extractor1 = FeatureExtractor(features=[Features.TROUGH])\n",
-    "feature1 = extractor1.extract_features(ts_data.data)\n",
+    "extractor = FeatureExtractor(features=[\"trough\"])\n",
+    "feature = extractor.extract_features(ts_data.data)\n",
     "\n",
-    "extractor2 = FeatureExtractor(features=[Features.TROUGH], window_size=4,\n",
-    "                              feature_params={\"trough\": {\"start\": 1, \"end\": 3}})\n",
-    "feature2 = extractor2.extract_features(ts_data.data)\n",
     "\n",
-    "print(f\"Troughs of time series: \\n{feature1[Features.TROUGH]}\")\n",
-    "print(f\"Troughs with params of time series: \\n{feature2[Features.TROUGH]}\")\n"
+    "print(f\"Troughs of time series: \\n{feature['trough']}\")"
    ]
   }
  ],
diff --git a/examples/core/features/feature_variance.ipynb b/examples/core/features/feature_variance.ipynb
index a8701c7..f5be41c 100644
--- a/examples/core/features/feature_variance.ipynb
+++ b/examples/core/features/feature_variance.ipynb
@@ -25,22 +25,7 @@
    ],
    "source": [
     "import pandas as pd\n",
-    "import sys\n",
-    "import os\n",
-    "\n",
-    "# Adding path to interpreTS directory so notebook can import modules\n",
-    "sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname('__file__'), '../../../interpreTS')))\n",
-    "from core.features.feature_variance import calculate_variance\n",
-    "\n",
-    "# Data preparation\n",
-    "data = pd.Series([1, 2, 3, 4, 5])\n",
-    "\n",
-    "# Function call\n",
-    "variance = calculate_variance(data)\n",
-    "\n",
-    "# Displaying the result\n",
-    "print(f\"Variance of time series: {variance}\")\n",
-    "\n"
+    "from interpreTS import FeatureExtractor, TimeSeriesData"
    ]
   },
   {
@@ -48,7 +33,18 @@
    "execution_count": null,
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "# Extract variance feature from time series data\n",
+    "raw_data = pd.DataFrame({'time': pd.date_range(start=\"2023-01-01\", periods=8, freq=\"D\"),\n",
+    "                         'value': [15, -3, 6, 2, 1, -5, 8, -10]})\n",
+    "ts_data = TimeSeriesData(raw_data.set_index('time'))\n",
+    "\n",
+    "extractor = FeatureExtractor(features=[\"variance\"])\n",
+    "feature = extractor.extract_features(ts_data.data)\n",
+    "\n",
+    "\n",
+    "print(f\"Troughs of time series: \\n{feature['variance']}\")"
+   ]
   }
  ],
  "metadata": {
diff --git a/interpreTS/__init__.py b/interpreTS/__init__.py
index 4f00d12..c986315 100644
--- a/interpreTS/__init__.py
+++ b/interpreTS/__init__.py
@@ -1,6 +1,54 @@
-from .core.streaming_feature_extractor import StreamingFeatureExtractor
+"""
+interpreTS: A library for time series analysis and feature extraction.
+
+Available imports:
+- FeatureExtractor: Extracts features from time series data.
+- StreamingFeatureExtractor: Processes streaming time series data.
+- Features: Contains constants for supported feature calculations.
+- TimeSeriesData: Utility class for handling and manipulating time series data.
+- convert_to_time_series: Converts raw data into a time series format.
+- validate_time_series_data: Validates the integrity and format of time series data.
+
+Dependencies:
+- pandas>=1.1.0
+- numpy>=1.18.0
+- statsmodels>=0.12.0
+- pytest
+"""
+
+# from .core.streaming_feature_extractor import StreamingFeatureExtractor
 from .core.feature_extractor import FeatureExtractor
 from .core.feature_extractor import Features
-from .core.time_series_data import TimeSeriesData
-from .utils.data_conversion import convert_to_time_series
-from .utils.data_validation import validate_time_series_data
\ No newline at end of file
+# from .core.time_series_data import TimeSeriesData
+# from .utils.data_conversion import convert_to_time_series
+from .utils.data_validation import validate_time_series_data
+
+__version__ = "0.3.0"
+
+__all__ = [
+    "FeatureExtractor",
+    "StreamingFeatureExtractor",
+    "Features",
+    "TimeSeriesData",
+    "convert_to_time_series",
+    "validate_time_series_data",
+]
+
+# Check required dependencies
+required_libraries = {
+    "pandas": "1.1.0",
+    "numpy": "1.18.0",
+    "statsmodels": "0.12.0",
+    "statsmodels": None,
+    "pytest": None,  
+}
+
+for library, min_version in required_libraries.items():
+    try:
+        module = __import__(library)
+        if min_version:
+            from packaging import version
+            if version.parse(module.__version__) < version.parse(min_version):
+                print(f"Warning: {library} version must be >= {min_version}. Current version: {module.__version__}")
+    except ImportError:
+        print(f"Warning: {library} is not installed. Please install it to use interpreTS.")
diff --git a/interpreTS/core/feature_extractor.py b/interpreTS/core/feature_extractor.py
index 1125b34..df965b6 100644
--- a/interpreTS/core/feature_extractor.py
+++ b/interpreTS/core/feature_extractor.py
@@ -1,86 +1,235 @@
 import pandas as pd
 import numpy as np
 
-from .features.feature_binarize_mean import calculate_binarize_mean
-from .features.feature_crossing_points import calculate_crossing_points
 from .features.feature_spikeness import calculate_spikeness
-from .features.feature_peak import calculate_peak
-from .features.feature_trough import calculate_trough
+from .features.feature_entropy import calculate_entropy
+from .features.feature_stability import calculate_stability
 from .features.feature_length import calculate_length
 from .features.feature_mean import calculate_mean
 from .features.seasonality_strength import calculate_seasonality_strength
 from .features.feature_variance import calculate_variance
-from .features.feature_std_1st_der import calculate_std_1st_der
-from .features.feature_absolute_energy import absolute_energy
-from .features.feature_entropy import calculate_entropy
-from .features.feature_stability import calculate_stability
-from .features.feature_flat_spots import calculate_flat_spots
-from .features.feature_missing_points import missing_points
+# from .features.feature_peak import calculate_peak
+# from .features.feature_trough import calculate_trough
+# from .features.feature_std_1st_der import calculate_std_1st_der
+# from .features.feature_heterogeneity import heterogeneity
+# from .features.feature_absolute_energy import absolute_energy
+# from .features.feature_flat_spots import calculate_flat_spots
+# from .features.feature_missing_points import missing_points
+# from .features.feature_outliers_std import calculate_outliers_std
+# from .features.feature_binarize_mean import calculate_binarize_mean
+# from .features.feature_binarize_mean import calculate_binarize_mean
+# from .features.feature_outliers_iqr import calculate_outliers_iqr
+# from .features.feature_significant_changes import calculate_significant_changes
+# from .features.feature_above_9th_decile import calculate_above_9th_decile
+# from .features.feature_below_1st_decile import calculate_below_1st_decile
+# from .features.feature_binarize_mean import calculate_binarize_mean
+# from .features.feature_crossing_points import calculate_crossing_points
 
 class Features:
     LENGTH = 'length'
     MEAN = 'mean'
-    PEAK = 'peak'
-    STD_1ST_DER = 'std_1st_der'
-    TROUGH = 'trough'
     VARIANCE = 'variance'
     SPIKENESS = 'spikeness'
     ENTROPY = 'entropy'
     CALCULATE_SEASONALITY_STRENGTH = 'seasonality_strength'
-    ABSOLUTE_ENERGY = 'absolute_energy'
     STABILITY = 'stability'
-    FLAT_SPOTS = 'flat_spots'
-    CROSSING_POINTS = 'crossing_points'
-    MISSING_POINTS = 'missing_points'
-    BINARIZE_MEAN = 'binarize_mean'
+    # PEAK = 'peak'
+    # STD_1ST_DER = 'std_1st_der'
+    # TROUGH = 'trough'
+    # HETEROGENEITY = 'heterogeneity'
+    # ABSOLUTE_ENERGY = 'absolute_energy'
+    # FLAT_SPOTS = 'flat_spots'
+    # CROSSING_POINTS = 'crossing_points'
+    # MISSING_POINTS = 'missing_points'
+    # BINARIZE_MEAN = 'binarize_mean'
+    # OUTLIERS_STD = 'outliers_std'
+    # OUTLIERS_IQR = 'outliers_iqr'
+    # SIGNIFICANT_CHANGES = 'significant_changes'
+    # ABOVE_9TH_DECILE = 'above_9th_decile'
+    # BELOW_1ST_DECILE = 'below_1st_decile'
 
 class FeatureExtractor:
-    def __init__(self, features=None, feature_params=None, window_size=5, stride=1, id_column=None, sort_column=None):
+    DEFAULT_FEATURES = [
+        Features.LENGTH, Features.MEAN, Features.VARIANCE, Features.STABILITY,
+        Features.ENTROPY, Features.SPIKENESS, Features.CALCULATE_SEASONALITY_STRENGTH
+    ]
+
+    def __init__(self, features=None, feature_params=None, window_size=np.nan, stride=1, id_column=None, sort_column=None, feature_column=None):
         """
         Initialize the FeatureExtractor with a list of features to calculate and optional parameters for each feature.
-        
+
         Parameters
         ----------
         features : list of Features constants, optional
             A list of features to calculate. Default is None, which calculates all available features.
         feature_params : dict, optional
             Parameters for specific features, where keys are feature names and values are dicts of parameters.
-        window_size : int, optional
-            The size of the window for feature extraction (default is 5).
+        window_size : int or float (NaN), optional
+            The size of the window for feature extraction. If NaN (default), the entire series is used as a single window.
         stride : int, optional
             The step size for moving the window (default is 1).
         id_column : str, optional
             The name of the column used to identify different time series (optional).
         sort_column : str, optional
             The column to sort by before feature extraction (optional).
+        feature_column : str or None, optional
+            The column containing feature data. If None, features are calculated for all columns except ID and sort columns.
+        Raises
+        -------
+        ValueError
+            If any parameter is invalid.
         """
-        
-        self.features = features if features is not None else [Features.LENGTH]
+        self._validate_parameters(features, feature_params, window_size, stride, id_column, sort_column)
+
+        self.features = features if features is not None else self.DEFAULT_FEATURES
         self.feature_params = feature_params if feature_params is not None else {}
         self.window_size = window_size
         self.stride = stride
         self.id_column = id_column
         self.sort_column = sort_column
+        self.feature_column = feature_column
 
-        # Map of feature names to calculation functions
         self.feature_functions = {
             Features.LENGTH: calculate_length,
             Features.MEAN: calculate_mean,
-            Features.PEAK: calculate_peak,
-            Features.STD_1ST_DER: calculate_std_1st_der,
-            Features.TROUGH: calculate_trough,
             Features.VARIANCE: calculate_variance,
             Features.SPIKENESS: calculate_spikeness,
-            Features.CALCULATE_SEASONALITY_STRENGTH: calculate_seasonality_strength,
-            Features.ABSOLUTE_ENERGY: absolute_energy,
             Features.ENTROPY: calculate_entropy,
             Features.STABILITY: calculate_stability,
-            Features.FLAT_SPOTS: calculate_flat_spots, 
-            Features.CROSSING_POINTS: calculate_crossing_points, 
-            Features.MISSING_POINTS: missing_points,
-            Features.BINARIZE_MEAN: calculate_binarize_mean,
+            Features.CALCULATE_SEASONALITY_STRENGTH: calculate_seasonality_strength,
+            # Features.PEAK: calculate_peak,
+            # Features.STD_1ST_DER: calculate_std_1st_der,
+            # Features.TROUGH: calculate_trough,
+            # Features.HETEROGENEITY: heterogeneity,
+            # Features.ABSOLUTE_ENERGY: absolute_energy,
+            # Features.FLAT_SPOTS: calculate_flat_spots,
+            # Features.CROSSING_POINTS: calculate_crossing_points,
+            # Features.MISSING_POINTS: missing_points,
+            # Features.BINARIZE_MEAN: calculate_binarize_mean,
+            # Features.OUTLIERS_STD: calculate_outliers_std,
+            # Features.OUTLIERS_IQR: calculate_outliers_iqr,
+            # Features.SIGNIFICANT_CHANGES: calculate_significant_changes,
+            # Features.ABOVE_9TH_DECILE: calculate_above_9th_decile,
+            # Features.BELOW_1ST_DECILE: calculate_below_1st_decile
+        }
+
+        self.feature_metadata = {
+            Features.LENGTH: {
+                'level': 'easy',
+                'description': 'Number of points in the window.'
+            },
+            Features.MEAN: {
+                'level': 'easy',
+                'description': 'Mean value within the window.'
+            },
+            Features.VARIANCE: {
+                'level': 'moderate',
+                'description': 'Variance of the signal within the window.'
+            },
+            Features.ENTROPY: {
+                'level': 'advanced',
+                'description': 'Degree of randomness or disorder in the window.'
+            },
+            Features.SPIKENESS: {
+                'level': 'moderate',
+                'description': 'Measure of sudden jumps or spikes in the signal.'
+            },
+            Features.CALCULATE_SEASONALITY_STRENGTH: {
+                'level': 'advanced',
+                'description': 'Strength of seasonal patterns within the signal.'
+            },
+            Features.STABILITY: {
+                'level': 'moderate',
+                'description': 'Measure of consistency in the signal values.'
+            },
+            # Features.FLAT_SPOTS: {
+            #     'level': 'easy',
+            #     'description': 'Number of segments with constant values in the signal.'
+            # },
+            # Features.CROSSING_POINTS: {
+            #     'level': 'easy',
+            #     'description': 'Number of times the signal crosses its mean.'
+            # },
+            # Features.PEAK: {
+            #     'level': 'easy',
+            #     'description': 'The maximum value in the window.'
+            # },
+            # Features.TROUGH: {
+            #     'level': 'easy',
+            #     'description': 'The minimum value in the window.'
+            # },
+            #             Features.ABSOLUTE_ENERGY: {
+            #     'level': 'advanced',
+            #     'description': 'Total energy of the signal in the window.'
+            # },
+            # Features.STD_1ST_DER: {
+            #     'level': 'moderate',
+            #     'description': 'Standard deviation of the first derivative of the signal.'
+            # },
+            # Features.MISSING_POINTS: {
+            #     'level': 'easy',
+            #     'description': 'Proportion or count of missing data points in the window.'
+            # },
+            # Features.BINARIZE_MEAN: {
+            #     'level': 'moderate',
+            #     'description': 'Binary value indicating whether the signal mean exceeds a threshold.'
+            # },
         }
 
+    def head(self, features_df, n=5):
+        """
+        Zwraca pierwsze n wierszy wynikowego DataFrame z funkcji extract_features.
+
+        Parametry
+        ----------
+        features_df : pd.DataFrame
+            DataFrame wynikowy z funkcji extract_features.
+        n : int, opcjonalne (domyślnie 5)
+            Liczba wierszy do zwrócenia. Jeśli n jest ujemne, zwraca wszystkie wiersze oprócz ostatnich |n| wierszy.
+
+        Zwraca
+        -------
+        pd.DataFrame
+            Pierwsze n wierszy DataFrame.
+        """
+        if not isinstance(features_df, pd.DataFrame):
+            raise ValueError("Input must be a DataFrame.")
+        if len(features_df) < n:
+            print(f"Warning: Only {len(features_df)} rows available in DataFrame.")
+        return features_df.head(n)
+
+    @staticmethod
+    def _validate_parameters(features, feature_params, window_size, stride, id_column, sort_column):
+        """
+        Validate input parameters to ensure they are valid.
+
+        Raises
+        ------
+        ValueError
+            If any parameter is invalid.
+        """
+        available_features = FeatureExtractor.available_features()
+
+        if features is not None:
+            if not isinstance(features, list):
+                raise ValueError("Features must be a list or None.")
+            invalid_features = [feature for feature in features if feature not in available_features]
+            if invalid_features:
+                raise ValueError(
+                    f"The following features are invalid or not implemented: {invalid_features}. "
+                    f"Available features are: {available_features}."
+                )
+        if feature_params is not None and not isinstance(feature_params, dict):
+            raise ValueError("Feature parameters must be a dictionary or None.")
+        if not (np.isnan(window_size) or (isinstance(window_size, (int, float)) and window_size > 0)):
+            raise ValueError("Window size must be a positive number or NaN.")
+        if not isinstance(stride, int) or stride <= 0:
+            raise ValueError("Stride must be a positive integer.")
+        if id_column is not None and not isinstance(id_column, str):
+            raise ValueError("ID column must be a string or None.")
+        if sort_column is not None and not isinstance(sort_column, str):
+            raise ValueError("Sort column must be a string or None.")
+
     def extract_features(self, data):
         """
         Extract features from a time series dataset.
@@ -95,41 +244,122 @@ def extract_features(self, data):
         pd.DataFrame
             A DataFrame containing calculated features for each window.
         """
-        # Convert Series to DataFrame with 'value' column if necessary
+        if data.empty:
+            print("Warning: Input data is empty. Returning an empty DataFrame.")
+            return pd.DataFrame()
+
         if isinstance(data, pd.Series):
-            data = data.to_frame(name='value')
+            data = data.to_frame(name=self.feature_column)
 
-        # Sort data if sort_column is provided
         if self.sort_column:
             data = data.sort_values(by=self.sort_column)
 
-        # Group by id_column if provided``
+        # Wyklucz kolumny ID i sort_column, jeśli feature_column=None
+        feature_columns = (
+            [self.feature_column] if self.feature_column else
+            [col for col in data.columns if col not in {self.id_column, self.sort_column}]
+        )
+
         grouped_data = data.groupby(self.id_column) if self.id_column else [(None, data)]
 
         results = []
-
-        # Process each group separately
         for _, group in grouped_data:
-            for start in range(0, len(group) - self.window_size + 1, self.stride):
-                window = group.iloc[start:start + self.window_size]
+            group_length = len(group)
+            window_size = group_length if np.isnan(self.window_size) else int(self.window_size)
+
+            if window_size > group_length:
+                print(f"Warning: Window size ({window_size}) exceeds group length ({group_length}). Skipping group.")
+                continue
+
+            for start in range(0, group_length - window_size + 1, self.stride):
+                window = group.iloc[start:start + window_size]
                 extracted_features = {self.id_column: group[self.id_column].iloc[0]} if self.id_column else {}
 
-                # Calculate each selected feature on the window
                 for feature_name in self.features:
                     if feature_name in self.feature_functions:
                         params = self.feature_params.get(feature_name, {})
-                        feature_data = window['value'] if 'value' in window else window.iloc[:, 0]
-                        extracted_features[feature_name] = self.feature_functions[feature_name](feature_data, **params)
+                        for col in feature_columns:
+                            try:
+                                feature_data = window[col].dropna()
+
+                                # Walidacja danych przed obliczeniami
+                                if feature_data.empty:
+                                    extracted_features[f"{feature_name}_{col}"] = np.nan
+                                    continue
+                                if feature_data.nunique() == 1:
+                                    # Stałe dane, np. wszystkie wartości są takie same
+                                    extracted_features[f"{feature_name}_{col}"] = np.nan
+                                    continue
+                                if len(feature_data) < 2:
+                                    # Za mało danych, aby wykonać obliczenia
+                                    extracted_features[f"{feature_name}_{col}"] = np.nan
+                                    continue
+
+                                # Wywołanie funkcji cechy
+                                extracted_features[f"{feature_name}_{col}"] = self.feature_functions[feature_name](
+                                    feature_data, **params
+                                )
+                            except Exception as e:
+                                print(f"Warning: Failed to calculate {feature_name} for column {col}: {e}")
+                                extracted_features[f"{feature_name}_{col}"] = np.nan
 
                 results.append(extracted_features)
 
-        return pd.DataFrame(results) 
+        if not results:
+            print("Warning: No features could be extracted. Returning an empty DataFrame.")
+            return pd.DataFrame()
+
+        return pd.DataFrame(results)
+    
+    def group_features_by_interpretability(self):
+        """
+        Group features by their interpretability levels.
+
+        Returns
+        -------
+        dict
+            A dictionary where keys are interpretability levels ('easy', 'moderate', 'advanced'),
+            and values are lists of feature names.
+        """
+        groups = {'easy': [], 'moderate': [], 'advanced': []}
+        for feature_name, metadata in self.feature_metadata.items():
+            level = metadata['level']
+            groups[level].append(feature_name)
+        return groups
+    
+    def generate_feature_descriptions(self, extracted_features):
+        """
+        Generate textual descriptions for extracted features.
+
+        Parameters
+        ----------
+        extracted_features : dict
+            A dictionary where keys are feature names and values are their calculated values.
+
+        Returns
+        -------
+        dict
+            A dictionary where keys are feature names and values are textual descriptions.
+        """
+        descriptions = {}
+        for feature_name, feature_value in extracted_features.items():
+            if feature_name in self.feature_metadata:
+                metadata = self.feature_metadata[feature_name]
+                description = metadata['description']
+                descriptions[feature_name] = (
+                    f"Feature '{feature_name}': {description} Value: {feature_value}."
+                )
+            else:
+                descriptions[feature_name] = (
+                    f"Unknown feature: '{feature_name}'. Value: {feature_value}."
+                )
+        return descriptions
 
     @staticmethod
     def available_features():
         """
         Returns a list of all available features.
-        
+
         Returns
         -------
         list
diff --git a/interpreTS/core/features/feature_above_9th_decile.py b/interpreTS/core/features/feature_above_9th_decile.py
new file mode 100644
index 0000000..4979a3f
--- /dev/null
+++ b/interpreTS/core/features/feature_above_9th_decile.py
@@ -0,0 +1,59 @@
+import pandas as pd
+import numpy as np
+from interpreTS.utils.data_validation import validate_time_series_data
+
+def calculate_above_9th_decile(data, training_data):
+    """
+    Calculate the fraction of values in the window above the 9th decile of the training data.
+    
+    Parameters
+    ----------
+    data : pd.Series or np.ndarray
+        The time series data for which the fraction is to be calculated.
+    training_data : pd.Series or np.ndarray
+        The training data to determine the 9th decile.
+        
+    Returns
+    -------
+    float
+        The fraction of values in the window above the 9th decile, in the range [0, 1].
+        
+    Raises
+    ------
+    TypeError
+        If the data is not a valid time series type.
+    ValueError
+        If the data contains NaN values or is empty.
+        
+    Examples
+    --------
+    >>> import pandas as pd
+    >>> data = pd.Series([8, 9, 10, 11, 12])
+    >>> training_data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+    >>> calculate_above_9th_decile(data, training_data)
+    0.6
+    """
+    # Validate the time series data
+    validate_time_series_data(data, require_datetime_index=False)
+    validate_time_series_data(training_data, require_datetime_index=False)
+    
+    # Ensure data is not empty
+    if len(data) == 0 or len(training_data) == 0:
+        raise ValueError("Data and training data must not be empty.")
+    
+    # Ensure no NaN values in the input
+    if np.any(pd.isna(data)) or np.any(pd.isna(training_data)):
+        raise ValueError("Data and training data must not contain NaN values.")
+    
+    # Convert to NumPy arrays for consistency
+    data = np.asarray(data)
+    training_data = np.asarray(training_data)
+    
+    # Calculate the 9th decile of the training data
+    ninth_decile = np.percentile(training_data, 90)
+    
+    # Calculate the fraction of values above the 9th decile
+    above_decile_count = np.sum(data > ninth_decile)
+    above_decile_fraction = above_decile_count / len(data)
+    
+    return above_decile_fraction
diff --git a/interpreTS/core/features/feature_below_1st_decile.py b/interpreTS/core/features/feature_below_1st_decile.py
new file mode 100644
index 0000000..f29e619
--- /dev/null
+++ b/interpreTS/core/features/feature_below_1st_decile.py
@@ -0,0 +1,59 @@
+import pandas as pd
+import numpy as np
+from interpreTS.utils.data_validation import validate_time_series_data
+
+def calculate_below_1st_decile(data, training_data):
+    """
+    Calculate the fraction of values in the window below the 1st decile of the training data.
+    
+    Parameters
+    ----------
+    data : pd.Series or np.ndarray
+        The time series data for which the fraction is to be calculated.
+    training_data : pd.Series or np.ndarray
+        The training data to determine the 1st decile.
+        
+    Returns
+    -------
+    float
+        The fraction of values in the window below the 1st decile, in the range [0, 1].
+        
+    Raises
+    ------
+    TypeError
+        If the data is not a valid time series type.
+    ValueError
+        If the data contains NaN values or is empty.
+        
+    Examples
+    --------
+    >>> import pandas as pd
+    >>> data = pd.Series([1, 2, 3, 4, 5])
+    >>> training_data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+    >>> calculate_below_1st_decile(data, training_data)
+    0.2
+    """
+    # Validate the time series data
+    validate_time_series_data(data, require_datetime_index=False)
+    validate_time_series_data(training_data, require_datetime_index=False)
+    
+    # Ensure data is not empty
+    if len(data) == 0 or len(training_data) == 0:
+        raise ValueError("Data and training data must not be empty.")
+    
+    # Ensure no NaN values in the input
+    if np.any(pd.isna(data)) or np.any(pd.isna(training_data)):
+        raise ValueError("Data and training data must not contain NaN values.")
+    
+    # Convert to NumPy arrays for consistency
+    data = np.asarray(data)
+    training_data = np.asarray(training_data)
+    
+    # Calculate the 1st decile of the training data
+    first_decile = np.percentile(training_data, 10)
+    
+    # Calculate the fraction of values below the 1st decile
+    below_decile_count = np.sum(data < first_decile)
+    below_decile_fraction = below_decile_count / len(data)
+    
+    return below_decile_fraction
diff --git a/interpreTS/core/features/feature_entropy.py b/interpreTS/core/features/feature_entropy.py
index bda12c5..f3105e7 100644
--- a/interpreTS/core/features/feature_entropy.py
+++ b/interpreTS/core/features/feature_entropy.py
@@ -2,7 +2,7 @@
 import numpy as np
 from interpreTS.utils.data_validation import validate_time_series_data
 
-def calculate_entropy(data, bins=None):
+def calculate_entropy(data, bins=2):
     """
     Calculate the entropy of a time series based on its value distribution.
 
@@ -11,60 +11,40 @@ def calculate_entropy(data, bins=None):
     data : pd.Series or np.ndarray
         The time series data for which the entropy is to be calculated.
     bins : int, optional
-        The number of bins to use for discretizing the data. 
-        Default is 10.
+        The number of bins to use for discretizing the data. Default is 2.
 
     Returns
     -------
     float
-        The normalized entropy, ranging from 0 to 1, where 0 indicates 
-        no entropy (completely predictable) and 1 indicates maximum entropy 
-        (completely random).
+        The normalized entropy, ranging from 0 to 1.
 
     Raises
     ------
     TypeError
-        If the data is not a valid time series type.
+        If the data is not numeric or not a valid time series type.
     ValueError
-        If the data contains NaN values or is too short to calculate entropy.
+        If the data contains NaN values, is too short, or bins < 2.
     """
-    # Validate the time series data
-    validate_time_series_data(data, require_datetime_index=False)
-    
-    # Convert data to numpy array if it's a pandas Series
-    if isinstance(data, pd.Series):
-        data = data.values
-        
-    # Handle empty or insufficient data
-    if len(data) == 0:
-        raise ValueError("The input data is empty.")
+    # Validate data, disallowing NaN values
+    validate_time_series_data(data, allow_nan=False)
+
+    # Ensure data is numeric
+    if not np.issubdtype(data.dtype, np.number):
+        raise TypeError("Data must be numeric.")
+
     if len(data) < 2:
-        raise ValueError("The input data is too short to calculate entropy.")
-    
-    if bins is None:
-        bins = len(data)
-    
+        raise ValueError("Input data is too short to calculate entropy.")
+    if bins < 2:
+        raise ValueError("Number of bins must be at least 2.")
+
     # Check for constant values
-    if np.all(data == data[0]):
+    if np.ptp(data) == 0:
         return 0.0  # No entropy for constant values
-    
-    # Discretize the data into bins and get the histogram
-    hist, _ = np.histogram(data, bins=bins, density=True)
-    
-    # Normalize histogram to get a probability distribution
-    probabilities = hist / np.sum(hist)
-    
-    # Filter out zero probabilities to avoid log(0)
-    probabilities = probabilities[probabilities > 0]
-    
-    # Calculate Shannon entropy manually
+
+    unique, counts = np.unique(data, return_counts=True)
+    probabilities = counts / len(data)
     shannon_entropy = -np.sum(probabilities * np.log2(probabilities))
-    
-    # Normalize the entropy to range [0, 1]
-    max_entropy = np.log2(len(probabilities))
+    max_entropy = np.log2(len(unique))
     normalized_entropy = shannon_entropy / max_entropy if max_entropy > 0 else 0.0
-    
-    # Ensure the result is within [0, 1]
-    normalized_entropy = max(0.0, min(normalized_entropy, 1.0))
-    
-    return normalized_entropy
\ No newline at end of file
+
+    return normalized_entropy
diff --git a/interpreTS/core/features/feature_heterogeneity.py b/interpreTS/core/features/feature_heterogeneity.py
new file mode 100644
index 0000000..e6bacd8
--- /dev/null
+++ b/interpreTS/core/features/feature_heterogeneity.py
@@ -0,0 +1,52 @@
+import pandas as pd
+import numpy as np
+from interpreTS.utils.data_validation import validate_time_series_data
+
+def heterogeneity(data):
+    """
+    Calculate the heterogeneity (coefficient of variation) of a time series.
+
+    Parameters
+    ----------
+    data : pd.Series or np.ndarray
+        The time series data for which the heterogeneity is to be calculated.
+
+    Returns
+    -------
+    float
+        The heterogeneity (coefficient of variation) of the provided time series.
+
+    Raises
+    ------
+    TypeError
+        If the data is not a valid time series type.
+    ValueError
+        If the data contains NaN values or if the mean of the series is zero.
+
+    Examples
+    --------
+    >>> import pandas as pd
+    >>> data = pd.Series([1, 2, 3, 4, 5])
+    >>> calculate_heterogeneity(data)
+    0.5270462766947299
+    """
+    # Validate the time series without requiring a DateTime index
+    validate_time_series_data(data, require_datetime_index=False)
+    
+    # Ensure data is a pandas Series for compatibility
+    if isinstance(data, np.ndarray):
+        data = pd.Series(data)
+    
+    # Calculate mean and standard deviation
+    mean = data.mean()
+    std_dev = data.std()
+    
+    # Handle empty series
+    if len(data) == 0:
+        return np.nan
+    
+    # Handle a single value in the series
+    if len(data) == 1:
+        return 0.0  # No variability
+    
+    return std_dev / abs(mean) if mean != 0 else np.nan
diff --git a/interpreTS/core/features/feature_length.py b/interpreTS/core/features/feature_length.py
index 9cd9ea7..e795403 100644
--- a/interpreTS/core/features/feature_length.py
+++ b/interpreTS/core/features/feature_length.py
@@ -1,4 +1,6 @@
 from interpreTS.utils.data_validation import validate_time_series_data
+import numpy as np
+import pandas as pd
 
 def calculate_length(data):
     """
@@ -19,7 +21,7 @@ def calculate_length(data):
     TypeError
         If the data is not a valid time series type.
     ValueError
-        If the data contains NaN values.
+        If the data contains NaN values or is not one-dimensional.
         
     Examples
     --------
@@ -31,5 +33,11 @@ def calculate_length(data):
     # Validate the time series without requiring a DateTime index
     validate_time_series_data(data, require_datetime_index=False)
     
+    # Check if the data is one-dimensional
+    if isinstance(data, np.ndarray) and data.ndim != 1:
+        raise ValueError("Data must be one-dimensional.")
+    if isinstance(data, pd.Series) and len(data.shape) != 1:
+        raise ValueError("Data must be one-dimensional.")
+
     # Return the length of the data
     return len(data)
diff --git a/interpreTS/core/features/feature_mean.py b/interpreTS/core/features/feature_mean.py
index a31cc94..9486abe 100644
--- a/interpreTS/core/features/feature_mean.py
+++ b/interpreTS/core/features/feature_mean.py
@@ -31,7 +31,7 @@ def calculate_mean(data):
     3.0
     """
     # Validate the time series without requiring a DateTime index
-    validate_time_series_data(data, require_datetime_index=False)
+    validate_time_series_data(data, require_datetime_index=False, allow_nan=False)
     
     # Calculate and return the mean, handling empty series by returning NaN
     return data.mean() if len(data) > 0 else np.nan
diff --git a/interpreTS/core/features/feature_outliers_iqr.py b/interpreTS/core/features/feature_outliers_iqr.py
new file mode 100644
index 0000000..df46e21
--- /dev/null
+++ b/interpreTS/core/features/feature_outliers_iqr.py
@@ -0,0 +1,34 @@
+import numpy as np
+
+def calculate_outliers_iqr(data, training_data):
+    """
+    Oblicza procent obserwacji w oknie, które są poniżej (Q1 - 1.5 * IQR) lub powyżej (Q3 + 1.5 * IQR).
+    
+    Parameters
+    ----------
+    data : np.ndarray or pd.Series
+        Dane z okna do analizy.
+    training_data : np.ndarray or pd.Series
+        Dane treningowe do obliczenia Q1, Q3 i IQR.
+
+    Returns
+    -------
+    float
+        Procent obserwacji w oknie odbiegających od wyznaczonych granic.
+    """
+    if isinstance(training_data, pd.Series):
+        training_data = training_data.values
+    if isinstance(data, pd.Series):
+        data = data.values
+
+    # Obliczenie Q1, Q3 i IQR na podstawie zbioru treningowego
+    q1 = np.percentile(training_data, 25)
+    q3 = np.percentile(training_data, 75)
+    iqr = q3 - q1
+
+    lower_bound = q1 - 1.5 * iqr
+    upper_bound = q3 + 1.5 * iqr
+
+    # Liczenie obserwacji poza granicami
+    outliers = np.sum((data < lower_bound) | (data > upper_bound))
+    return outliers / len(data)
diff --git a/interpreTS/core/features/feature_outliers_std.py b/interpreTS/core/features/feature_outliers_std.py
new file mode 100644
index 0000000..cdb602a
--- /dev/null
+++ b/interpreTS/core/features/feature_outliers_std.py
@@ -0,0 +1,36 @@
+import numpy as np
+import pandas as pd
+
+def calculate_outliers_std(data, training_data):
+    """
+    Calculates the percentage of observations in a window that are above or below 
+    3 standard deviations from the mean, based on the training dataset.
+    
+    Parameters
+    ----------
+    data : np.ndarray or pd.Series
+        Window data to analyze.
+    training_data : np.ndarray or pd.Series
+        Training data used to calculate the mean and standard deviation.
+
+    Returns
+    -------
+    float
+        Percentage of observations in the window that deviate by more than 3 standard deviations.
+    """
+    if isinstance(training_data, pd.Series):
+        training_data = training_data.values
+    if isinstance(data, pd.Series):
+        data = data.values
+
+    # Calculate mean and standard deviation from training data
+    mean_value = np.mean(training_data)
+    std_dev = np.std(training_data)
+
+    # Define bounds for outliers (3 standard deviations from the mean)
+    lower_bound = mean_value - 3 * std_dev
+    upper_bound = mean_value + 3 * std_dev
+
+    # Count observations outside the bounds
+    outliers = np.sum((data < lower_bound) | (data > upper_bound))
+    return outliers / len(data)
diff --git a/interpreTS/core/features/feature_significant_changes.py b/interpreTS/core/features/feature_significant_changes.py
new file mode 100644
index 0000000..ac5cded
--- /dev/null
+++ b/interpreTS/core/features/feature_significant_changes.py
@@ -0,0 +1,60 @@
+import numpy as np
+import pandas as pd
+from interpreTS.utils.data_validation import validate_time_series_data
+
+def calculate_significant_changes(data):
+    """
+    Calculate the proportion of significant increases or decreases in the signal within the given window.
+     
+    Parameters
+    ----------
+    data : pd.Series or np.ndarray
+        The time series data for which the significant change is to be calculated.
+        
+    Returns
+    -------
+    float
+        The proportion of significant changes in the window, in the range [0, 1].
+        A value > 0 indicates the presence of significant changes.
+        
+    Raises
+    ------
+    TypeError
+        If the data is not a valid time series type.
+    ValueError
+        If the data contains NaN values or has fewer than 2 elements.
+
+    Example
+    -------
+    >>> data = pd.Series([1, 2, 1.5, 3, 2.5, 5, 4.5])
+    >>> calculate_significant_change(data)
+    0.3333333333333333
+
+    """
+
+    # Validate the time series data
+    validate_time_series_data(data, require_datetime_index=False)
+    
+    # Ensure data contains enough points for calculation
+    if len(data) < 2:
+        return 0.0  # Not enough data to compute differences
+    
+    # Compute differences between consecutive values
+    differences = np.diff(data)
+    
+    # Calculate Q1, Q3, and IQR for the differences
+    Q1 = np.percentile(differences, 25)
+    Q3 = np.percentile(differences, 75)
+    IQR = Q3 - Q1
+    
+    # Define bounds for significant changes
+    lower_bound = Q1 - 1.5 * IQR
+    upper_bound = Q3 + 1.5 * IQR
+    
+    # Count significant changes
+    significant_changes = np.sum((differences < lower_bound) | (differences > upper_bound))
+    
+    # Proportion of significant changes
+    proportion_significant_changes = significant_changes / len(differences)
+    
+    return proportion_significant_changes
\ No newline at end of file
diff --git a/interpreTS/core/features/feature_spikeness.py b/interpreTS/core/features/feature_spikeness.py
index 546e85d..b5909bf 100644
--- a/interpreTS/core/features/feature_spikeness.py
+++ b/interpreTS/core/features/feature_spikeness.py
@@ -19,9 +19,9 @@ def calculate_spikeness(data):
     Raises
     ------
     TypeError
-        If the data is not a valid time series type.
+        If the data is not a valid time series type or contains non-numeric values.
     ValueError
-        If the data contains NaN values.
+        If the data is empty.
 
     Examples
     --------
@@ -32,10 +32,28 @@ def calculate_spikeness(data):
     """
     # Validate the time series without requiring a DateTime index
     validate_time_series_data(data, require_datetime_index=False)
-    
+
     # Ensure data is a pandas Series for compatibility with .skew()
     if isinstance(data, np.ndarray):
         data = pd.Series(data)
-    
-    # Return spikeness (skewness), handling empty series by returning NaN
-    return data.skew() if len(data) > 0 else np.nan
+
+    # Drop NaN values to avoid issues with skewness calculation
+    original_length = len(data)
+    data = data.dropna()
+
+    # Handle empty series after dropping NaNs
+    if len(data) == 0:
+        return np.nan
+
+    # Check if data is numeric
+    if not np.issubdtype(data.dtype, np.number):
+        raise TypeError("Data must be numeric.")
+
+    # Calculate and return spikeness (skewness)
+    spikeness = data.skew()
+
+    # Log adjustment if NaN values were dropped
+    if len(data) < original_length:
+        print(f"Warning: {original_length - len(data)} NaN values were dropped for spikeness calculation.")
+
+    return spikeness
diff --git a/interpreTS/core/features/feature_stability.py b/interpreTS/core/features/feature_stability.py
index ab84d77..482ea56 100644
--- a/interpreTS/core/features/feature_stability.py
+++ b/interpreTS/core/features/feature_stability.py
@@ -12,49 +12,57 @@ def calculate_stability(data, max_lag=None):
     data : pd.Series or np.ndarray
         The time series data for which the stability is to be calculated.
     max_lag : int, optional
-        The maximum number of lags to consider for autocorrelation. 
+        The maximum number of lags to consider for autocorrelation.
         If None, it will be set to `min(12, len(data) - 1)`.
 
     Returns
     -------
     float
         The stability strength, ranging from 0 to 1, where 1 indicates high stability.
-
-    Raises
-    ------
-    TypeError
-        If the data is not a valid time series type.
-    ValueError
-        If the data contains NaN values or is too short to calculate stability.
-
     """
     # Validate the time series data
-    validate_time_series_data(data, require_datetime_index=False)
-    
+    validate_time_series_data(data, require_datetime_index=False, allow_nan=False)
+
+    # Convert to pandas Series if it's a numpy array
+    if isinstance(data, np.ndarray):
+        data = pd.Series(data)
+
+    # Ensure the data is numeric and handle empty series
+    if data.empty:
+        return np.nan
+    if not np.issubdtype(data.dtype, np.number):
+        raise TypeError("Data must be numeric.")
+
     # Dynamically determine max_lag if not provided
     if max_lag is None:
         max_lag = min(12, len(data) - 1)
-    
-    # Handle empty or insufficient data
-    if len(data) < max_lag + 1 or max_lag < 1:
+
+    # Handle insufficient data
+    if len(data) <= max_lag or max_lag < 1:
+        return np.nan
+
+    # Handle zero variance
+    if data.var() == 0:
+        return 1.0
+
+    try:
+        # Calculate the autocorrelation of the data up to the max lag
+        autocorr_values = acf(data, nlags=max_lag, fft=True)
+
+        # Exclude the first autocorrelation (lag 0) as it is always 1
+        autocorr_values = autocorr_values[1:]
+
+        # Calculate stability based on variance of autocorrelation values at higher lags
+        mean_autocorr = np.mean(np.abs(autocorr_values))
+        variance_autocorr = np.var(autocorr_values)
+
+        # Combine mean and variance to get a measure of stability
+        stability_strength = 1 - (mean_autocorr + variance_autocorr) / 2
+        stability_strength = max(0, min(stability_strength, 1))  # Ensure result is within [0, 1]
+
+        return stability_strength
+
+    except Exception as e:
+        # Log unexpected exceptions and return NaN
+        print(f"Error calculating stability: {e}")
         return np.nan
-    
-    # Check for constant values
-    if data.nunique() == 1:
-        return 1.0  # Perfect stability for constant values
-    
-    # Calculate the autocorrelation of the data up to the max lag
-    autocorr_values = acf(data, nlags=max_lag, fft=True)
-    
-    # Exclude the first autocorrelation (lag 0) as it is always 1
-    autocorr_values = autocorr_values[1:]
-    
-    # Calculate stability based on variance of autocorrelation values at higher lags
-    mean_autocorr = np.mean(np.abs(autocorr_values))
-    variance_autocorr = np.var(autocorr_values)
-    
-    # Combine mean and variance to get a measure of stability
-    stability_strength = 1 - (mean_autocorr + variance_autocorr) / 2
-    stability_strength = max(0, min(stability_strength, 1))  # Ensure result is within [0, 1]
-    
-    return stability_strength
diff --git a/interpreTS/core/features/feature_trough.py b/interpreTS/core/features/feature_trough.py
index fa20541..60f96ba 100644
--- a/interpreTS/core/features/feature_trough.py
+++ b/interpreTS/core/features/feature_trough.py
@@ -2,7 +2,6 @@
 import numpy as np
 from interpreTS.utils.data_validation import validate_time_series_data
 
-
 def calculate_trough(data, start=None, end=None):
     """
     Calculate the local minimum of a time series within an optional range.
@@ -28,11 +27,10 @@ def calculate_trough(data, start=None, end=None):
     TypeError
         If the data is not a valid time series type.
     ValueError
-        If the data contains NaN values.
+        If the data contains only NaN values or is invalid.
 
     Examples
     --------
-    >>> import pandas as pd
     >>> data = pd.Series([1, 2, 5, 4, 3])
     >>> calculate_trough(data)
     1.0
@@ -40,15 +38,33 @@ def calculate_trough(data, start=None, end=None):
     2.0
     """
 
-    # Validate the time series without requiring a DateTime index
+    # Validate the input type
+    if not isinstance(data, (pd.Series, np.ndarray)):
+        raise TypeError("Data must be a pandas Series or numpy ndarray.")
+
+    # Convert ndarray to pandas Series for consistency
+    if isinstance(data, np.ndarray):
+        data = pd.Series(data)
+
+    # Validate the time series (ignoring datetime requirement)
     validate_time_series_data(data, require_datetime_index=False)
 
-    # Slice the data based on start and end, if provided
-    if end is None:
-        end = len(data)
+    # Check if data contains only NaN or is empty
+    if data.isna().all() or len(data) == 0:
+        return np.nan
+
+    # Adjust slicing parameters
     if start is None:
         start = 0
-    data = data[start:end]
-    
-    # Calculate and return the minimum, handling empty series by returning NaN
-    return data.min() if len(data) > 0 else np.nan
\ No newline at end of file
+    if end is None or end > len(data):
+        end = len(data)
+
+    # Ensure slicing indices are valid
+    if not (0 <= start < len(data)) or not (start < end <= len(data)):
+        raise ValueError("Invalid range for start and end indices.")
+
+    # Slice the data
+    sliced_data = data.iloc[start:end]
+
+    # Return the minimum value, handling empty slices
+    return sliced_data.min() if not sliced_data.empty else np.nan
\ No newline at end of file
diff --git a/interpreTS/core/features/feature_variance.py b/interpreTS/core/features/feature_variance.py
index 9f7126b..9fb19a7 100644
--- a/interpreTS/core/features/feature_variance.py
+++ b/interpreTS/core/features/feature_variance.py
@@ -22,25 +22,26 @@ def calculate_variance(data, ddof=1):
     Raises
     ------
     TypeError
-        If the data is not a valid time series type.
+        If the data is not numeric.
     ValueError
-        If the data contains NaN values.
-        
-    Examples
-    --------
-    >>> import pandas as pd
-    >>> data = pd.Series([1, 2, 3, 4, 5])
-    >>> calculate_variance(data)
-    2.5
-    >>> calculate_variance(data, ddof=0)  # Population variance
-    2.0
+        If the data contains NaN values or is not one-dimensional.
     """
-    # Validate the time series without requiring a DateTime index
-    validate_time_series_data(data, require_datetime_index=False)
+    # Validate the time series without requiring a DateTime index but disallowing NaN
+    validate_time_series_data(data, require_datetime_index=False, allow_nan=False)
+    
+    # Check for numeric data
+    if not np.issubdtype(data.dtype, np.number):
+        raise TypeError("Data must be numeric.")
+    
+    # Check for one-dimensional data
+    if isinstance(data, np.ndarray) and data.ndim != 1:
+        raise ValueError("Data must be one-dimensional.")
+    if isinstance(data, pd.DataFrame) and data.shape[1] != 1:
+        raise ValueError("Data must be one-dimensional.")
     
     # Handle the case where the series has only one value
     if len(data) == 1:
         return 0.0
 
     # Calculate and return the variance with specified ddof, handling empty series by returning NaN
-    return np.var(data, ddof=ddof) if len(data) > 0 else np.nan
\ No newline at end of file
+    return np.var(data, ddof=ddof) if len(data) > 0 else np.nan
diff --git a/interpreTS/core/features/seasonality_strength.py b/interpreTS/core/features/seasonality_strength.py
index 47cb55c..67ca501 100644
--- a/interpreTS/core/features/seasonality_strength.py
+++ b/interpreTS/core/features/seasonality_strength.py
@@ -3,6 +3,8 @@
 from statsmodels.tsa.stattools import acf
 from interpreTS.utils.data_validation import validate_time_series_data
 
+import warnings
+
 def calculate_seasonality_strength(data, period=2, max_lag=12):
     """
     Calculate the strength of the seasonality in a time series based on autocorrelation.
@@ -20,13 +22,14 @@ def calculate_seasonality_strength(data, period=2, max_lag=12):
     -------
     float
         The seasonality strength, ranging from 0 to 1, where 1 indicates strong seasonality.
+        Returns np.nan if the data is insufficient or invalid.
 
     Raises
     ------
     TypeError
         If the data is not a valid time series type.
     ValueError
-        If the data contains NaN values or is too short to calculate seasonality.
+        If the data contains NaN values, is too short to calculate seasonality, or if the period is invalid.
 
     Examples
     --------
@@ -37,15 +40,48 @@ def calculate_seasonality_strength(data, period=2, max_lag=12):
     """
     # Validate the time series data
     validate_time_series_data(data, require_datetime_index=False)
+
+    # Check for a valid period
+    if period <= 0:
+        raise ValueError("Period must be a positive integer.")
     
-    # Handle empty or insufficient data
-    if len(data) < period + 1:
+    # Convert data to numpy array for consistency
+    if isinstance(data, pd.Series):
+        data = data.values
+
+    # Remove NaN values
+    data = data[~np.isnan(data)]
+
+    # Handle insufficient data length
+    if len(data) <= period:
         return np.nan
+
+    # Handle constant data
+    if np.all(data == data[0]):
+        return 0.0
+
+    try:
+        # Suppress warnings from acf
+        with warnings.catch_warnings():
+            warnings.simplefilter("ignore", category=RuntimeWarning)
+            autocorr_values = acf(data, nlags=max(max_lag, period), fft=True)
+        
+        # Ensure the autocorrelation result is valid
+        if len(autocorr_values) <= period:
+            return np.nan
+        
+        # Extract the autocorrelation value at the specified period
+        seasonality_strength = autocorr_values[period]
+        
+        # Ensure the strength value is in the range [0, 1]
+        seasonality_strength = max(0.0, min(seasonality_strength, 1.0))
+        return seasonality_strength
     
-    # Calculate the autocorrelation of the data
-    autocorr_values = acf(data, nlags=max(max_lag, period), fft=True)
-    
-    # The seasonality strength is based on the autocorrelation at the specified period
-    seasonality_strength = autocorr_values[period] if period < len(autocorr_values) else 0.0
+    except ZeroDivisionError:
+        # Handle division by zero in acf calculation (e.g., constant data)
+        return 0.0
     
-    return seasonality_strength
+    except Exception as e:
+        # Log or handle unexpected exceptions
+        print(f"Error calculating seasonality strength: {e}")
+        return np.nan
diff --git a/interpreTS/core/streaming_feature_extractor.py b/interpreTS/core/streaming_feature_extractor.py
index 258688a..8547952 100644
--- a/interpreTS/core/streaming_feature_extractor.py
+++ b/interpreTS/core/streaming_feature_extractor.py
@@ -1,99 +1,106 @@
-import pandas as pd
-import numpy as np
+# import pandas as pd
+# import numpy as np
 
-from .features.feature_crossing_points import calculate_crossing_points
-from .features.feature_spikeness import calculate_spikeness
-from .features.feature_peak import calculate_peak
-from .features.feature_trough import calculate_trough
-from .features.feature_length import calculate_length
-from .features.feature_mean import calculate_mean
-from .features.seasonality_strength import calculate_seasonality_strength
-from .features.feature_variance import calculate_variance
-from .features.feature_std_1st_der import calculate_std_1st_der
-from .features.feature_flat_spots import calculate_flat_spots
+# from .features.feature_crossing_points import calculate_crossing_points
+# from .features.feature_spikeness import calculate_spikeness
+# from .features.feature_peak import calculate_peak
+# from .features.feature_trough import calculate_trough
+# from .features.feature_length import calculate_length
+# from .features.feature_mean import calculate_mean
+# from .features.seasonality_strength import calculate_seasonality_strength
+# from .features.feature_variance import calculate_variance
+# from .features.feature_std_1st_der import calculate_std_1st_der
+# from .features.feature_flat_spots import calculate_flat_spots
+# from .features.feature_significant_changes import calculate_significant_changes
+# from .features.feature_above_9th_decile import calculate_above_9th_decile
+# from .features.feature_below_1st_decile import calculate_below_1st_decile
 
-class StreamingFeatureExtractor:
-    def __init__(self, features=None, feature_params=None, window_size=5):
-        """
-        Initialize the StreamingFeatureExtractor with a list of features to calculate and optional parameters.
+# class StreamingFeatureExtractor:
+#     def __init__(self, features=None, feature_params=None, window_size=5):
+#         """
+#         Initialize the StreamingFeatureExtractor with a list of features to calculate and optional parameters.
         
-        Parameters
-        ----------
-        features : list of str, optional
-            A list of features to calculate. Default is None, which calculates all available features.
-        feature_params : dict, optional
-            Parameters for specific features, where keys are feature names and values are dicts of parameters.
-        window_size : int, optional
-            The size of the window for feature extraction.
-        """
-        self.features = features if features is not None else [
-            'length', 'mean', 'peak', 'std_1st_der', 'trough', 
-            'variance', 'spikeness', 'seasonality_strength', 'flat_spots', 
-            'crossing_points'
-        ]
-        self.feature_params = feature_params if feature_params is not None else {}
-        self.window_size = window_size
-        self.data_buffer = []
+#         Parameters
+#         ----------
+#         features : list of str, optional
+#             A list of features to calculate. Default is None, which calculates all available features.
+#         feature_params : dict, optional
+#             Parameters for specific features, where keys are feature names and values are dicts of parameters.
+#         window_size : int, optional
+#             The size of the window for feature extraction.
+#         """
+#         self.features = features if features is not None else [
+#             'length', 'mean', 'peak', 'std_1st_der', 'trough', 
+#             'variance', 'spikeness', 'seasonality_strength', 'flat_spots', 
+#             'crossing_points', 'significant_changes'
+#             'crossing_points', 'above_9th_decile', 'below_1st_decile'
+#         ]
+#         self.feature_params = feature_params if feature_params is not None else {}
+#         self.window_size = window_size
+#         self.data_buffer = []
 
-        # Map of feature names to calculation functions
-        self.feature_functions = {
-            'length': calculate_length,
-            'mean': calculate_mean,
-            'peak': calculate_peak,
-            'std_1st_der': calculate_std_1st_der,
-            'trough': calculate_trough,
-            'variance': calculate_variance,
-            'spikeness': calculate_spikeness,
-            'seasonality_strength': calculate_seasonality_strength,
-            'flat_spots': calculate_flat_spots,
-            'crossing_points': calculate_crossing_points,
-        }
+#         # Map of feature names to calculation functions
+#         self.feature_functions = {
+#             'length': calculate_length,
+#             'mean': calculate_mean,
+#             'peak': calculate_peak,
+#             'std_1st_der': calculate_std_1st_der,
+#             'trough': calculate_trough,
+#             'variance': calculate_variance,
+#             'spikeness': calculate_spikeness,
+#             'seasonality_strength': calculate_seasonality_strength,
+#             'flat_spots': calculate_flat_spots,
+#             'crossing_points': calculate_crossing_points,
+#             'significant_changes': calculate_significant_changes,
+#             'above_9th_decile': calculate_above_9th_decile,
+#             'below_1st_decile': calculate_below_1st_decile
+#         }
 
-    def add_data(self, new_data):
-        """
-        Add new data to the buffer and calculate features if the window size is met.
+#     def add_data(self, new_data):
+#         """
+#         Add new data to the buffer and calculate features if the window size is met.
         
-        Parameters
-        ----------
-        new_data : float or int
-            New data point to add to the buffer.
+#         Parameters
+#         ----------
+#         new_data : float or int
+#             New data point to add to the buffer.
             
-        Returns
-        -------
-        dict or None
-            A dictionary of calculated features if the window size is met, else None.
-        """
-        self.data_buffer.append(new_data)
+#         Returns
+#         -------
+#         dict or None
+#             A dictionary of calculated features if the window size is met, else None.
+#         """
+#         self.data_buffer.append(new_data)
 
-        # Sprawdzanie długości bufora przed obliczaniem cech
-        if len(self.data_buffer) < self.window_size:
-            return None
+#         # Sprawdzanie długości bufora przed obliczaniem cech
+#         if len(self.data_buffer) < self.window_size:
+#             return None
 
-        window_data = pd.Series(self.data_buffer[-self.window_size:])
-        features = self._calculate_features(window_data)
-        return features
+#         window_data = pd.Series(self.data_buffer[-self.window_size:])
+#         features = self._calculate_features(window_data)
+#         return features
 
 
-    def _calculate_features(self, data):
-        """
-        Calculate selected features on the current window data.
+#     def _calculate_features(self, data):
+#         """
+#         Calculate selected features on the current window data.
         
-        Parameters
-        ----------
-        data : pd.Series
-            The data window on which to calculate features.
+#         Parameters
+#         ----------
+#         data : pd.Series
+#             The data window on which to calculate features.
             
-        Returns
-        -------
-        dict
-            A dictionary containing calculated features.
-        """
-        extracted_features = {}
+#         Returns
+#         -------
+#         dict
+#             A dictionary containing calculated features.
+#         """
+#         extracted_features = {}
 
-        for feature_name in self.features:
-            if feature_name in self.feature_functions:
-                # Retrieve parameters for each feature, if provided
-                params = self.feature_params.get(feature_name, {})
-                extracted_features[feature_name] = self.feature_functions[feature_name](data, **params)
+#         for feature_name in self.features:
+#             if feature_name in self.feature_functions:
+#                 # Retrieve parameters for each feature, if provided
+#                 params = self.feature_params.get(feature_name, {})
+#                 extracted_features[feature_name] = self.feature_functions[feature_name](data, **params)
 
-        return extracted_features
+#         return extracted_features
diff --git a/interpreTS/knowledge_base/feature_metadata.json b/interpreTS/knowledge_base/feature_metadata.json
new file mode 100644
index 0000000..ffd7c8d
--- /dev/null
+++ b/interpreTS/knowledge_base/feature_metadata.json
@@ -0,0 +1,122 @@
+{
+    "length": {
+        "description": "Calculates the length of the time series window.",
+        "interpretation": "Represents the number of data points in the current time window. A fixed length ensures consistent feature extraction for machine learning models.",
+        "parameters": [],
+        "examples": "Used to ensure consistent window sizes across series for further analysis.",
+        "complexity": "easy",
+        "related_features": []
+    },
+    "mean": {
+        "description": "Calculates the average value of the time series window.",
+        "interpretation": "Higher values indicate an upward trend in the series within the window, while lower values suggest a downward trend.",
+        "parameters": [],
+        "examples": "Can be used to detect general trends, such as identifying periods of growth or decline in financial data.",
+        "complexity": "easy",
+        "related_features": ["variance", "peak"]
+    },
+    "peak": {
+        "description": "Finds the maximum value in the time series window.",
+        "interpretation": "A higher peak suggests the presence of significant outliers or short-term spikes in the data.",
+        "parameters": [],
+        "examples": "Useful in applications like anomaly detection (e.g., finding sudden increases in network traffic or temperature spikes).",
+        "complexity": "easy",
+        "related_features": ["trough", "range"]
+    },
+    "trough": {
+        "description": "Finds the minimum value in the time series window.",
+        "interpretation": "Lower trough values indicate significant dips, which may correspond to anomalies or key events.",
+        "parameters": [],
+        "examples": "Can be used for identifying low periods, such as demand dips in sales data.",
+        "complexity": "easy",
+        "related_features": ["peak", "range"]
+    },
+    "variance": {
+        "description": "Calculates the variance of values in the time series window.",
+        "interpretation": "Indicates the spread of values. A higher variance suggests greater instability, while lower variance suggests consistency in the data.",
+        "parameters": [],
+        "examples": "Useful in assessing risk or variability in financial time series or system stability.",
+        "complexity": "moderate",
+        "related_features": ["mean", "std_1st_der"]
+    },
+    "spikeness": {
+        "description": "Measures the degree of spikes in the time series window.",
+        "interpretation": "Quantifies the presence of sudden, sharp increases or decreases in the data, which may correspond to anomalies or rapid changes.",
+        "parameters": ["threshold"],
+        "examples": "Can detect unusual patterns like sudden traffic surges or sharp voltage fluctuations.",
+        "complexity": "moderate",
+        "related_features": ["peak", "variance"]
+    },
+    "entropy": {
+        "description": "Calculates the Shannon entropy of the time series window.",
+        "interpretation": "Higher entropy indicates more randomness or disorder, while lower entropy suggests regular patterns.",
+        "parameters": [],
+        "examples": "Useful in applications like stock market analysis (detecting chaotic behavior) or identifying data quality issues.",
+        "complexity": "advanced",
+        "related_features": []
+    },
+    "seasonality_strength": {
+        "description": "Measures the strength of seasonal patterns in the time series.",
+        "interpretation": "Quantifies how strongly the data exhibits periodic behavior (e.g., daily, weekly, or yearly trends).",
+        "parameters": [],
+        "examples": "Commonly used in retail to identify seasonal demand changes or in climate data analysis.",
+        "complexity": "advanced",
+        "related_features": []
+    },
+    "absolute_energy": {
+        "description": "Computes the absolute energy of the time series window.",
+        "interpretation": "Indicates the overall magnitude of the signal. Higher values suggest periods of strong activity.",
+        "parameters": [],
+        "examples": "Useful in vibration analysis for machinery health or monitoring power usage.",
+        "complexity": "advanced",
+        "related_features": ["variance", "mean"]
+    },
+    "stability": {
+        "description": "Measures the stability of the time series within the window.",
+        "interpretation": "Lower stability suggests increasing variability or emerging trends, while higher stability reflects consistent behavior.",
+        "parameters": [],
+        "examples": "Used to detect transitions or phases in industrial process monitoring.",
+        "complexity": "moderate",
+        "related_features": ["variance", "entropy"]
+    },
+    "flat_spots": {
+        "description": "Counts the number of flat regions in the time series window.",
+        "interpretation": "Flat spots indicate areas where the signal remains constant over time, often highlighting periods of inactivity.",
+        "parameters": ["threshold"],
+        "examples": "Can identify idle times in machine operation or plateaus in sensor readings.",
+        "complexity": "easy",
+        "related_features": ["stability", "length"]
+    },
+    "crossing_points": {
+        "description": "Counts the number of times the time series crosses its mean.",
+        "interpretation": "Higher crossing points suggest oscillatory or cyclic patterns, while lower values suggest a trend or plateau.",
+        "parameters": [],
+        "examples": "Useful in analyzing rhythmic patterns in biomedical signals or detecting market oscillations.",
+        "complexity": "easy",
+        "related_features": ["mean", "variance"]
+    },
+    "missing_points": {
+        "description": "Counts the number of missing values in the time series window.",
+        "interpretation": "Indicates the extent of missing data, which can impact model performance or indicate data quality issues.",
+        "parameters": [],
+        "examples": "Commonly used in preprocessing for data cleaning or imputing missing values.",
+        "complexity": "easy",
+        "related_features": []
+    },
+    "binarize_mean": {
+        "description": "Binarizes the time series based on whether values are above or below the mean.",
+        "interpretation": "Converts the series into binary form for simplified analysis, often used for symbolic or pattern analysis.",
+        "parameters": [],
+        "examples": "Useful in threshold-based event detection, such as binary classification of high or low activity.",
+        "complexity": "moderate",
+        "related_features": ["mean", "crossing_points"]
+    },
+    "std_1st_der": {
+        "description": "Calculates the standard deviation of the first derivative of the time series.",
+        "interpretation": "Measures the variability in the rate of change of the time series. A higher value indicates rapid or inconsistent changes, while a lower value suggests smoother trends.",
+        "parameters": [],
+        "examples": "Useful for detecting volatility in financial data, abrupt changes in sensor readings, or irregular behavior in systems.",
+        "complexity": "moderate",
+        "related_features": ["variance", "spikeness", "stability"]
+    }
+}
diff --git a/interpreTS/utils/data_conversion.py b/interpreTS/utils/data_conversion.py
index 940d6ff..5c77fd1 100644
--- a/interpreTS/utils/data_conversion.py
+++ b/interpreTS/utils/data_conversion.py
@@ -5,33 +5,46 @@
 def convert_to_time_series(data):
     """
     Convert input data to a TimeSeriesData object.
-    
+
     Parameters
     ----------
     data : pd.DataFrame, pd.Series, or np.ndarray
         The data to be converted into a TimeSeriesData object.
-        
+
     Returns
     -------
     TimeSeriesData
         An instance of TimeSeriesData wrapping the input data.
-        
+
     Raises
     ------
     TypeError
         If the input data is not of type pd.DataFrame, pd.Series, or np.ndarray.
-        
+    ValueError
+        If the input data is empty or has invalid dimensions.
+
     Examples
     --------
     >>> import pandas as pd
     >>> data = pd.Series([1, 2, 3, 4, 5])
     >>> ts_data = convert_to_time_series(data)
     """
-    
-    
-    if isinstance(data, (pd.DataFrame, pd.Series)):
+
+    # Handle pandas Series or DataFrame
+    if isinstance(data, (pd.Series, pd.DataFrame)):
         return TimeSeriesData(data)
+
+    # Handle numpy array
     elif isinstance(data, np.ndarray):
-        return TimeSeriesData(pd.Series(data))
+        if data.size == 0:
+            return TimeSeriesData(pd.Series(data))
+        if data.ndim > 2:
+            raise ValueError("Input numpy array must be 1D or 2D.")
+        if data.ndim == 1:
+            return TimeSeriesData(pd.Series(data))
+        else:
+            return TimeSeriesData(pd.DataFrame(data))
+
+    # Raise error for unsupported types
     else:
         raise TypeError("Data must be of type pandas DataFrame, Series, or numpy array.")
diff --git a/interpreTS/utils/data_validation.py b/interpreTS/utils/data_validation.py
index c1e2a1d..e781870 100644
--- a/interpreTS/utils/data_validation.py
+++ b/interpreTS/utils/data_validation.py
@@ -1,7 +1,7 @@
 import pandas as pd
 import numpy as np
 
-def validate_time_series_data(data, require_datetime_index=False):
+def validate_time_series_data(data, require_datetime_index=False, allow_nan=True):
     """
     Validate if the input data is suitable for time series processing.
     
@@ -11,6 +11,8 @@ def validate_time_series_data(data, require_datetime_index=False):
         The time series data to be validated.
     require_datetime_index : bool, optional
         If True, validation will ensure the data has a DateTime index (for time-based operations).
+    allow_nan : bool, optional
+        If False, validation will raise an error if NaN values are present (default is True).
         
     Returns
     -------
@@ -22,21 +24,26 @@ def validate_time_series_data(data, require_datetime_index=False):
     TypeError
         If data is not a pd.Series, pd.DataFrame, or np.ndarray.
     ValueError
-        If the data contains NaN values or lacks a DateTime index when required.
+        If the data contains NaN values and `allow_nan` is False, or if the index is not a DateTime index when required.
     """
-    
-    # Sprawdzenie typu danych
+    # Check data type
     if not isinstance(data, (pd.Series, pd.DataFrame, np.ndarray)):
         raise TypeError("Data must be a pandas Series, DataFrame, or numpy array.")
     
-    # Walidacja dla danych w formacie Series lub DataFrame
+    # Validate pandas Series or DataFrame
     if isinstance(data, (pd.Series, pd.DataFrame)):
-        # Sprawdzenie wartości NaN
-        if data.isnull().any().any():
+        # Check for NaN values
+        if not allow_nan and data.isnull().any().any():
             raise ValueError("Data contains NaN values.")
         
-        # Sprawdzenie typu indeksu, jeśli wymagany jest DateTimeIndex
+        # Check index type if datetime index is required
         if require_datetime_index and not isinstance(data.index, pd.DatetimeIndex):
             raise ValueError("Data must have a DateTime index for time-based operations.")
     
+    # Validate numpy array
+    elif isinstance(data, np.ndarray):
+        if data.ndim > 1 and not allow_nan:
+            if np.isnan(data).any():
+                raise ValueError("Data contains NaN values.")
+    
     return True
diff --git a/requirements.txt b/requirements.txt
index d129605..bd61350 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,3 +2,6 @@
 numpy>=1.18.0
 statsmodels>=0.12.0
 pytest
+langchain_community
+langchain 
+openai
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 3ca37a7..2cdca45 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@
 
 setup(
     name="InterpreTS",
-    version="0.2.0",
+    version="0.3.0",
     packages=find_packages(),
     install_requires=[
         "pandas>=1.0.0",


Test patch:
diff --git a/tests/core/features/test_absolute_energy.py b/tests/core/features/test_absolute_energy.py
index fcc9ffe..57569b8 100644
--- a/tests/core/features/test_absolute_energy.py
+++ b/tests/core/features/test_absolute_energy.py
@@ -1,75 +1,75 @@
-import pytest
-import pandas as pd
-import numpy as np
-from interpreTS.core.features.feature_absolute_energy import absolute_energy
+# import pytest
+# import pandas as pd
+# import numpy as np
+# from interpreTS.core.features.feature_absolute_energy import absolute_energy
 
-def test_absolute_energy():
-    """
-    Test that absolute_energy correctly calculates the absolute energy of a time series.
-    """
-    data = pd.Series([1, 2, 3, 4, 5])
-    assert absolute_energy(data) == 55.0, "The absolute energy should be 55.0"
+# def test_absolute_energy():
+#     """
+#     Test that absolute_energy correctly calculates the absolute energy of a time series.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5])
+#     assert absolute_energy(data) == 55.0, "The absolute energy should be 55.0"
 
-def test_absolute_energy_empty_series():
-    """
-    Test that absolute_energy returns NaN for an empty time series.
-    """
-    data = pd.Series([])
-    assert pd.isna(absolute_energy(data)), "The absolute energy of an empty series should be NaN"
+# def test_absolute_energy_empty_series():
+#     """
+#     Test that absolute_energy returns NaN for an empty time series.
+#     """
+#     data = pd.Series([])
+#     assert pd.isna(absolute_energy(data)), "The absolute energy of an empty series should be NaN"
 
-def test_absolute_energy_numpy_array():
-    """
-    Test that absolute_energy correctly calculates the absolute energy of a numpy array.
-    """
-    data = np.array([1, 2, 3, 4, 5])
-    assert absolute_energy(data) == 55.0, "The absolute energy should be 55.0 for numpy array"
+# def test_absolute_energy_numpy_array():
+#     """
+#     Test that absolute_energy correctly calculates the absolute energy of a numpy array.
+#     """
+#     data = np.array([1, 2, 3, 4, 5])
+#     assert absolute_energy(data) == 55.0, "The absolute energy should be 55.0 for numpy array"
 
-def test_absolute_energy_with_negative_values():
-    """
-    Test that absolute_energy correctly calculates the absolute energy for a series with negative values.
-    """
-    data = pd.Series([-1, -2, -3, -4, -5])
-    assert absolute_energy(data) == 55.0, "The absolute energy should be 55.0 even with negative values"
+# def test_absolute_energy_with_negative_values():
+#     """
+#     Test that absolute_energy correctly calculates the absolute energy for a series with negative values.
+#     """
+#     data = pd.Series([-1, -2, -3, -4, -5])
+#     assert absolute_energy(data) == 55.0, "The absolute energy should be 55.0 even with negative values"
 
-def test_absolute_energy_with_start_and_end():
-    """
-    Test that absolute_energy correctly calculates the absolute energy within a specified start and end range.
-    """
-    data = pd.Series([1, 2, 3, 4, 5])
-    assert absolute_energy(data, start=1, end=4) == 29.0, "The absolute energy within index range 1 to 4 should be 29.0"
+# def test_absolute_energy_with_start_and_end():
+#     """
+#     Test that absolute_energy correctly calculates the absolute energy within a specified start and end range.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5])
+#     assert absolute_energy(data, start=1, end=4) == 29.0, "The absolute energy within index range 1 to 4 should be 29.0"
 
-def test_absolute_energy_with_out_of_range_indices():
-    """
-    Test that absolute_energy handles out-of-range start and end indices gracefully.
-    """
-    data = pd.Series([1, 2, 3, 4, 5])
-    assert pd.isna(absolute_energy(data, start=10)), "The absolute energy with out-of-range start index should be NaN"
-    assert pd.isna(absolute_energy(data, end=-10)), "The absolute energy with out-of-range end index should be NaN"
+# def test_absolute_energy_with_out_of_range_indices():
+#     """
+#     Test that absolute_energy handles out-of-range start and end indices gracefully.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5])
+#     assert pd.isna(absolute_energy(data, start=10)), "The absolute energy with out-of-range start index should be NaN"
+#     assert pd.isna(absolute_energy(data, end=-10)), "The absolute energy with out-of-range end index should be NaN"
 
-def test_absolute_energy_with_start_greater_than_end():
-    """
-    Test that absolute_energy returns NaN if start index is greater than end index.
-    """
-    data = pd.Series([1, 2, 3, 4, 5])
-    assert pd.isna(absolute_energy(data, start=4, end=2)), "The absolute energy should be NaN if start index is greater than end index"
+# def test_absolute_energy_with_start_greater_than_end():
+#     """
+#     Test that absolute_energy returns NaN if start index is greater than end index.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5])
+#     assert pd.isna(absolute_energy(data, start=4, end=2)), "The absolute energy should be NaN if start index is greater than end index"
 
-def test_absolute_energy_with_all_zeros():
-    """
-    Test that absolute_energy correctly handles a series of all zeros.
-    """
-    data = pd.Series([0, 0, 0, 0, 0])
-    assert absolute_energy(data) == 0.0, "The absolute energy of a series of all zeros should be 0.0"
+# def test_absolute_energy_with_all_zeros():
+#     """
+#     Test that absolute_energy correctly handles a series of all zeros.
+#     """
+#     data = pd.Series([0, 0, 0, 0, 0])
+#     assert absolute_energy(data) == 0.0, "The absolute energy of a series of all zeros should be 0.0"
 
-def test_absolute_energy_with_single_element():
-    """
-    Test that absolute_energy correctly handles a series with a single element.
-    """
-    data = pd.Series([42])
-    assert absolute_energy(data) == 42**2, "The absolute energy of a single-element series should be the square of the element"
+# def test_absolute_energy_with_single_element():
+#     """
+#     Test that absolute_energy correctly handles a series with a single element.
+#     """
+#     data = pd.Series([42])
+#     assert absolute_energy(data) == 42**2, "The absolute energy of a single-element series should be the square of the element"
 
-def test_absolute_energy_with_floats():
-    """
-    Test that absolute_energy handles float values correctly.
-    """
-    data = pd.Series([1.5, 2.5, 3.5])
-    assert absolute_energy(data) == 1.5**2 + 2.5**2 + 3.5**2, "The absolute energy should correctly sum the squares of float values"
+# def test_absolute_energy_with_floats():
+#     """
+#     Test that absolute_energy handles float values correctly.
+#     """
+#     data = pd.Series([1.5, 2.5, 3.5])
+#     assert absolute_energy(data) == 1.5**2 + 2.5**2 + 3.5**2, "The absolute energy should correctly sum the squares of float values"
diff --git a/tests/core/features/test_distance_to_the_last_change_point.py b/tests/core/features/test_distance_to_the_last_change_point.py
index 6902d95..40bc7b2 100644
--- a/tests/core/features/test_distance_to_the_last_change_point.py
+++ b/tests/core/features/test_distance_to_the_last_change_point.py
@@ -1,111 +1,111 @@
-import pytest
-import pandas as pd
-import numpy as np
-from interpreTS.core.features.distance_to_the_last_change_point import calculate_distance_to_last_trend_change  
-
-def test_calculate_distance_to_last_trend_change_constant_data():
-    """
-    Test that calculate_distance_to_last_trend_change returns None for constant data (no trend change).
-    """
-    data = pd.Series([5] * 10)  # Constant series
-    result = calculate_distance_to_last_trend_change(data, window_size=3)
-    assert result is None, "There should be no trend change in constant data"
-
-
-def test_calculate_distance_to_last_trend_change_increasing_data():
-    """
-    Test that calculate_distance_to_last_trend_change detects the correct distance for increasing data.
-    """
-    data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])  # Increasing trend
-    result = calculate_distance_to_last_trend_change(data, window_size=3)
-    assert result is None, "No trend change should occur for consistently increasing data"
-
-
-def test_calculate_distance_to_last_trend_change_decreasing_data():
-    """
-    Test that calculate_distance_to_last_trend_change detects the correct distance for decreasing data.
-    """
-    data = pd.Series([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])  # Decreasing trend
-    result = calculate_distance_to_last_trend_change(data, window_size=3)
-    assert result is None, "No trend change should occur for consistently decreasing data"
-
-
-def test_calculate_distance_to_last_trend_change_random_data():
-    """
-    Test that calculate_distance_to_last_trend_change handles random data and detects the last trend change.
-    """
-    np.random.seed(0)
-    data = pd.Series(np.random.randn(100))  # Random normal data
-    result = calculate_distance_to_last_trend_change(data, window_size=5)
-    assert isinstance(result, int), "The result should be an integer representing the distance"
-    assert result >= 0, "Distance to last trend change should be a non-negative integer"
-
-
-def test_calculate_distance_to_last_trend_change_no_trend_change():
-    """
-    Test that calculate_distance_to_last_trend_change returns None when there is no trend change.
-    """
-    data = pd.Series([1, 1, 1, 1, 1, 1, 1, 1, 1, 1])  # Constant data
-    result = calculate_distance_to_last_trend_change(data, window_size=3)
-    assert result is None, "There should be no trend change in constant data"
-
-
-def test_calculate_distance_to_last_trend_change_single_trend_change():
-    """
-    Test that calculate_distance_to_last_trend_change detects the correct distance to the last trend change.
-    """
-    data = pd.Series([1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1])  # Trend change after index 5
-    result = calculate_distance_to_last_trend_change(data, window_size=3)
-    assert result == 8, "Distance to the last trend change should be 8"
-
-
-def test_calculate_distance_to_last_trend_change_multiple_trend_changes():
-    """
-    Test that calculate_distance_to_last_trend_change detects the correct distance to the last trend change 
-    after multiple changes.
-    """
-    data = pd.Series([1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 5, 6, 7])  # Multiple trend changes
-    result = calculate_distance_to_last_trend_change(data, window_size=3)
-    assert result == 10, "Distance to the last trend change should be 10 (last change is at index 10)"
-
-
-def test_calculate_distance_to_last_trend_change_empty_series():
-    """
-    Test that calculate_distance_to_last_trend_change raises an error for an empty series.
-    """
-    data = pd.Series([])
-    with pytest.raises(ValueError, match="too short"):
-        calculate_distance_to_last_trend_change(data, window_size=3)
-
-
-def test_calculate_distance_to_last_trend_change_insufficient_data():
-    """
-    Test that calculate_distance_to_last_trend_change raises an error for insufficient data.
-    """
-    data = pd.Series([1, 2])
-    with pytest.raises(ValueError, match="too short"):
-        calculate_distance_to_last_trend_change(data, window_size=3)
-
-
-def test_calculate_distance_to_last_trend_change_window_size():
-    """
-    Test that calculate_distance_to_last_trend_change respects the specified window size.
-    """
-    data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])  # Increasing trend
-    window_size = 4
-    result = calculate_distance_to_last_trend_change(data, window_size=window_size)
-    if data.is_monotonic_increasing or data.is_monotonic_decreasing:
-        assert result is None, "For monotonic data, result should be None"
-    else:
-        assert isinstance(result, int), "Result should be an integer representing the distance to the last trend change"
-
-
-
-def test_calculate_distance_to_last_trend_change_numpy_array():
-    """
-    Test that calculate_distance_to_last_trend_change works with a numpy array.
-    """
-    data = np.array([1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1])
-    result = calculate_distance_to_last_trend_change(data, window_size=3)
-    assert isinstance(result, int), "Result should be an integer for numpy array input"
-    assert result >= 0, "Distance should be a non-negative integer"
\ No newline at end of file
+# import pytest
+# import pandas as pd
+# import numpy as np
+# from interpreTS.core.features.distance_to_the_last_change_point import calculate_distance_to_last_trend_change  
+
+# def test_calculate_distance_to_last_trend_change_constant_data():
+#     """
+#     Test that calculate_distance_to_last_trend_change returns None for constant data (no trend change).
+#     """
+#     data = pd.Series([5] * 10)  # Constant series
+#     result = calculate_distance_to_last_trend_change(data, window_size=3)
+#     assert result is None, "There should be no trend change in constant data"
+
+
+# def test_calculate_distance_to_last_trend_change_increasing_data():
+#     """
+#     Test that calculate_distance_to_last_trend_change detects the correct distance for increasing data.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])  # Increasing trend
+#     result = calculate_distance_to_last_trend_change(data, window_size=3)
+#     assert result is None, "No trend change should occur for consistently increasing data"
+
+
+# def test_calculate_distance_to_last_trend_change_decreasing_data():
+#     """
+#     Test that calculate_distance_to_last_trend_change detects the correct distance for decreasing data.
+#     """
+#     data = pd.Series([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])  # Decreasing trend
+#     result = calculate_distance_to_last_trend_change(data, window_size=3)
+#     assert result is None, "No trend change should occur for consistently decreasing data"
+
+
+# def test_calculate_distance_to_last_trend_change_random_data():
+#     """
+#     Test that calculate_distance_to_last_trend_change handles random data and detects the last trend change.
+#     """
+#     np.random.seed(0)
+#     data = pd.Series(np.random.randn(100))  # Random normal data
+#     result = calculate_distance_to_last_trend_change(data, window_size=5)
+#     assert isinstance(result, int), "The result should be an integer representing the distance"
+#     assert result >= 0, "Distance to last trend change should be a non-negative integer"
+
+
+# def test_calculate_distance_to_last_trend_change_no_trend_change():
+#     """
+#     Test that calculate_distance_to_last_trend_change returns None when there is no trend change.
+#     """
+#     data = pd.Series([1, 1, 1, 1, 1, 1, 1, 1, 1, 1])  # Constant data
+#     result = calculate_distance_to_last_trend_change(data, window_size=3)
+#     assert result is None, "There should be no trend change in constant data"
+
+
+# def test_calculate_distance_to_last_trend_change_single_trend_change():
+#     """
+#     Test that calculate_distance_to_last_trend_change detects the correct distance to the last trend change.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1])  # Trend change after index 5
+#     result = calculate_distance_to_last_trend_change(data, window_size=3)
+#     assert result == 8, "Distance to the last trend change should be 8"
+
+
+# def test_calculate_distance_to_last_trend_change_multiple_trend_changes():
+#     """
+#     Test that calculate_distance_to_last_trend_change detects the correct distance to the last trend change 
+#     after multiple changes.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 5, 6, 7])  # Multiple trend changes
+#     result = calculate_distance_to_last_trend_change(data, window_size=3)
+#     assert result == 10, "Distance to the last trend change should be 10 (last change is at index 10)"
+
+
+# def test_calculate_distance_to_last_trend_change_empty_series():
+#     """
+#     Test that calculate_distance_to_last_trend_change raises an error for an empty series.
+#     """
+#     data = pd.Series([])
+#     with pytest.raises(ValueError, match="too short"):
+#         calculate_distance_to_last_trend_change(data, window_size=3)
+
+
+# def test_calculate_distance_to_last_trend_change_insufficient_data():
+#     """
+#     Test that calculate_distance_to_last_trend_change raises an error for insufficient data.
+#     """
+#     data = pd.Series([1, 2])
+#     with pytest.raises(ValueError, match="too short"):
+#         calculate_distance_to_last_trend_change(data, window_size=3)
+
+
+# def test_calculate_distance_to_last_trend_change_window_size():
+#     """
+#     Test that calculate_distance_to_last_trend_change respects the specified window size.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])  # Increasing trend
+#     window_size = 4
+#     result = calculate_distance_to_last_trend_change(data, window_size=window_size)
+#     if data.is_monotonic_increasing or data.is_monotonic_decreasing:
+#         assert result is None, "For monotonic data, result should be None"
+#     else:
+#         assert isinstance(result, int), "Result should be an integer representing the distance to the last trend change"
+
+
+
+# def test_calculate_distance_to_last_trend_change_numpy_array():
+#     """
+#     Test that calculate_distance_to_last_trend_change works with a numpy array.
+#     """
+#     data = np.array([1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1])
+#     result = calculate_distance_to_last_trend_change(data, window_size=3)
+#     assert isinstance(result, int), "Result should be an integer for numpy array input"
+#     assert result >= 0, "Distance should be a non-negative integer"
\ No newline at end of file
diff --git a/tests/core/features/test_feature_above_9th_decile.py b/tests/core/features/test_feature_above_9th_decile.py
new file mode 100644
index 0000000..349b89c
--- /dev/null
+++ b/tests/core/features/test_feature_above_9th_decile.py
@@ -0,0 +1,40 @@
+# import pytest
+# import pandas as pd
+# import numpy as np
+# from interpreTS.core.features.feature_above_9th_decile import calculate_above_9th_decile
+
+# def test_calculate_above_9th_decile_with_valid_data():
+#     data = pd.Series([1, 8, 9, 10, 11])
+#     training_data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+#     result = calculate_above_9th_decile(data, training_data)
+#     assert result == 0.4
+
+# def test_calculate_above_9th_decile_with_no_values_above_decile():
+#     data = pd.Series([1, 2, 3, 4, 5])
+#     training_data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+#     result = calculate_above_9th_decile(data, training_data)
+#     assert result == 0.0
+
+# def test_calculate_above_9th_decile_with_all_values_above_decile():
+#     data = pd.Series([11, 12, 13, 14, 15])
+#     training_data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+#     result = calculate_above_9th_decile(data, training_data)
+#     assert result == 1.0
+
+# def test_calculate_above_9th_decile_with_nan_values():
+#     data = pd.Series([1, 8, 9, np.nan, 11])
+#     training_data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+#     with pytest.raises(ValueError):
+#         calculate_above_9th_decile(data, training_data)
+
+# def test_calculate_above_9th_decile_with_invalid_data_type():
+#     data = [1, 8, 9, 10, 11]
+#     training_data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+#     with pytest.raises(TypeError):
+#         calculate_above_9th_decile(data, training_data)
+
+# def test_calculate_above_9th_decile_with_empty_data():
+#     data = pd.Series([])
+#     training_data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+#     with pytest.raises(ValueError):
+#         calculate_above_9th_decile(data, training_data)
\ No newline at end of file
diff --git a/tests/core/features/test_feature_below_1st_decile.py b/tests/core/features/test_feature_below_1st_decile.py
new file mode 100644
index 0000000..13e7ba2
--- /dev/null
+++ b/tests/core/features/test_feature_below_1st_decile.py
@@ -0,0 +1,34 @@
+# import pytest
+# import pandas as pd
+# import numpy as np
+# from interpreTS.core.features.feature_below_1st_decile import calculate_below_1st_decile
+
+# def test_calculate_below_1st_decile_valid_data():
+#     data = pd.Series([1, 2, 3, 4, 5])
+#     training_data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+#     result = calculate_below_1st_decile(data, training_data)
+#     assert result == 0.2, "The fraction of values below the 1st decile should be 0.2"
+
+# def test_calculate_below_1st_decile_with_nan_values():
+#     data = pd.Series([1, np.nan, 3, 4, 5])
+#     training_data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+#     with pytest.raises(ValueError):
+#         calculate_below_1st_decile(data, training_data)
+
+# def test_calculate_below_1st_decile_empty_data():
+#     data = pd.Series([])
+#     training_data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+#     with pytest.raises(ValueError):
+#         calculate_below_1st_decile(data, training_data)
+
+# def test_calculate_below_1st_decile_numpy_array():
+#     data = np.array([1, 2, 3, 4, 5])
+#     training_data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+#     result = calculate_below_1st_decile(data, training_data)
+#     assert result == 0.2, "The fraction of values below the 1st decile should be 0.2"
+
+# def test_calculate_below_1st_decile_invalid_type():
+#     data = "invalid data"
+#     training_data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+#     with pytest.raises(TypeError):
+#         calculate_below_1st_decile(data, training_data)
\ No newline at end of file
diff --git a/tests/core/features/test_feature_binarize_mean.py b/tests/core/features/test_feature_binarize_mean.py
index 0c57f1b..e78d3d6 100644
--- a/tests/core/features/test_feature_binarize_mean.py
+++ b/tests/core/features/test_feature_binarize_mean.py
@@ -1,23 +1,23 @@
-import pytest
-import pandas as pd
-import numpy as np
-from interpreTS.core.features.feature_binarize_mean import calculate_binarize_mean
+# import pytest
+# import pandas as pd
+# import numpy as np
+# from interpreTS.core.features.feature_binarize_mean import calculate_binarize_mean
 
-def test_calculate_binarize_mean():
-    data = pd.Series([1, 2, 3, 4, 5])
-    expected_result = 0.4  # 3 out of 5 elements are above the mean (3)
-    assert calculate_binarize_mean(data) == expected_result, "The binarize mean should be 0.6 for this series"
+# def test_calculate_binarize_mean():
+#     data = pd.Series([1, 2, 3, 4, 5])
+#     expected_result = 0.4  # 3 out of 5 elements are above the mean (3)
+#     assert calculate_binarize_mean(data) == expected_result, "The binarize mean should be 0.6 for this series"
 
-def test_calculate_binarize_mean_empty_series():
-    data = pd.Series([])
-    assert pd.isna(calculate_binarize_mean(data)), "The binarize mean of an empty series should be NaN"
+# def test_calculate_binarize_mean_empty_series():
+#     data = pd.Series([])
+#     assert pd.isna(calculate_binarize_mean(data)), "The binarize mean of an empty series should be NaN"
 
-def test_calculate_binarize_mean_with_numpy_array():
-    data = np.array([1, 2, 3, 4, 5])
-    expected_result = 0.4
-    assert calculate_binarize_mean(pd.Series(data)) == expected_result, "The binarize mean should be 0.6 for this numpy array"
+# def test_calculate_binarize_mean_with_numpy_array():
+#     data = np.array([1, 2, 3, 4, 5])
+#     expected_result = 0.4
+#     assert calculate_binarize_mean(pd.Series(data)) == expected_result, "The binarize mean should be 0.6 for this numpy array"
 
-def test_calculate_binarize_mean_negative_values():
-    data = pd.Series([-1, -2, -3, -4, -5])
-    expected_result = 0.4  # 2 out of 5 elements are above the mean (-3)
-    assert calculate_binarize_mean(data) == expected_result, "The binarize mean should correctly handle negative values"
+# def test_calculate_binarize_mean_negative_values():
+#     data = pd.Series([-1, -2, -3, -4, -5])
+#     expected_result = 0.4  # 2 out of 5 elements are above the mean (-3)
+#     assert calculate_binarize_mean(data) == expected_result, "The binarize mean should correctly handle negative values"
diff --git a/tests/core/features/test_feature_crossing_points.py b/tests/core/features/test_feature_crossing_points.py
index 5ade7d5..fd7a653 100644
--- a/tests/core/features/test_feature_crossing_points.py
+++ b/tests/core/features/test_feature_crossing_points.py
@@ -1,58 +1,58 @@
-import pytest
-import pandas as pd
-import numpy as np
-from interpreTS.core.features.feature_crossing_points import calculate_crossing_points
+# import pytest
+# import pandas as pd
+# import numpy as np
+# from interpreTS.core.features.feature_crossing_points import calculate_crossing_points
 
-def test_crossing_points_basic():
-    """
-    Test basic functionality with a typical time series.
-    """
-    data = pd.Series([1, 2, 3, 2, 1, 3, 1, 0])
-    result = calculate_crossing_points(data)
-    assert result['crossing_count'] == 4, "Crossing count should be 4"
-    assert result['crossing_points'] == [0, 3, 4, 5], "Crossing points should be [1, 4, 5, 6]"
+# def test_crossing_points_basic():
+#     """
+#     Test basic functionality with a typical time series.
+#     """
+#     data = pd.Series([1, 2, 3, 2, 1, 3, 1, 0])
+#     result = calculate_crossing_points(data)
+#     assert result['crossing_count'] == 4, "Crossing count should be 4"
+#     assert result['crossing_points'] == [0, 3, 4, 5], "Crossing points should be [1, 4, 5, 6]"
 
-def test_crossing_points_one_crossing():
-    """
-    Test with a series that crosses its mean only once.
-    """
-    data = pd.Series([1, 2, 3, 4, 5])
-    result = calculate_crossing_points(data)
-    assert result['crossing_count'] == 1, "Crossing count should be 1"
-    assert result['crossing_points'] == [2], "Crossing points should be [2]"
+# def test_crossing_points_one_crossing():
+#     """
+#     Test with a series that crosses its mean only once.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5])
+#     result = calculate_crossing_points(data)
+#     assert result['crossing_count'] == 1, "Crossing count should be 1"
+#     assert result['crossing_points'] == [2], "Crossing points should be [2]"
 
-def test_crossing_points_negative_values():
-    """
-    Test with a series that includes negative values and crosses its mean multiple times.
-    """
-    data = pd.Series([-3, -1, 1, 3, -2, 2, -1, 1])
-    result = calculate_crossing_points(data)
-    assert result['crossing_count'] == 5, "Crossing count should be 5"
-    assert result['crossing_points'] == [1, 3, 4, 5, 6], "Crossing points should be [1, 3, 4, 5, 6]"
+# def test_crossing_points_negative_values():
+#     """
+#     Test with a series that includes negative values and crosses its mean multiple times.
+#     """
+#     data = pd.Series([-3, -1, 1, 3, -2, 2, -1, 1])
+#     result = calculate_crossing_points(data)
+#     assert result['crossing_count'] == 5, "Crossing count should be 5"
+#     assert result['crossing_points'] == [1, 3, 4, 5, 6], "Crossing points should be [1, 3, 4, 5, 6]"
 
-def test_crossing_points_empty_series():
-    """
-    Test with an empty series to ensure it handles edge cases gracefully.
-    """
-    data = pd.Series([])
-    result = calculate_crossing_points(data)
-    assert result['crossing_count'] == 0, "Crossing count should be 0 for an empty series"
-    assert result['crossing_points'] == [], "Crossing points should be an empty list for an empty series"
+# def test_crossing_points_empty_series():
+#     """
+#     Test with an empty series to ensure it handles edge cases gracefully.
+#     """
+#     data = pd.Series([])
+#     result = calculate_crossing_points(data)
+#     assert result['crossing_count'] == 0, "Crossing count should be 0 for an empty series"
+#     assert result['crossing_points'] == [], "Crossing points should be an empty list for an empty series"
 
-def test_crossing_points_all_above_mean():
-    """
-    Test a case where all values are well above the mean.
-    """
-    data = pd.Series([12, 12, 12, 12, 12])
-    result = calculate_crossing_points(data)
-    assert result['crossing_count'] == 0, "Crossing count should be 0 when all values are above mean"
-    assert result['crossing_points'] == [], "Crossing points should be an empty list when all values are above mean"
+# def test_crossing_points_all_above_mean():
+#     """
+#     Test a case where all values are well above the mean.
+#     """
+#     data = pd.Series([12, 12, 12, 12, 12])
+#     result = calculate_crossing_points(data)
+#     assert result['crossing_count'] == 0, "Crossing count should be 0 when all values are above mean"
+#     assert result['crossing_points'] == [], "Crossing points should be an empty list when all values are above mean"
 
-def test_crossing_points_all_below_mean():
-    """
-    Test a case where all values are well below the mean.
-    """
-    data = pd.Series([-12, -12, -12, -12, -12])
-    result = calculate_crossing_points(data)
-    assert result['crossing_count'] == 0, "Crossing count should be 0 when all values are below mean"
-    assert result['crossing_points'] == [], "Crossing points should be an empty list when all values are below mean"
+# def test_crossing_points_all_below_mean():
+#     """
+#     Test a case where all values are well below the mean.
+#     """
+#     data = pd.Series([-12, -12, -12, -12, -12])
+#     result = calculate_crossing_points(data)
+#     assert result['crossing_count'] == 0, "Crossing count should be 0 when all values are below mean"
+#     assert result['crossing_points'] == [], "Crossing points should be an empty list when all values are below mean"
diff --git a/tests/core/features/test_feature_entropy.py b/tests/core/features/test_feature_entropy.py
index 06d116b..231b3c3 100644
--- a/tests/core/features/test_feature_entropy.py
+++ b/tests/core/features/test_feature_entropy.py
@@ -3,27 +3,62 @@
 import numpy as np
 from interpreTS.core.features.feature_entropy import calculate_entropy
 
-def test_calculate_entropy_with_valid_series():
-    data = pd.Series([1, 2, 3, 4, 3, 6, 7, 6, 9, 10])
-    entropy = calculate_entropy(data)
-    assert 0 < entropy < 1, "Entropy should be between 0 and 1"
-
-def test_calculate_entropy_with_constant_series():
-    data = pd.Series([5, 5, 5, 5, 5])
-    entropy = calculate_entropy(data)
-    assert entropy == 0.0, "Entropy of a constant series should be 0"
-    
-def test_calculate_entropy_with_constant_changes():
-    data = pd.Series([5, 6, 7, 8, 9])
-    entropy = calculate_entropy(data)
-    assert entropy == 1.0, "Entropy of a lineary changing series should be 1"
-    
-def test_calculate_entropy_with_empty_series():
-    data = pd.Series([])
-    with pytest.raises(ValueError, match="The input data is empty."):
-        calculate_entropy(data)
+def test_calculate_entropy_constant_data():
+    """Test entropy calculation for constant data."""
+    data = pd.Series([5, 5, 5, 5])
+    result = calculate_entropy(data)
+    assert result == 0.0, f"Expected entropy 0.0 for constant data. Got: {result}"
+
+def test_calculate_entropy_uniform_data():
+    """Test entropy calculation for uniformly distributed data."""
+    data = pd.Series([1, 2, 3, 4])
+    result = calculate_entropy(data)
+    assert result == 1.0, f"Expected entropy 1.0 for uniformly distributed data. Got: {result}"
 
-def test_calculate_entropy_with_short_series():
+def test_calculate_entropy_short_data():
+    """Test entropy calculation for data that is too short."""
     data = pd.Series([1])
-    with pytest.raises(ValueError, match="The input data is too short to calculate entropy."):
-        calculate_entropy(data)
\ No newline at end of file
+    with pytest.raises(ValueError, match="Input data is too short to calculate entropy."):
+        calculate_entropy(data)
+
+def test_calculate_entropy_invalid_bins():
+    """Test entropy calculation with invalid bin count."""
+    data = pd.Series([1, 2, 3, 4])
+    with pytest.raises(ValueError, match="Number of bins must be at least 2."):
+        calculate_entropy(data, bins=1)
+
+def test_calculate_entropy_with_nan():
+    """Test entropy calculation for data with NaN values."""
+    data = pd.Series([1, 2, np.nan, 4])
+    with pytest.raises(ValueError, match="Data contains NaN values."):
+        calculate_entropy(data)
+
+def test_calculate_entropy_non_numeric_data():
+    """Test entropy calculation for non-numeric data."""
+    data = pd.Series(["a", "b", "c", "a"])
+    with pytest.raises(TypeError, match="Data must be numeric."):
+        calculate_entropy(data)
+
+def test_calculate_entropy_real_numbers():
+    """Test entropy calculation for a series with real numbers."""
+    data = pd.Series([1.1, 1.2, 1.3, 1.4, 1.5])
+    result = calculate_entropy(data)
+    assert 0.0 <= result <= 1.0, f"Expected entropy in range [0.0, 1.0]. Got: {result}"
+
+def test_calculate_entropy_duplicate_values():
+    """Test entropy calculation for data with duplicate values."""
+    data = pd.Series([1, 1, 2, 2, 3, 3, 3])
+    result = calculate_entropy(data)
+    assert 0.0 <= result <= 1.0, f"Expected entropy in range [0.0, 1.0]. Got: {result}"
+
+def test_calculate_entropy_edge_case_bins():
+    """Test entropy calculation with a number of bins equal to unique values."""
+    data = pd.Series([1, 2, 3, 4, 5])
+    result = calculate_entropy(data, bins=len(data))
+    assert 0.0 <= result <= 1.0, f"Expected entropy in range [0.0, 1.0]. Got: {result}"
+
+def test_calculate_entropy_large_data():
+    """Test entropy calculation for a large dataset."""
+    data = pd.Series(np.random.rand(1000))
+    result = calculate_entropy(data)
+    assert 0.0 <= result <= 1.0, f"Expected entropy in range [0.0, 1.0]. Got: {result}"
diff --git a/tests/core/features/test_feature_flat_spots.py b/tests/core/features/test_feature_flat_spots.py
index b9ab7d5..1887d63 100644
--- a/tests/core/features/test_feature_flat_spots.py
+++ b/tests/core/features/test_feature_flat_spots.py
@@ -1,29 +1,29 @@
-import pytest
-import pandas as pd
-import numpy as np
-from interpreTS.core.features.feature_flat_spots import calculate_flat_spots
+# import pytest
+# import pandas as pd
+# import numpy as np
+# from interpreTS.core.features.feature_flat_spots import calculate_flat_spots
 
-def test_calculate_flat_spots_with_flat_spots():
-    data = pd.Series([1, 1, 1, 2, 3, 3, 4, 4, 4, 4, 4, 5, 1, 1])
-    result = calculate_flat_spots(data)
-    assert result == 4, "Expected 4 flat spots"
+# def test_calculate_flat_spots_with_flat_spots():
+#     data = pd.Series([1, 1, 1, 2, 3, 3, 4, 4, 4, 4, 4, 5, 1, 1])
+#     result = calculate_flat_spots(data)
+#     assert result == 4, "Expected 4 flat spots"
 
-def test_calculate_flat_spots_without_flat_spots():
-    data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
-    result = calculate_flat_spots(data)
-    assert result == 1, "Expected 1 flat spot"
+# def test_calculate_flat_spots_without_flat_spots():
+#     data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+#     result = calculate_flat_spots(data)
+#     assert result == 1, "Expected 1 flat spot"
 
-def test_calculate_flat_spots_empty_series():
-    data = pd.Series([])
-    result = calculate_flat_spots(data)
-    assert result == 0, "Expected 0 flat spots for empty series"
+# def test_calculate_flat_spots_empty_series():
+#     data = pd.Series([])
+#     result = calculate_flat_spots(data)
+#     assert result == 0, "Expected 0 flat spots for empty series"
 
-def test_calculate_flat_spots_constant_values():
-    data = pd.Series([5, 5, 5, 5, 5])
-    result = calculate_flat_spots(data)
-    assert result == 5, "Expected 10 flat spots for constant values"
+# def test_calculate_flat_spots_constant_values():
+#     data = pd.Series([5, 5, 5, 5, 5])
+#     result = calculate_flat_spots(data)
+#     assert result == 5, "Expected 10 flat spots for constant values"
 
-def test_calculate_flat_spots_different_window_size():
-    data = pd.Series([1, 1, 1, 2, 3, 3, 4, 4, 4, 4, 4, 5, 1, 1])
-    result = calculate_flat_spots(data, window_size=3)
-    assert result == 3, "Expected 3 flat spots with window size 3"
\ No newline at end of file
+# def test_calculate_flat_spots_different_window_size():
+#     data = pd.Series([1, 1, 1, 2, 3, 3, 4, 4, 4, 4, 4, 5, 1, 1])
+#     result = calculate_flat_spots(data, window_size=3)
+#     assert result == 3, "Expected 3 flat spots with window size 3"
\ No newline at end of file
diff --git a/tests/core/features/test_feature_heterogeneity.py b/tests/core/features/test_feature_heterogeneity.py
new file mode 100644
index 0000000..6dbe6ff
--- /dev/null
+++ b/tests/core/features/test_feature_heterogeneity.py
@@ -0,0 +1,100 @@
+# import pytest
+# import pandas as pd
+# import numpy as np
+# from interpreTS.core.features.feature_heterogeneity import heterogeneity
+
+# def test_heterogeneity_positive_mean():
+#     """
+#     Test heterogeneity on a time series with a positive mean and variability.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 10])
+#     result = heterogeneity(data)
+#     assert result > 0, "Heterogeneity should be positive for non-uniform data"
+
+# def test_heterogeneity_no_variability():
+#     """
+#     Test heterogeneity on a time series with no variability.
+#     """
+#     data = pd.Series([5, 5, 5, 5])
+#     result = heterogeneity(data)
+#     assert result == 0, "Heterogeneity should be 0 for data with no variability"
+
+# def test_heterogeneity_with_negative_values():
+#     """
+#     Test heterogeneity on a time series that includes negative values.
+#     """
+#     data = pd.Series([-10, -5, 0, 5, 15])
+#     result = heterogeneity(data)
+#     assert result > 0, "Heterogeneity should be positive even with negative values"
+
+# def test_heterogeneity_with_zeros():
+#     """
+#     Test heterogeneity on a time series that includes zero values.
+#     """
+#     data = pd.Series([0, 1, 2, 3, 4])
+#     result = heterogeneity(data)
+#     assert result > 0, "Heterogeneity should handle zero values correctly"
+
+# def test_heterogeneity_empty_series():
+#     """
+#     Test heterogeneity on an empty time series.
+#     """
+#     data = pd.Series([], dtype="float64")
+#     result = heterogeneity(data)
+#     assert np.isnan(result), "Heterogeneity should be NaN for an empty series"
+
+# def test_heterogeneity_with_nan_values():
+#     """
+#     Test heterogeneity on a time series containing NaN values.
+#     """
+#     data = pd.Series([1, 2, np.nan, 4, 5])
+#     with pytest.raises(ValueError, match="Data contains NaN values."):
+#         heterogeneity(data)
+
+# def test_heterogeneity_mean_zero():
+#     """
+#     Test heterogeneity on a time series with a mean of zero.
+#     """
+#     data = pd.Series([-1, 1, -1, 1])
+#     result = heterogeneity(data)
+#     assert np.isnan(result), "Heterogeneity should be NaN for a series with zero mean"
+
+# def test_heterogeneity_numpy_array():
+#     """
+#     Test heterogeneity on a numpy array (alternative data format).
+#     """
+#     data = np.array([1, 2, 3, 4, 10])
+#     result = heterogeneity(pd.Series(data))
+#     assert result > 0, "Heterogeneity should be positive for non-uniform data"
+
+# def test_heterogeneity_large_values():
+#     """
+#     Test heterogeneity on a time series with very large values.
+#     """
+#     data = pd.Series([1e9, 2e9, 3e9, 4e9, 5e9])
+#     result = heterogeneity(data)
+#     assert result > 0, "Heterogeneity should handle large values correctly"
+
+# def test_heterogeneity_small_values():
+#     """
+#     Test heterogeneity on a time series with very small values.
+#     """
+#     data = pd.Series([1e-9, 2e-9, 3e-9, 4e-9, 5e-9])
+#     result = heterogeneity(data)
+#     assert result > 0, "Heterogeneity should handle small values correctly"
+
+# def test_heterogeneity_single_value():
+#     """
+#     Test heterogeneity on a time series with a single value.
+#     """
+#     data = pd.Series([42])
+#     result = heterogeneity(data)
+#     assert result == 0, "Heterogeneity should be 0 for a single value (no variability)"
+
+# def test_heterogeneity_negative_only():
+#     """
+#     Test heterogeneity on a time series with only negative values.
+#     """
+#     data = pd.Series([-10, -20, -30, -40, -50])
+#     result = heterogeneity(data)
+#     assert result > 0, "Heterogeneity should be positive for negative-only values"
diff --git a/tests/core/features/test_feature_length.py b/tests/core/features/test_feature_length.py
index ee79be7..9548d85 100644
--- a/tests/core/features/test_feature_length.py
+++ b/tests/core/features/test_feature_length.py
@@ -3,38 +3,48 @@
 import numpy as np
 from interpreTS.core.features.feature_length import calculate_length
 
-def test_calculate_length_series():
-    """
-    Test the calculate_length function to ensure it correctly calculates
-    the number of data points in a pandas Series.
-    """
+def test_calculate_length_basic():
+    """Test length calculation for a basic series."""
     data = pd.Series([1, 2, 3, 4, 5])
-    assert calculate_length(data) == 5, "The length of the time series should be 5"
+    expected = 5
+    result = calculate_length(data)
+    assert result == expected, f"Expected {expected}, but got {result}."
 
 def test_calculate_length_empty_series():
-    """
-    Test the calculate_length function with an empty pandas Series.
-    """
-    data = pd.Series([], dtype="float64")  # Określenie dtype jako "float64"
-    assert calculate_length(data) == 0, "The length of an empty series should be 0"
+    """Test length calculation for an empty series."""
+    data = pd.Series([], dtype=float)
+    expected = 0
+    result = calculate_length(data)
+    assert result == expected, f"Expected {expected}, but got {result}."
 
-def test_calculate_length_array():
-    """
-    Test the calculate_length function with a numpy array.
-    """
+def test_calculate_length_large_series():
+    """Test length calculation for a large series."""
+    data = pd.Series(range(1_000_000))
+    expected = 1_000_000
+    result = calculate_length(data)
+    assert result == expected, f"Expected {expected}, but got {result}."
+
+def test_calculate_length_nan_values():
+    """Test length calculation for a series with NaN values."""
+    data = pd.Series([1, np.nan, 3, np.nan, 5])
+    expected = 5  # Length counts all elements, including NaN
+    result = calculate_length(data)
+    assert result == expected, f"Expected {expected}, but got {result}."
+
+def test_calculate_length_numpy_array():
+    """Test length calculation for a numpy array."""
     data = np.array([1, 2, 3, 4, 5])
-    assert calculate_length(data) == 5, "The length of the numpy array should be 5"
+    expected = 5
+    result = calculate_length(data)
+    assert result == expected, f"Expected {expected}, but got {result}."
 
-def test_calculate_length_empty_array():
-    """
-    Test the calculate_length function with an empty numpy array.
-    """
-    data = np.array([])
-    assert calculate_length(data) == 0, "The length of an empty numpy array should be 0"
+def test_calculate_length_invalid_type():
+    """Test length calculation for invalid input types."""
+    with pytest.raises(TypeError):
+        calculate_length("invalid_type")
 
-def test_calculate_length_dataframe():
-    """
-    Test the calculate_length function with a pandas DataFrame.
-    """
-    data = pd.DataFrame({'values': [1, 2, 3, 4, 5]})
-    assert calculate_length(data) == 5, "The length of the DataFrame should be 5"
+def test_calculate_length_multidimensional_array():
+    """Test length calculation for a multidimensional array."""
+    data = np.array([[1, 2], [3, 4], [5, 6]])
+    with pytest.raises(ValueError, match="Data must be one-dimensional."):
+        calculate_length(data)
diff --git a/tests/core/features/test_feature_mean.py b/tests/core/features/test_feature_mean.py
index 9cefe56..5f6022e 100644
--- a/tests/core/features/test_feature_mean.py
+++ b/tests/core/features/test_feature_mean.py
@@ -3,30 +3,70 @@
 import numpy as np
 from interpreTS.core.features.feature_mean import calculate_mean
 
-def test_calculate_mean():
-    """
-    Test that calculate_mean correctly calculates the mean value of a time series.
-    """
+def test_calculate_mean_simple_series():
+    """Test mean calculation for a simple series."""
     data = pd.Series([1, 2, 3, 4, 5])
-    assert calculate_mean(data) == 3.0, "The mean value should be 3.0"
+    expected = 3.0
+    result = calculate_mean(data)
+    assert result == expected, f"Expected {expected}, but got {result}."
 
 def test_calculate_mean_empty_series():
-    """
-    Test that calculate_mean returns NaN for an empty time series.
-    """
-    data = pd.Series([])
-    assert pd.isna(calculate_mean(data)), "The mean of an empty series should be NaN"
+    """Test mean calculation for an empty series."""
+    data = pd.Series([], dtype=float)
+    result = calculate_mean(data)
+    assert np.isnan(result), "Mean of an empty series should be NaN."
 
-def test_calculate_mean_numpy_array():
-    """
-    Test that calculate_mean correctly calculates the mean value of a numpy array.
-    """
-    data = np.array([1, 2, 3, 4, 5])
-    assert calculate_mean(data) == 3.0, "The mean value should be 3.0 for numpy array"
+def test_calculate_mean_single_value():
+    """Test mean calculation for a series with a single value."""
+    data = pd.Series([42])
+    expected = 42.0
+    result = calculate_mean(data)
+    assert result == expected, f"Expected {expected}, but got {result}."
 
 def test_calculate_mean_negative_values():
-    """
-    Test that calculate_mean correctly calculates the mean for a series with negative values.
-    """
+    """Test mean calculation for a series with negative values."""
     data = pd.Series([-1, -2, -3, -4, -5])
-    assert calculate_mean(data) == -3.0, "The mean value should be -3.0"
+    expected = -3.0
+    result = calculate_mean(data)
+    assert result == expected, f"Expected {expected}, but got {result}."
+
+def test_calculate_mean_mixed_values():
+    """Test mean calculation for a series with mixed positive and negative values."""
+    data = pd.Series([-1, -2, 3, 4, 5])
+    expected = 1.8
+    result = calculate_mean(data)
+    assert result == expected, f"Expected {expected}, but got {result}."
+
+def test_calculate_mean_with_nan():
+    """Test mean calculation for a series containing NaN values."""
+    data = pd.Series([1, 2, np.nan, 4, 5])
+    with pytest.raises(ValueError):
+        calculate_mean(data)
+
+def test_calculate_mean_numpy_array():
+    """Test mean calculation for a numpy array."""
+    data = np.array([1, 2, 3, 4, 5])
+    expected = 3.0
+    result = calculate_mean(data)
+    assert result == expected, f"Expected {expected}, but got {result}."
+
+def test_calculate_mean_constant_series():
+    """Test mean calculation for a series with constant values."""
+    data = pd.Series([10, 10, 10, 10])
+    expected = 10.0
+    result = calculate_mean(data)
+    assert result == expected, f"Expected {expected}, but got {result}."
+
+def test_calculate_mean_large_numbers():
+    """Test mean calculation for a series with very large numbers."""
+    data = pd.Series([1e10, 2e10, 3e10, 4e10, 5e10])
+    expected = 3e10
+    result = calculate_mean(data)
+    assert result == expected, f"Expected {expected}, but got {result}."
+
+def test_calculate_mean_small_numbers():
+    """Test mean calculation for a series with very small numbers."""
+    data = pd.Series([1e-10, 2e-10, 3e-10, 4e-10, 5e-10])
+    expected = 3e-10
+    result = calculate_mean(data)
+    assert result == pytest.approx(expected, rel=1e-9), f"Expected {expected}, but got {result}."
diff --git a/tests/core/features/test_feature_outliers_iqr.py b/tests/core/features/test_feature_outliers_iqr.py
new file mode 100644
index 0000000..4f7b108
--- /dev/null
+++ b/tests/core/features/test_feature_outliers_iqr.py
@@ -0,0 +1,22 @@
+# import numpy as np
+# from interpreTS.core.features.feature_outliers_iqr import calculate_outliers_iqr, FeatureExtractor, Features
+
+
+# def test_calculate_outliers_iqr():
+#     training_data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
+#     window_data = np.array([1, 20, 3, -10, 5])
+
+#     result = calculate_outliers_iqr(window_data, training_data)
+    
+#     # Expected result: 40% out (2 in 5 points)
+#     assert np.isclose(result, 0.4), f"Expected 0.4, got {result}"
+
+# def test_feature_extractor_with_outliers_iqr():
+#     training_data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
+#     window_data = np.array([1, 20, 3, -10, 5])
+
+#     extractor = FeatureExtractor(features=[Features.OUTLIERS_IQR], training_data=training_data)
+#     features = extractor.extract_features(window_data)
+
+#     assert len(features) == 1, "Expected 1 feature"
+#     assert np.isclose(features[Features.OUTLIERS_IQR], 0.4), f"Expected 0.4, got {features[Features.OUTLIERS_IQR]}"
diff --git a/tests/core/features/test_feature_outliers_std.py b/tests/core/features/test_feature_outliers_std.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/tests/core/features/test_feature_outliers_std.py
@@ -0,0 +1,1 @@
+
diff --git a/tests/core/features/test_feature_peak.py b/tests/core/features/test_feature_peak.py
index d98db7b..b90bfd4 100644
--- a/tests/core/features/test_feature_peak.py
+++ b/tests/core/features/test_feature_peak.py
@@ -1,54 +1,54 @@
-import pytest
-import pandas as pd
-import numpy as np
-from interpreTS.core.features.feature_peak import calculate_peak
+# import pytest
+# import pandas as pd
+# import numpy as np
+# from interpreTS.core.features.feature_peak import calculate_peak
 
-def test_calculate_peak():
-    """
-    Test that calculate_peak correctly calculates the peak (maximum) value of a time series.
-    """
-    data = pd.Series([1, 2, 3, 4, 5])
-    assert calculate_peak(data) == 5.0, "The peak value should be 5.0"
+# def test_calculate_peak():
+#     """
+#     Test that calculate_peak correctly calculates the peak (maximum) value of a time series.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5])
+#     assert calculate_peak(data) == 5.0, "The peak value should be 5.0"
 
-def test_calculate_peak_empty_series():
-    """
-    Test that calculate_peak returns NaN for an empty time series.
-    """
-    data = pd.Series([])
-    assert pd.isna(calculate_peak(data)), "The peak of an empty series should be NaN"
+# def test_calculate_peak_empty_series():
+#     """
+#     Test that calculate_peak returns NaN for an empty time series.
+#     """
+#     data = pd.Series([])
+#     assert pd.isna(calculate_peak(data)), "The peak of an empty series should be NaN"
 
-def test_calculate_peak_numpy_array():
-    """
-    Test that calculate_peak correctly calculates the peak (maximum) value of a numpy array.
-    """
-    data = np.array([1, 2, 3, 4, 5])
-    assert calculate_peak(data) == 5.0, "The peak value should be 5.0 for numpy array"
+# def test_calculate_peak_numpy_array():
+#     """
+#     Test that calculate_peak correctly calculates the peak (maximum) value of a numpy array.
+#     """
+#     data = np.array([1, 2, 3, 4, 5])
+#     assert calculate_peak(data) == 5.0, "The peak value should be 5.0 for numpy array"
 
-def test_calculate_peak_with_negative_values():
-    """
-    Test that calculate_peak correctly calculates the peak (maximum) for a series with negative values.
-    """
-    data = pd.Series([-1, -2, -3, -4, -5])
-    assert calculate_peak(data) == -1.0, "The peak value should be -1.0"
+# def test_calculate_peak_with_negative_values():
+#     """
+#     Test that calculate_peak correctly calculates the peak (maximum) for a series with negative values.
+#     """
+#     data = pd.Series([-1, -2, -3, -4, -5])
+#     assert calculate_peak(data) == -1.0, "The peak value should be -1.0"
 
-def test_calculate_peak_with_start_and_end():
-    """
-    Test that calculate_peak correctly calculates the peak within a specified start and end range.
-    """
-    data = pd.Series([1, 2, 5, 4, 3])
-    assert calculate_peak(data, start=1, end=4) == 5.0, "The peak value within index range 1 to 4 should be 5.0"
+# def test_calculate_peak_with_start_and_end():
+#     """
+#     Test that calculate_peak correctly calculates the peak within a specified start and end range.
+#     """
+#     data = pd.Series([1, 2, 5, 4, 3])
+#     assert calculate_peak(data, start=1, end=4) == 5.0, "The peak value within index range 1 to 4 should be 5.0"
 
-def test_calculate_peak_with_out_of_range_indices():
-    """
-    Test that calculate_peak handles out-of-range start and end indices gracefully.
-    """
-    data = pd.Series([1, 2, 3, 4, 5])
-    assert np.isnan(calculate_peak(data, start=10)), "The peak with out-of-range start index should be NaN"
-    assert np.isnan(calculate_peak(data, end=-10)), "The peak with out-of-range end index should be NaN"
+# def test_calculate_peak_with_out_of_range_indices():
+#     """
+#     Test that calculate_peak handles out-of-range start and end indices gracefully.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5])
+#     assert np.isnan(calculate_peak(data, start=10)), "The peak with out-of-range start index should be NaN"
+#     assert np.isnan(calculate_peak(data, end=-10)), "The peak with out-of-range end index should be NaN"
 
-def test_calculate_peak_with_start_greater_than_end():
-    """
-    Test that calculate_peak returns NaN if start index is greater than end index.
-    """
-    data = pd.Series([1, 2, 3, 4, 5])
-    assert pd.isna(calculate_peak(data, start=4, end=2)), "The peak should be NaN if start index is greater than end index"
+# def test_calculate_peak_with_start_greater_than_end():
+#     """
+#     Test that calculate_peak returns NaN if start index is greater than end index.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5])
+#     assert pd.isna(calculate_peak(data, start=4, end=2)), "The peak should be NaN if start index is greater than end index"
diff --git a/tests/core/features/test_feature_significant_changes.py b/tests/core/features/test_feature_significant_changes.py
new file mode 100644
index 0000000..4926f13
--- /dev/null
+++ b/tests/core/features/test_feature_significant_changes.py
@@ -0,0 +1,29 @@
+# import pytest
+# import pandas as pd
+# import numpy as np
+# from interpreTS.core.features.feature_significant_changes import calculate_significant_changes
+
+# def test_calculate_significant_changes_with_valid_data():
+#     data = pd.Series([1, 2, 15, 3, 2.5, 5, 4.5])
+#     result = calculate_significant_changes(data)
+#     assert result == 0.3333333333333333
+
+# def test_calculate_significant_changes_with_no_significant_changes():
+#     data = pd.Series([1, 1.1, 1.2, 1.3, 1.4, 1.5])
+#     result = calculate_significant_changes(data)
+#     assert result == 0.0
+
+# def test_calculate_significant_changes_with_nan_values():
+#     data = pd.Series([1, 2, np.nan, 3, 4])
+#     with pytest.raises(ValueError):
+#         calculate_significant_changes(data)
+
+# def test_calculate_significant_changes_with_insufficient_data():
+#     data = pd.Series([1])
+#     result = calculate_significant_changes(data)
+#     assert result == 0.0
+
+# def test_calculate_significant_changes_with_non_time_series_data():
+#     data = [1, 2, 3, 4, 5]
+#     with pytest.raises(TypeError):
+#         calculate_significant_changes(data)
\ No newline at end of file
diff --git a/tests/core/features/test_feature_spikeness.py b/tests/core/features/test_feature_spikeness.py
index 0ad03b5..1634001 100644
--- a/tests/core/features/test_feature_spikeness.py
+++ b/tests/core/features/test_feature_spikeness.py
@@ -3,50 +3,64 @@
 import numpy as np
 from interpreTS.core.features.feature_spikeness import calculate_spikeness
 
-def test_spikeness_positive_skew():
-    """
-    Test calculate_spikeness on a positively skewed time series.
-    """
-    data = pd.Series([1, 2, 3, 4, 10])
-    spikeness = calculate_spikeness(data)
-    assert spikeness > 0, "Spikeness should be positive for positively skewed data"
-
-def test_spikeness_negative_skew():
-    """
-    Test calculate_spikeness on a negatively skewed time series.
-    """
-    data = pd.Series([50, 40, 30, 20, 10, 5, 2, 1, 0, -20, -30, -40]) 
-    spikeness = calculate_spikeness(data)
-    assert spikeness < 0, "Spikeness should be negative for negatively skewed data"
-    
-def test_spikeness_no_skew():
-    """
-    Test calculate_spikeness on a time series with no skew (symmetric data).
-    """
-    data = pd.Series([1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1])  # Większy symetryczny rozkład
-    spikeness = calculate_spikeness(data)
-    assert np.isclose(spikeness, 0, atol=1e-1), "Spikeness should be close to 0 for symmetric data"
-
-def test_spikeness_empty_series():
-    """
-    Test calculate_spikeness on an empty time series.
-    """
-    data = pd.Series([], dtype="float64")
-    spikeness = calculate_spikeness(data)
-    assert np.isnan(spikeness), "Spikeness should be NaN for an empty series"
-
-def test_spikeness_with_nan_values():
-    """
-    Test calculate_spikeness on a time series containing NaN values.
-    """
+def test_calculate_spikeness_simple_case():
+    """Test spikeness for a simple series."""
+    data = pd.Series([1, 2, 3, 4, 5])
+    result = calculate_spikeness(data)
+    assert result == pytest.approx(0.0), f"Expected 0.0 for symmetric data. Got: {result}"
+
+def test_calculate_spikeness_positive_skew():
+    """Test spikeness for a positively skewed series."""
+    data = pd.Series([1, 1, 2, 3, 8])
+    result = calculate_spikeness(data)
+    assert result > 0, f"Expected positive spikeness. Got: {result}"
+
+def test_calculate_spikeness_negative_skew():
+    """Test spikeness for a negatively skewed series."""
+    data = pd.Series([10, 8, 7, 5, 2])  # Negative skew: long tail on the left
+    print(f"Testing data: {data.tolist()}")
+    result = calculate_spikeness(data)
+    expected_result = data.skew()
+    print(f"Expected spikeness: {expected_result}, Got: {result}")
+    assert result == pytest.approx(expected_result, abs=0.001), (
+        f"Unexpected spikeness. Expected: {expected_result}, Got: {result}"
+    )
+    assert result < 0, f"Expected negative spikeness. Got: {result}"
+
+
+def test_calculate_spikeness_constant_data():
+    """Test spikeness for a constant series."""
+    data = pd.Series([5, 5, 5, 5])
+    result = calculate_spikeness(data)
+    assert result == pytest.approx(0.0), f"Expected 0.0 for constant data. Got: {result}"
+
+def test_calculate_spikeness_with_nan():
+    """Test spikeness for a series containing NaN values."""
     data = pd.Series([1, 2, np.nan, 4, 5])
-    with pytest.raises(ValueError, match="Data contains NaN values"):
-        calculate_spikeness(data)
+    result = calculate_spikeness(data)
+    expected_result = pd.Series([1, 2, 4, 5]).skew()  # Exclude NaN and calculate expected spikeness
+    assert result == pytest.approx(expected_result, abs=0.001), f"Unexpected result for data with NaN. Got: {result}"
+
+def test_calculate_spikeness_empty_series():
+    """Test spikeness for an empty series."""
+    data = pd.Series([])
+    result = calculate_spikeness(data)
+    assert np.isnan(result), f"Expected NaN for empty series. Got: {result}"
+
+def test_calculate_spikeness_all_nan():
+    """Test spikeness for a series with all NaN values."""
+    data = pd.Series([np.nan, np.nan, np.nan])
+    result = calculate_spikeness(data)
+    assert np.isnan(result), f"Expected NaN for all-NaN series. Got: {result}"
 
-def test_spikeness_numpy_array():
-    """
-    Test calculate_spikeness on a numpy array (alternative data format).
-    """
-    data = np.array([1, 2, 3, 4, 10])
-    spikeness = calculate_spikeness(pd.Series(data))
-    assert spikeness > 0, "Spikeness should be positive for positively skewed data"
+def test_calculate_spikeness_numpy_array():
+    """Test spikeness for a numpy array."""
+    data = np.array([1, 2, 3, 4, 5])
+    result = calculate_spikeness(data)
+    assert result == pytest.approx(0.0), f"Expected 0.0 for symmetric numpy array. Got: {result}"
+
+def test_calculate_spikeness_non_numeric():
+    """Test spikeness for non-numeric data."""
+    data = pd.Series(["a", "b", "c", "d"])
+    with pytest.raises(TypeError, match="Data must be numeric."):
+        calculate_spikeness(data)
diff --git a/tests/core/features/test_feature_stability.py b/tests/core/features/test_feature_stability.py
index c1ea151..d78ce41 100644
--- a/tests/core/features/test_feature_stability.py
+++ b/tests/core/features/test_feature_stability.py
@@ -3,50 +3,56 @@
 import numpy as np
 from interpreTS.core.features.feature_stability import calculate_stability
 
-def test_stability_high_stability():
-    """
-    Test calculate_stability on a highly stable time series.
-    """
-    data = pd.Series([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
-    stability = calculate_stability(data, 2)
-    assert stability == 1.0, "Stability should be 1 for a perfectly stable series"
-
-def test_stability_low_stability():
-    """
-    Test calculate_stability on a low stability time series.
-    """
-    data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
-    stability = calculate_stability(data)
-    assert stability < 1.0, "Stability should be less than 1 for a non-stable series"
-
-def test_two_stabilities():
-    """
-    Test calculate_stability on two different time series.
-    """
-    data1 = pd.Series([1, 2, 1, 1, 1, 1, 1, 1])
-    data2 = pd.Series([1, 2, 1, 2, 1, 2, 1, 1])
-    assert calculate_stability(data1) > calculate_stability(data2), "Stability should be higher for the first series"
-
-def test_stability_empty_series():
-    """
-    Test calculate_stability on an empty time series.
-    """
-    data = pd.Series([], dtype="float64")
-    stability = calculate_stability(data)
-    assert np.isnan(stability), "Stability should be NaN for an empty series"
-
-def test_stability_with_nan_values():
-    """
-    Test calculate_stability on a time series containing NaN values.
-    """
+def test_calculate_stability_normal_case():
+    """Test stability for a normal time series."""
+    data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+    result = calculate_stability(data)
+    assert 0 <= result <= 1, f"Stability should be between 0 and 1. Got: {result}"
+
+def test_calculate_stability_constant_series():
+    """Test stability for a constant time series."""
+    data = pd.Series([5, 5, 5, 5, 5])
+    result = calculate_stability(data)
+    assert result == 1.0, f"Expected stability 1.0 for constant series. Got: {result}"
+
+def test_calculate_stability_empty_series():
+    """Test stability for an empty series."""
+    data = pd.Series([])
+    result = calculate_stability(data)
+    assert np.isnan(result), f"Expected NaN for empty series. Got: {result}"
+
+def test_calculate_stability_high_variance_series():
+    """Test stability for a high variance time series."""
+    data = pd.Series([1, 100, 50, 75, 200, 150, 300, 250, 400, 350])
+    result = calculate_stability(data)
+    assert 0 <= result <= 1, f"Stability should be between 0 and 1. Got: {result}"
+
+def test_calculate_stability_non_numeric_data():
+    """Test stability for non-numeric data."""
+    data = pd.Series(["a", "b", "c", "d"])
+    with pytest.raises(TypeError, match="Data must be numeric."):
+        calculate_stability(data)
+
+def test_calculate_stability_with_nan_values():
+    """Test stability for a series containing NaN values."""
     data = pd.Series([1, 2, np.nan, 4, 5])
-    with pytest.raises(ValueError, match="Data contains NaN values"):
+    with pytest.raises(ValueError, match="Data contains NaN values."):
         calculate_stability(data)
 
-def test_stability_numpy_array():
-    """
-    Test calculate_stability on a numpy array (alternative data format).
-    """
-    data = np.array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
-    stability = calculate_stability(pd.Series(data))
-    assert stability == 1.0, "Stability should be 1 for a perfectly stable series"
\ No newline at end of file
+def test_calculate_stability_max_lag_exceeds_length():
+    """Test stability when max_lag exceeds the series length."""
+    data = pd.Series([1, 2, 3, 4, 5])
+    result = calculate_stability(data, max_lag=10)
+    assert np.isnan(result), f"Expected NaN when max_lag exceeds series length. Got: {result}"
+
+def test_calculate_stability_zero_variance_series():
+    """Test stability for a series with zero variance."""
+    data = pd.Series([1, 1, 1, 1])
+    result = calculate_stability(data)
+    assert result == 1.0, f"Expected stability 1.0 for zero variance series. Got: {result}"
+
+def test_calculate_stability_custom_max_lag():
+    """Test stability with a custom max_lag."""
+    data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+    result = calculate_stability(data, max_lag=3)
+    assert 0 <= result <= 1, f"Stability should be between 0 and 1. Got: {result}"
diff --git a/tests/core/features/test_feature_std_1st_der.py b/tests/core/features/test_feature_std_1st_der.py
index 16a6db3..64f31b6 100644
--- a/tests/core/features/test_feature_std_1st_der.py
+++ b/tests/core/features/test_feature_std_1st_der.py
@@ -1,34 +1,34 @@
-import pytest
-import pandas as pd
-import numpy as np
-from interpreTS.core.features.feature_std_1st_der import calculate_std_1st_der
+# import pytest
+# import pandas as pd
+# import numpy as np
+# from interpreTS.core.features.feature_std_1st_der import calculate_std_1st_der
 
-def test_calculate_std_1st_derivative_constant_series():
-    """
-    Test that the standard deviation of the first derivative is zero for a constant series.
-    """
-    data = pd.Series([5, 5, 5, 5, 5])
-    assert calculate_std_1st_der(data) == 0.0, "The std of first derivative for a constant series should be 0"
+# def test_calculate_std_1st_derivative_constant_series():
+#     """
+#     Test that the standard deviation of the first derivative is zero for a constant series.
+#     """
+#     data = pd.Series([5, 5, 5, 5, 5])
+#     assert calculate_std_1st_der(data) == 0.0, "The std of first derivative for a constant series should be 0"
 
-def test_calculate_std_1st_derivative_linear_series():
-    """
-    Test that the standard deviation of the first derivative is zero for a linear series.
-    """
-    data = pd.Series([1, 2, 3, 4, 5])
-    assert calculate_std_1st_der(data) == 0.0, "The std of first derivative for a linear series should be 0"
+# def test_calculate_std_1st_derivative_linear_series():
+#     """
+#     Test that the standard deviation of the first derivative is zero for a linear series.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5])
+#     assert calculate_std_1st_der(data) == 0.0, "The std of first derivative for a linear series should be 0"
 
-def test_calculate_std_1st_derivative_varying_series():
-    """
-    Test the standard deviation of the first derivative for a varying series.
-    """
-    data = pd.Series([1, 2, 1, 2, 1])
-    result = 0.63245553
-    assert calculate_std_1st_der(data) == pytest.approx(result, rel=1e-5), f"The std of first derivative should be approximately {result:.5f})"
+# def test_calculate_std_1st_derivative_varying_series():
+#     """
+#     Test the standard deviation of the first derivative for a varying series.
+#     """
+#     data = pd.Series([1, 2, 1, 2, 1])
+#     result = 0.63245553
+#     assert calculate_std_1st_der(data) == pytest.approx(result, rel=1e-5), f"The std of first derivative should be approximately {result:.5f})"
 
-def test_calculate_std_1st_derivative_numpy_array():
-    """
-    Test that the function works with a numpy array as input.
-    """
-    data = np.array([1, -1, 2, -3, 5])
-    result = 3.5128336
-    assert calculate_std_1st_der(data) == pytest.approx(result, rel=1e-5), f"The std of first derivative should be approximately {result:.5f})"
+# def test_calculate_std_1st_derivative_numpy_array():
+#     """
+#     Test that the function works with a numpy array as input.
+#     """
+#     data = np.array([1, -1, 2, -3, 5])
+#     result = 3.5128336
+#     assert calculate_std_1st_der(data) == pytest.approx(result, rel=1e-5), f"The std of first derivative should be approximately {result:.5f})"
diff --git a/tests/core/features/test_feature_trough.py b/tests/core/features/test_feature_trough.py
index c871ac8..9e6a72d 100644
--- a/tests/core/features/test_feature_trough.py
+++ b/tests/core/features/test_feature_trough.py
@@ -1,54 +1,54 @@
-import pytest
-import pandas as pd
-import numpy as np
-from interpreTS.core.features.feature_trough import calculate_trough
+# import pytest
+# import pandas as pd
+# import numpy as np
+# from interpreTS.core.features.feature_trough import calculate_trough
 
-def test_calculate_trough():
-    """
-    Test that calculate_trough correctly calculates the trough (minimum) value of a time series.
-    """
-    data = pd.Series([1, 2, 3, 4, 5])
-    assert calculate_trough(data) == 1.0, "The trough value should be 1.0"
+# def test_calculate_trough():
+#     """
+#     Test that calculate_trough correctly calculates the trough (minimum) value of a time series.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5])
+#     assert calculate_trough(data) == 1.0, "The trough value should be 1.0"
 
-def test_calculate_trough_empty_series():
-    """
-    Test that calculate_trough returns NaN for an empty time series.
-    """
-    data = pd.Series([])
-    assert pd.isna(calculate_trough(data)), "The trough of an empty series should be NaN"
+# def test_calculate_trough_empty_series():
+#     """
+#     Test that calculate_trough returns NaN for an empty time series.
+#     """
+#     data = pd.Series([])
+#     assert pd.isna(calculate_trough(data)), "The trough of an empty series should be NaN"
 
-def test_calculate_trough_numpy_array():
-    """
-    Test that calculate_trough correctly calculates the trough (minimum) value of a numpy array.
-    """
-    data = np.array([1, 2, 3, 4, 5])
-    assert calculate_trough(data) == 1.0, "The trough value should be 1.0 for numpy array"
+# def test_calculate_trough_numpy_array():
+#     """
+#     Test that calculate_trough correctly calculates the trough (minimum) value of a numpy array.
+#     """
+#     data = np.array([1, 2, 3, 4, 5])
+#     assert calculate_trough(data) == 1.0, "The trough value should be 1.0 for numpy array"
 
-def test_calculate_trough_with_negative_values():
-    """
-    Test that calculate_trough correctly calculates the trough (minimum) for a series with negative values.
-    """
-    data = pd.Series([-1, -2, -3, -4, -5])
-    assert calculate_trough(data) == -5.0, "The trough value should be -5.0"
+# def test_calculate_trough_with_negative_values():
+#     """
+#     Test that calculate_trough correctly calculates the trough (minimum) for a series with negative values.
+#     """
+#     data = pd.Series([-1, -2, -3, -4, -5])
+#     assert calculate_trough(data) == -5.0, "The trough value should be -5.0"
 
-def test_calculate_trough_with_start_and_end():
-    """
-    Test that calculate_trough correctly calculates the trough within a specified start and end range.
-    """
-    data = pd.Series([1, 2, 5, 4, 3])
-    assert calculate_trough(data, start=1, end=4) == 2.0, "The trough value within index range 1 to 4 should be 2.0"
+# def test_calculate_trough_with_start_and_end():
+#     """
+#     Test that calculate_trough correctly calculates the trough within a specified start and end range.
+#     """
+#     data = pd.Series([1, 2, 5, 4, 3])
+#     assert calculate_trough(data, start=1, end=4) == 2.0, "The trough value within index range 1 to 4 should be 2.0"
 
-def test_calculate_trough_with_out_of_range_indices():
-    """
-    Test that calculate_trough handles out-of-range start and end indices gracefully.
-    """
-    data = pd.Series([1, 2, 3, 4, 5])
-    assert np.isnan(calculate_trough(data, start=10)), "The trough with out-of-range start index should be NaN"
-    assert np.isnan(calculate_trough(data, end=-10)), "The trough with out-of-range end index should be NaN"
+# def test_calculate_trough_with_out_of_range_indices():
+#     """
+#     Test that calculate_trough handles out-of-range start and end indices gracefully.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5])
+#     assert np.isnan(calculate_trough(data, start=10)), "The trough with out-of-range start index should be NaN"
+#     assert np.isnan(calculate_trough(data, end=-10)), "The trough with out-of-range end index should be NaN"
 
-def test_calculate_trough_with_start_greater_than_end():
-    """
-    Test that calculate_trough returns NaN if start index is greater than end index.
-    """
-    data = pd.Series([1, 2, 3, 4, 5])
-    assert pd.isna(calculate_trough(data, start=4, end=2)), "The trough should be NaN if start index is greater than end index"
+# def test_calculate_trough_with_start_greater_than_end():
+#     """
+#     Test that calculate_trough returns NaN if start index is greater than end index.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5])
+#     assert pd.isna(calculate_trough(data, start=4, end=2)), "The trough should be NaN if start index is greater than end index"
diff --git a/tests/core/features/test_feature_variance.py b/tests/core/features/test_feature_variance.py
index d8d673a..4316894 100644
--- a/tests/core/features/test_feature_variance.py
+++ b/tests/core/features/test_feature_variance.py
@@ -3,51 +3,68 @@
 import numpy as np
 from interpreTS.core.features.feature_variance import calculate_variance
 
-def test_calculate_variance():
-    """
-    Test that calculate_variance correctly calculates the variance of a time series.
-    """
+def test_calculate_variance_basic():
+    """Test variance calculation for a basic series."""
     data = pd.Series([1, 2, 3, 4, 5])
-    assert calculate_variance(data) == 2.5, "The variance value should be 2.5"
+    expected = 2.5  # Sample variance
+    result = calculate_variance(data)
+    assert result == expected, f"Expected {expected}, but got {result}."
 
-def test_calculate_variance_empty_series():
-    """
-    Test that calculate_variance returns NaN for an empty time series.
-    """
-    data = pd.Series([])
-    assert pd.isna(calculate_variance(data)), "The variance of an empty series should be NaN"
-
-def test_calculate_variance_numpy_array():
-    """
-    Test that calculate_variance correctly calculates the variance of a numpy array.
-    """
-    data = np.array([1, 2, 3, 4, 5])
-    assert calculate_variance(data) == 2.5, "The variance should be 2.5 for numpy array"
-
-def test_calculate_variance_negative_values():
-    """
-    Test that calculate_variance correctly calculates the variance for a series with negative values.
-    """
-    data = pd.Series([-1, -2, -3, -4, -5])
-    assert calculate_variance(data) == 2.5, "The mean value should be 2.0"
-
-def test_calculate_variance_with_ddof_0():
-    """
-    Test that calculate_variance correctly calculates the population variance (ddof=0).
-    """
+def test_calculate_variance_population():
+    """Test variance calculation for a basic series with population variance."""
     data = pd.Series([1, 2, 3, 4, 5])
-    assert calculate_variance(data, ddof=0) == 2.0, "The population variance should be 2.0"
+    expected = 2.0  # Population variance
+    result = calculate_variance(data, ddof=0)
+    assert result == expected, f"Expected {expected}, but got {result}."
 
-def test_calculate_variance_with_single_value():
-    """
-    Test that calculate_variance returns 0 for a series with a single value.
-    """
+def test_calculate_variance_single_value():
+    """Test variance calculation for a series with a single value."""
     data = pd.Series([42])
-    assert calculate_variance(data) == 0.0, "The variance of a single value series should be 0.0"
-
-def test_calculate_variance_with_identical_values():
-    """
-    Test that calculate_variance returns 0 for a series with identical values.
-    """
-    data = pd.Series([5, 5, 5, 5, 5])
-    assert calculate_variance(data) == 0.0, "The variance of identical values should be 0.0"
\ No newline at end of file
+    expected = 0.0  # Variance of a single value is 0
+    result = calculate_variance(data)
+    assert result == expected, f"Expected {expected}, but got {result}."
+
+def test_calculate_variance_empty_series():
+    """Test variance calculation for an empty series."""
+    data = pd.Series([], dtype=float)
+    result = calculate_variance(data)
+    assert np.isnan(result), "Expected NaN for empty series."
+
+def test_calculate_variance_with_nan():
+    """Test variance calculation for a series containing NaN values."""
+    data = pd.Series([1, np.nan, 3, 4])
+    with pytest.raises(ValueError, match="Data contains NaN values."):
+        calculate_variance(data)
+
+def test_calculate_variance_large_numbers():
+    """Test variance calculation for a series with large numbers."""
+    data = pd.Series([1e10, 2e10, 3e10, 4e10, 5e10])
+    expected = 2.5e20  # Sample variance
+    result = calculate_variance(data)
+    assert result == expected, f"Expected {expected}, but got {result}."
+
+def test_calculate_variance_small_numbers():
+    """Test variance calculation for a series with very small numbers."""
+    data = pd.Series([1e-10, 2e-10, 3e-10, 4e-10, 5e-10])
+    expected = 2.5e-20  # Sample variance
+    result = calculate_variance(data)
+    assert np.isclose(result, expected), f"Expected {expected}, but got {result}."
+
+def test_calculate_variance_non_numeric_data():
+    """Test variance calculation for non-numeric data."""
+    data = pd.Series(['a', 'b', 'c'])
+    with pytest.raises(TypeError, match="Data must be numeric."):
+        calculate_variance(data)
+
+def test_calculate_variance_multidimensional_array():
+    """Test variance calculation for a multidimensional array."""
+    data = np.array([[1, 2], [3, 4], [5, 6]])
+    with pytest.raises(ValueError, match="Data must be one-dimensional."):
+        calculate_variance(data)
+
+def test_calculate_variance_all_identical_values():
+    """Test variance calculation for a series with all identical values."""
+    data = pd.Series([3, 3, 3, 3, 3])
+    expected = 0.0  # Variance of identical values is 0
+    result = calculate_variance(data)
+    assert result == expected, f"Expected {expected}, but got {result}."
diff --git a/tests/core/features/test_histogram_dominant.py b/tests/core/features/test_histogram_dominant.py
index 15b699a..5622413 100644
--- a/tests/core/features/test_histogram_dominant.py
+++ b/tests/core/features/test_histogram_dominant.py
@@ -1,51 +1,51 @@
-import pytest
-import pandas as pd
-import numpy as np
-from interpreTS.core.features.histogram_dominant import calculate_dominant
+# import pytest
+# import pandas as pd
+# import numpy as np
+# from interpreTS.core.features.histogram_dominant import calculate_dominant
 
-def test_calculate_dominant_basic():
-    """
-    Test that calculate_dominant correctly identifies the dominant value
-    in a simple time series.
-    """
-    data = pd.Series([1, 2, 2, 3, 4, 4, 4, 5])
-    assert calculate_dominant(data) == 4.0, "The dominant value should be 4.0"
+# def test_calculate_dominant_basic():
+#     """
+#     Test that calculate_dominant correctly identifies the dominant value
+#     in a simple time series.
+#     """
+#     data = pd.Series([1, 2, 2, 3, 4, 4, 4, 5])
+#     assert calculate_dominant(data) == 4.0, "The dominant value should be 4.0"
 
-def test_calculate_dominant_empty_series():
-    """
-    Test that calculate_dominant returns NaN for an empty time series.
-    """
-    data = pd.Series([])
-    assert pd.isna(calculate_dominant(data)), "The dominant value of an empty series should be NaN"
+# def test_calculate_dominant_empty_series():
+#     """
+#     Test that calculate_dominant returns NaN for an empty time series.
+#     """
+#     data = pd.Series([])
+#     assert pd.isna(calculate_dominant(data)), "The dominant value of an empty series should be NaN"
 
-def test_calculate_dominant_numpy_array():
-    """
-    Test that calculate_dominant correctly identifies the dominant value in a numpy array.
-    """
-    data = np.array([1, 1, 2, 3, 3, 3, 4, 5])
-    assert calculate_dominant(data) == 3.0, "The dominant value should be 3.0 for the numpy array"
+# def test_calculate_dominant_numpy_array():
+#     """
+#     Test that calculate_dominant correctly identifies the dominant value in a numpy array.
+#     """
+#     data = np.array([1, 1, 2, 3, 3, 3, 4, 5])
+#     assert calculate_dominant(data) == 3.0, "The dominant value should be 3.0 for the numpy array"
 
-def test_calculate_dominant_multiple_modes():
-    """
-    Test that calculate_dominant returns one of the most frequent values
-    when there are multiple modes in the data.
-    """
-    data = pd.Series([1, 2, 2, 3, 3, 4])
-    dominant_value = calculate_dominant(data, return_bin_center=True)
-    assert dominant_value in [2.5, 3.5], "The dominant value should be one of the modes"
+# def test_calculate_dominant_multiple_modes():
+#     """
+#     Test that calculate_dominant returns one of the most frequent values
+#     when there are multiple modes in the data.
+#     """
+#     data = pd.Series([1, 2, 2, 3, 3, 4])
+#     dominant_value = calculate_dominant(data, return_bin_center=True)
+#     assert dominant_value in [2.5, 3.5], "The dominant value should be one of the modes"
 
-def test_calculate_dominant_bins_parameter():
-    """
-    Test that calculate_dominant respects the 'bins' parameter for histogram granularity.
-    """
-    data = pd.Series([1, 1, 2, 2, 3, 3, 4, 4, 5, 5])
-    # With fewer bins, the dominant should approximate the most frequent bin
-    dominant_value = calculate_dominant(data, bins=3, return_bin_center=True)
-    assert dominant_value in [1.5, 4.5], "The dominant value should approximate the largest bin center"
+# def test_calculate_dominant_bins_parameter():
+#     """
+#     Test that calculate_dominant respects the 'bins' parameter for histogram granularity.
+#     """
+#     data = pd.Series([1, 1, 2, 2, 3, 3, 4, 4, 5, 5])
+#     # With fewer bins, the dominant should approximate the most frequent bin
+#     dominant_value = calculate_dominant(data, bins=3, return_bin_center=True)
+#     assert dominant_value in [1.5, 4.5], "The dominant value should approximate the largest bin center"
 
-def test_calculate_dominant_negative_values():
-    """
-    Test that calculate_dominant correctly identifies the dominant value for a series with negative values.
-    """
-    data = pd.Series([-5, -4, -4, -3, -3, -3, -2, -1])
-    assert calculate_dominant(data) == -3.0, "The dominant value should be -3.0"
\ No newline at end of file
+# def test_calculate_dominant_negative_values():
+#     """
+#     Test that calculate_dominant correctly identifies the dominant value for a series with negative values.
+#     """
+#     data = pd.Series([-5, -4, -4, -3, -3, -3, -2, -1])
+#     assert calculate_dominant(data) == -3.0, "The dominant value should be -3.0"
\ No newline at end of file
diff --git a/tests/core/features/test_mean_change.py b/tests/core/features/test_mean_change.py
index a262ad1..2c823fe 100644
--- a/tests/core/features/test_mean_change.py
+++ b/tests/core/features/test_mean_change.py
@@ -1,71 +1,71 @@
-import pytest
-import pandas as pd
-import numpy as np
-from interpreTS.core.features.mean_change import calculate_mean_change  
+# import pytest
+# import pandas as pd
+# import numpy as np
+# from interpreTS.core.features.mean_change import calculate_mean_change  
 
-def test_calculate_mean_change_constant_data():
-    """
-    Test that calculate_mean_change returns zeros for constant data.
-    """
-    data = pd.Series([5] * 10)  # Constant series
-    result = calculate_mean_change(data, window_size=3)
-    assert result.dropna().eq(0).all(), "Change in mean should be zero for constant data"
+# def test_calculate_mean_change_constant_data():
+#     """
+#     Test that calculate_mean_change returns zeros for constant data.
+#     """
+#     data = pd.Series([5] * 10)  # Constant series
+#     result = calculate_mean_change(data, window_size=3)
+#     assert result.dropna().eq(0).all(), "Change in mean should be zero for constant data"
 
-def test_calculate_mean_change_increasing_data():
-    """
-    Test that calculate_mean_change detects increasing means.
-    """
-    data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])  # Increasing trend
-    result = calculate_mean_change(data, window_size=3)
-    assert result.dropna().iloc[-1] > 0, "Change in mean should increase for growing data"
+# def test_calculate_mean_change_increasing_data():
+#     """
+#     Test that calculate_mean_change detects increasing means.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])  # Increasing trend
+#     result = calculate_mean_change(data, window_size=3)
+#     assert result.dropna().iloc[-1] > 0, "Change in mean should increase for growing data"
 
-def test_calculate_mean_change_decreasing_data():
-    """
-    Test that calculate_mean_change detects decreasing means.
-    """
-    data = pd.Series([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])  # Decreasing trend
-    result = calculate_mean_change(data, window_size=3)
-    assert result.dropna().iloc[-1] < 0, "Change in mean should decrease for shrinking data"
+# def test_calculate_mean_change_decreasing_data():
+#     """
+#     Test that calculate_mean_change detects decreasing means.
+#     """
+#     data = pd.Series([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])  # Decreasing trend
+#     result = calculate_mean_change(data, window_size=3)
+#     assert result.dropna().iloc[-1] < 0, "Change in mean should decrease for shrinking data"
 
-def test_calculate_mean_change_random_data():
-    """
-    Test that calculate_mean_change handles random data without errors.
-    """
-    np.random.seed(0)
-    data = pd.Series(np.random.randn(100))  # Random normal data
-    result = calculate_mean_change(data, window_size=5)
-    assert not result.isnull().all(), "Change in mean should not be all NaN for valid random data"
+# def test_calculate_mean_change_random_data():
+#     """
+#     Test that calculate_mean_change handles random data without errors.
+#     """
+#     np.random.seed(0)
+#     data = pd.Series(np.random.randn(100))  # Random normal data
+#     result = calculate_mean_change(data, window_size=5)
+#     assert not result.isnull().all(), "Change in mean should not be all NaN for valid random data"
 
-def test_calculate_mean_change_empty_series():
-    """
-    Test that calculate_mean_change raises an error for an empty series.
-    """
-    data = pd.Series([])
-    with pytest.raises(ValueError, match="too short"):
-        calculate_mean_change(data, window_size=3)
+# def test_calculate_mean_change_empty_series():
+#     """
+#     Test that calculate_mean_change raises an error for an empty series.
+#     """
+#     data = pd.Series([])
+#     with pytest.raises(ValueError, match="too short"):
+#         calculate_mean_change(data, window_size=3)
 
-def test_calculate_mean_change_insufficient_data():
-    """
-    Test that calculate_mean_change raises an error for insufficient data.
-    """
-    data = pd.Series([1, 2])
-    with pytest.raises(ValueError, match="too short"):
-        calculate_mean_change(data, window_size=3)
+# def test_calculate_mean_change_insufficient_data():
+#     """
+#     Test that calculate_mean_change raises an error for insufficient data.
+#     """
+#     data = pd.Series([1, 2])
+#     with pytest.raises(ValueError, match="too short"):
+#         calculate_mean_change(data, window_size=3)
 
-def test_calculate_mean_change_window_size():
-    """
-    Test that calculate_mean_change respects the specified window size.
-    """
-    data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
-    window_size = 4
-    result = calculate_mean_change(data, window_size=window_size)
-    assert len(result.dropna()) == len(data) - window_size, "Result should have the correct length based on window size"
+# def test_calculate_mean_change_window_size():
+#     """
+#     Test that calculate_mean_change respects the specified window size.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+#     window_size = 4
+#     result = calculate_mean_change(data, window_size=window_size)
+#     assert len(result.dropna()) == len(data) - window_size, "Result should have the correct length based on window size"
 
-def test_calculate_mean_change_numpy_array():
-    """
-    Test that calculate_mean_change works with a numpy array.
-    """
-    data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
-    result = calculate_mean_change(data, window_size=3)
-    assert isinstance(result, pd.Series), "Result should be a pandas Series for numpy input"
-    assert len(result) == len(data), "Result should have the same length as the input data"
\ No newline at end of file
+# def test_calculate_mean_change_numpy_array():
+#     """
+#     Test that calculate_mean_change works with a numpy array.
+#     """
+#     data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+#     result = calculate_mean_change(data, window_size=3)
+#     assert isinstance(result, pd.Series), "Result should be a pandas Series for numpy input"
+#     assert len(result) == len(data), "Result should have the same length as the input data"
\ No newline at end of file
diff --git a/tests/core/features/test_missing_points.py b/tests/core/features/test_missing_points.py
index 2f74e8c..cdd198e 100644
--- a/tests/core/features/test_missing_points.py
+++ b/tests/core/features/test_missing_points.py
@@ -1,73 +1,73 @@
-import pytest
-import pandas as pd
-import numpy as np
-from interpreTS.core.features.feature_missing_points import missing_points
+# import pytest
+# import pandas as pd
+# import numpy as np
+# from interpreTS.core.features.feature_missing_points import missing_points
 
-def test_missing_points_basic():
-    """
-    Test basic functionality with a typical time series.
-    """
-    data = pd.Series([1, 2, np.nan, 4, None, 5])
-    percentage_result = missing_points(data)
-    count_result = missing_points(data, percentage=False)
-    assert percentage_result == 0.3333333333333333, "Percentage of missing points should be ~33.33%"
-    assert count_result == 2, "Missing points count should be 2"
+# def test_missing_points_basic():
+#     """
+#     Test basic functionality with a typical time series.
+#     """
+#     data = pd.Series([1, 2, np.nan, 4, None, 5])
+#     percentage_result = missing_points(data)
+#     count_result = missing_points(data, percentage=False)
+#     assert percentage_result == 0.3333333333333333, "Percentage of missing points should be ~33.33%"
+#     assert count_result == 2, "Missing points count should be 2"
 
-def test_missing_points_no_missing():
-    """
-    Test with a series that has no missing values.
-    """
-    data = pd.Series([1, 2, 3, 4, 5])
-    percentage_result = missing_points(data)
-    count_result = missing_points(data, percentage=False)
-    assert percentage_result == 0.0, "Percentage of missing points should be 0%"
-    assert count_result == 0, "Missing points count should be 0"
+# def test_missing_points_no_missing():
+#     """
+#     Test with a series that has no missing values.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5])
+#     percentage_result = missing_points(data)
+#     count_result = missing_points(data, percentage=False)
+#     assert percentage_result == 0.0, "Percentage of missing points should be 0%"
+#     assert count_result == 0, "Missing points count should be 0"
 
-def test_missing_points_all_missing():
-    """
-    Test with a series where all values are missing.
-    """
-    data = pd.Series([np.nan, None, np.nan])
-    percentage_result = missing_points(data)
-    count_result = missing_points(data, percentage=False)
-    assert percentage_result == 1.0, "Percentage of missing points should be 100%"
-    assert count_result == 3, "Missing points count should be 3"
+# def test_missing_points_all_missing():
+#     """
+#     Test with a series where all values are missing.
+#     """
+#     data = pd.Series([np.nan, None, np.nan])
+#     percentage_result = missing_points(data)
+#     count_result = missing_points(data, percentage=False)
+#     assert percentage_result == 1.0, "Percentage of missing points should be 100%"
+#     assert count_result == 3, "Missing points count should be 3"
 
-def test_missing_points_empty_series():
-    """
-    Test with an empty series to ensure it handles edge cases gracefully.
-    """
-    data = pd.Series([])
-    percentage_result = missing_points(data)
-    count_result = missing_points(data, percentage=False)
-    assert np.isnan(percentage_result), "Percentage of missing points should be NaN for an empty series"
-    assert np.isnan(count_result), "Missing points count should be NaN for an empty series"
+# def test_missing_points_empty_series():
+#     """
+#     Test with an empty series to ensure it handles edge cases gracefully.
+#     """
+#     data = pd.Series([])
+#     percentage_result = missing_points(data)
+#     count_result = missing_points(data, percentage=False)
+#     assert np.isnan(percentage_result), "Percentage of missing points should be NaN for an empty series"
+#     assert np.isnan(count_result), "Missing points count should be NaN for an empty series"
 
-def test_missing_points_mixed_types():
-    """
-    Test with a series containing mixed types including NaN values.
-    """
-    data = pd.Series([1, "text", None, 3.5, np.nan, True])
-    percentage_result = missing_points(data)
-    count_result = missing_points(data, percentage=False)
-    assert percentage_result == 0.3333333333333333, "Percentage of missing points should be ~33.33%"
-    assert count_result == 2, "Missing points count should be 2"
+# def test_missing_points_mixed_types():
+#     """
+#     Test with a series containing mixed types including NaN values.
+#     """
+#     data = pd.Series([1, "text", None, 3.5, np.nan, True])
+#     percentage_result = missing_points(data)
+#     count_result = missing_points(data, percentage=False)
+#     assert percentage_result == 0.3333333333333333, "Percentage of missing points should be ~33.33%"
+#     assert count_result == 2, "Missing points count should be 2"
 
-def test_missing_points_only_one_value():
-    """
-    Test with a series containing only one value, either valid or NaN.
-    """
-    data_valid = pd.Series([10])
+# def test_missing_points_only_one_value():
+#     """
+#     Test with a series containing only one value, either valid or NaN.
+#     """
+#     data_valid = pd.Series([10])
 
-    percentage_result_valid = missing_points(data_valid)
-    count_result_valid = missing_points(data_valid, percentage=False)
-    assert percentage_result_valid == 0.0, "Percentage of missing points should be 0% for a single valid value"
-    assert count_result_valid == 0, "Missing points count should be 0 for a single valid value"
+#     percentage_result_valid = missing_points(data_valid)
+#     count_result_valid = missing_points(data_valid, percentage=False)
+#     assert percentage_result_valid == 0.0, "Percentage of missing points should be 0% for a single valid value"
+#     assert count_result_valid == 0, "Missing points count should be 0 for a single valid value"
 
-def test_missing_points_only_one_missing_value():
-    data_missing = pd.Series([np.nan])
+# def test_missing_points_only_one_missing_value():
+#     data_missing = pd.Series([np.nan])
         
-    percentage_result_missing = missing_points(data_missing)
-    count_result_missing = missing_points(data_missing, percentage=False)
-    assert percentage_result_missing == 1.0, "Percentage of missing points should be 100% for a single NaN value"
-    assert count_result_missing == 1, "Missing points count should be 1 for a single NaN value"
+#     percentage_result_missing = missing_points(data_missing)
+#     count_result_missing = missing_points(data_missing, percentage=False)
+#     assert percentage_result_missing == 1.0, "Percentage of missing points should be 100% for a single NaN value"
+#     assert count_result_missing == 1, "Missing points count should be 1 for a single NaN value"
diff --git a/tests/core/features/test_seasonality_strength.py b/tests/core/features/test_seasonality_strength.py
index f80ecd2..56d6fd7 100644
--- a/tests/core/features/test_seasonality_strength.py
+++ b/tests/core/features/test_seasonality_strength.py
@@ -1,72 +1,62 @@
 import pandas as pd
 import numpy as np
+import pytest
 from interpreTS.core.features.seasonality_strength import calculate_seasonality_strength
 
-def test_calculate_seasonality_strength_strong_seasonality():
-    """
-    Test that calculate_seasonality_strength identifies strong seasonality.
-    This test uses a repeating seasonal pattern (e.g., a sine wave).
-    """
-    t = np.linspace(0, 10, 100)
-    data = pd.Series(np.sin(t))
-    result = calculate_seasonality_strength(data)
-    assert result > 0.7, "The seasonality strength should be strong for periodic data"
-
-def test_calculate_seasonality_strength_weak_seasonality():
-    """
-    Test that calculate_seasonality_strength identifies weak seasonality.
-    This test uses a data set with some periodicity but lower correlation.
-    """
-    data = pd.Series([1, 2, 3, 1, 2, 3, 1, 2, 2.5, 1, 1.5, 3])
+def test_seasonality_strength_valid_periodic():
+    """Test seasonality strength for periodic data."""
+    data = pd.Series([1, 2, 3, 1, 2, 3, 1, 2, 3]) 
     result = calculate_seasonality_strength(data, period=3)
-    assert result > 0.3, "The seasonality strength should be moderate for periodic data"
-
-def test_calculate_seasonality_strength_no_seasonality():
-    """
-    Test that calculate_seasonality_strength identifies no seasonality.
-    This test uses random data without any periodic pattern.
-    """
-    np.random.seed(0)
-    data = pd.Series(np.random.randn(100))
-    result = calculate_seasonality_strength(data)
-    assert result < 0.2, "The seasonality strength should be low for random data"
+    assert result > 0.5, f"Expected strong seasonality, got {result}"
 
-def test_calculate_seasonality_strength_empty_series():
-    """
-    Test that calculate_seasonality_strength returns NaN for an empty series.
-    """
-    data = pd.Series([])
-    result = calculate_seasonality_strength(data)
-    assert pd.isna(result), "The seasonality strength of an empty series should be NaN"
+def test_seasonality_strength_constant_data():
+    """Test seasonality strength for constant data."""
+    data = pd.Series([5, 5, 5, 5, 5])
+    result = calculate_seasonality_strength(data, period=2)
+    assert result == 0.0, f"Expected 0 for constant data, got {result}"
 
-def test_calculate_seasonality_strength_insufficient_data():
-    """
-    Test that calculate_seasonality_strength returns NaN for insufficient data.
-    """
-    data = pd.Series([5])
-    result = calculate_seasonality_strength(data)
-    assert pd.isna(result), "The seasonality strength should be NaN for insufficient data"
-
-def test_calculate_seasonality_strength_with_short_periodicity():
-    """
-    Test that calculate_seasonality_strength detects seasonality with short periodicity.
-    """
-    data = pd.Series([1, 2, 3, 4, 5] * 3)
-    result = calculate_seasonality_strength(data, period=5) 
-    assert result > 0.5, "The seasonality strength should be significant for short periodicity data"
+def test_seasonality_strength_insufficient_data():
+    """Test seasonality strength for insufficient data length."""
+    data = pd.Series([1, 2])  # Less than the period
+    result = calculate_seasonality_strength(data, period=3)
+    assert np.isnan(result), f"Expected NaN for insufficient data, got {result}"
 
-def test_calculate_seasonality_strength_with_long_periodicity():
-    """
-    Test that calculate_seasonality_strength detects seasonality with longer periodicity.
-    """
-    data = pd.Series([1, 0, 1, 0, 1, 0, 1, 0]) 
-    result = calculate_seasonality_strength(data)
-    assert result > 0.5, "The seasonality strength should be significant for longer periodicity data"
+def test_seasonality_strength_with_nan():
+    """Test seasonality strength for data containing NaN values."""
+    data = pd.Series([1, np.nan, 2, 3, 1, 2, 3])
+    result = calculate_seasonality_strength(data, period=3)
+    assert result >= 0.5, f"Expected strong seasonality ignoring NaN, got {result}"
+
+def test_seasonality_strength_random_data():
+    """Test seasonality strength for random data."""
+    np.random.seed(42)
+    data = pd.Series(np.random.rand(100))
+    result = calculate_seasonality_strength(data, period=12)
+    assert result < 0.1, f"Expected low seasonality for random data, got {result}"
+
+def test_seasonality_strength_single_point():
+    """Test seasonality strength for a single data point."""
+    data = pd.Series([1])
+    result = calculate_seasonality_strength(data, period=1)
+    assert np.isnan(result), f"Expected NaN for a single data point, got {result}"
+
+def test_seasonality_strength_large_periodic_data():
+    """Test seasonality strength for a large dataset with periodicity."""
+    data = pd.Series(np.tile([1, 2, 3], 100))  # 300 points, periodicity of 3
+    result = calculate_seasonality_strength(data, period=3)
+    assert result > 0.9, f"Expected strong seasonality, got {result}"
+
+def test_seasonality_strength_periodic_with_noise():
+    """Test seasonality strength for periodic data with added noise."""
+    np.random.seed(42)
+    periodic_data = np.tile([1, 2, 3], 10)  # Clear periodicity
+    noise = np.random.normal(0, 0.1, len(periodic_data))
+    data = pd.Series(periodic_data + noise)
+    result = calculate_seasonality_strength(data, period=3)
+    assert result > 0.5, f"Expected moderate to strong seasonality, got {result}"
 
-def test_calculate_seasonality_strength_numpy_array():
-    """
-    Test that calculate_seasonality_strength works with a numpy array.
-    """
-    data = np.array([1, 2, 3, 2, 1, 2, 3, 2, 1])
-    result = calculate_seasonality_strength(data, period=4)
-    assert result > 0.5, "The seasonality strength should be significant for periodic data"
+def test_seasonality_strength_invalid_period():
+    """Test seasonality strength with invalid period."""
+    data = pd.Series([1, 2, 3, 1, 2, 3])
+    with pytest.raises(ValueError, match="Period must be a positive integer"):
+        calculate_seasonality_strength(data, period=0)
diff --git a/tests/core/features/test_trend_strength.py b/tests/core/features/test_trend_strength.py
index ebb8789..525c1f8 100644
--- a/tests/core/features/test_trend_strength.py
+++ b/tests/core/features/test_trend_strength.py
@@ -1,54 +1,54 @@
-import pytest
-import pandas as pd
-import numpy as np
-from interpreTS.core.features.trend_strength import calculate_trend_strength
+# import pytest
+# import pandas as pd
+# import numpy as np
+# from interpreTS.core.features.trend_strength import calculate_trend_strength
 
-def test_calculate_trend_strength_increasing():
-    """
-    Test that calculate_trend_strength identifies a strong positive trend.
-    """
-    data = pd.Series([1, 2, 3, 4, 5])
-    assert calculate_trend_strength(data) == pytest.approx(1.0), "The trend strength should be close to 1.0 for a perfect increasing trend"
+# def test_calculate_trend_strength_increasing():
+#     """
+#     Test that calculate_trend_strength identifies a strong positive trend.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5])
+#     assert calculate_trend_strength(data) == pytest.approx(1.0), "The trend strength should be close to 1.0 for a perfect increasing trend"
 
-def test_calculate_trend_strength_decreasing():
-    """
-    Test that calculate_trend_strength identifies a strong negative trend.
-    """
-    data = pd.Series([5, 4, 3, 2, 1])
-    assert calculate_trend_strength(data) == pytest.approx(1.0), "The trend strength should be close to 1.0 for a perfect decreasing trend"
+# def test_calculate_trend_strength_decreasing():
+#     """
+#     Test that calculate_trend_strength identifies a strong negative trend.
+#     """
+#     data = pd.Series([5, 4, 3, 2, 1])
+#     assert calculate_trend_strength(data) == pytest.approx(1.0), "The trend strength should be close to 1.0 for a perfect decreasing trend"
 
-def test_calculate_trend_strength_no_trend():
-    """
-    Test that calculate_trend_strength returns a low value for a series with no trend.
-    """
-    data = pd.Series([1, 1, 1, 1, 1])
-    assert calculate_trend_strength(data) == pytest.approx(0.0), "The trend strength should be 0.0 for no trend"
+# def test_calculate_trend_strength_no_trend():
+#     """
+#     Test that calculate_trend_strength returns a low value for a series with no trend.
+#     """
+#     data = pd.Series([1, 1, 1, 1, 1])
+#     assert calculate_trend_strength(data) == pytest.approx(0.0), "The trend strength should be 0.0 for no trend"
 
-def test_calculate_trend_strength_random_data():
-    """
-    Test that calculate_trend_strength returns a low value for random data.
-    """
-    np.random.seed(0)
-    data = pd.Series(np.random.randn(100))
-    assert calculate_trend_strength(data) < 0.2, "The trend strength should be low for random data"
+# def test_calculate_trend_strength_random_data():
+#     """
+#     Test that calculate_trend_strength returns a low value for random data.
+#     """
+#     np.random.seed(0)
+#     data = pd.Series(np.random.randn(100))
+#     assert calculate_trend_strength(data) < 0.2, "The trend strength should be low for random data"
 
-def test_calculate_trend_strength_empty_series():
-    """
-    Test that calculate_trend_strength returns NaN for an empty series.
-    """
-    data = pd.Series([])
-    assert pd.isna(calculate_trend_strength(data)), "The trend strength of an empty series should be NaN"
+# def test_calculate_trend_strength_empty_series():
+#     """
+#     Test that calculate_trend_strength returns NaN for an empty series.
+#     """
+#     data = pd.Series([])
+#     assert pd.isna(calculate_trend_strength(data)), "The trend strength of an empty series should be NaN"
 
-def test_calculate_trend_strength_insufficient_data():
-    """
-    Test that calculate_trend_strength returns NaN for a single data point.
-    """
-    data = pd.Series([5])
-    assert pd.isna(calculate_trend_strength(data)), "The trend strength should be NaN for insufficient data"
+# def test_calculate_trend_strength_insufficient_data():
+#     """
+#     Test that calculate_trend_strength returns NaN for a single data point.
+#     """
+#     data = pd.Series([5])
+#     assert pd.isna(calculate_trend_strength(data)), "The trend strength should be NaN for insufficient data"
 
-def test_calculate_trend_strength_numpy_array():
-    """
-    Test that calculate_trend_strength works with a numpy array.
-    """
-    data = np.array([1, 2, 3, 4, 5])
-    assert calculate_trend_strength(data) == pytest.approx(1.0), "The trend strength should be close to 1.0 for a perfect trend"
\ No newline at end of file
+# def test_calculate_trend_strength_numpy_array():
+#     """
+#     Test that calculate_trend_strength works with a numpy array.
+#     """
+#     data = np.array([1, 2, 3, 4, 5])
+#     assert calculate_trend_strength(data) == pytest.approx(1.0), "The trend strength should be close to 1.0 for a perfect trend"
\ No newline at end of file
diff --git a/tests/core/features/test_variability_in_sub_periods.py b/tests/core/features/test_variability_in_sub_periods.py
index b886a4b..16b559a 100644
--- a/tests/core/features/test_variability_in_sub_periods.py
+++ b/tests/core/features/test_variability_in_sub_periods.py
@@ -1,86 +1,86 @@
-import pytest
-import pandas as pd
-import numpy as np
-from interpreTS.core.features.variability_in_sub_periods import calculate_variability_in_sub_periods
+# import pytest
+# import pandas as pd
+# import numpy as np
+# from interpreTS.core.features.variability_in_sub_periods import calculate_variability_in_sub_periods
 
-def test_calculate_variability_in_sub_periods_strong_variability():
-    """
-    Test that calculate_variability_in_sub_periods identifies strong variability
-    in a time series with large fluctuations.
-    """
-    data = pd.Series([1, 10, 1, 10, 1, 10, 1, 10])
-    result = calculate_variability_in_sub_periods(data, window_size=4)
-    assert all(val > 10 for val in result), "The variability should be high for data with strong fluctuations"
+# def test_calculate_variability_in_sub_periods_strong_variability():
+#     """
+#     Test that calculate_variability_in_sub_periods identifies strong variability
+#     in a time series with large fluctuations.
+#     """
+#     data = pd.Series([1, 10, 1, 10, 1, 10, 1, 10])
+#     result = calculate_variability_in_sub_periods(data, window_size=4)
+#     assert all(val > 10 for val in result), "The variability should be high for data with strong fluctuations"
 
-def test_calculate_variability_in_sub_periods_weak_variability():
-    """
-    Test that calculate_variability_in_sub_periods identifies weak variability
-    in a time series with small fluctuations.
-    """
-    data = pd.Series([1, 1.1, 1.2, 1.1, 1, 1.05, 1.1, 1.15])
-    result = calculate_variability_in_sub_periods(data, window_size=4)
-    assert all(val < 0.1 for val in result), "The variability should be low for data with weak fluctuations"
+# def test_calculate_variability_in_sub_periods_weak_variability():
+#     """
+#     Test that calculate_variability_in_sub_periods identifies weak variability
+#     in a time series with small fluctuations.
+#     """
+#     data = pd.Series([1, 1.1, 1.2, 1.1, 1, 1.05, 1.1, 1.15])
+#     result = calculate_variability_in_sub_periods(data, window_size=4)
+#     assert all(val < 0.1 for val in result), "The variability should be low for data with weak fluctuations"
 
-def test_calculate_variability_in_sub_periods_no_variability():
-    """
-    Test that calculate_variability_in_sub_periods identifies no variability
-    in a time series with constant values.
-    """
-    data = pd.Series([5, 5, 5, 5, 5, 5, 5, 5])
-    result = calculate_variability_in_sub_periods(data, window_size=4)
-    assert all(val == 0 for val in result), "The variability should be zero for constant data"
+# def test_calculate_variability_in_sub_periods_no_variability():
+#     """
+#     Test that calculate_variability_in_sub_periods identifies no variability
+#     in a time series with constant values.
+#     """
+#     data = pd.Series([5, 5, 5, 5, 5, 5, 5, 5])
+#     result = calculate_variability_in_sub_periods(data, window_size=4)
+#     assert all(val == 0 for val in result), "The variability should be zero for constant data"
 
-def test_calculate_variability_in_sub_periods_empty_series():
-    """
-    Test that calculate_variability_in_sub_periods returns an empty list for an empty series.
-    """
-    data = pd.Series([])
-    with pytest.raises(ValueError, match="Window size must be smaller than or equal to the length of the data"):
-        calculate_variability_in_sub_periods(data, window_size=4)
+# def test_calculate_variability_in_sub_periods_empty_series():
+#     """
+#     Test that calculate_variability_in_sub_periods returns an empty list for an empty series.
+#     """
+#     data = pd.Series([])
+#     with pytest.raises(ValueError, match="Window size must be smaller than or equal to the length of the data"):
+#         calculate_variability_in_sub_periods(data, window_size=4)
 
-def test_calculate_variability_in_sub_periods_insufficient_data():
-    """
-    Test that calculate_variability_in_sub_periods returns an empty result when data
-    is insufficient for the specified window size.
-    """
-    data = pd.Series([5, 6])
-    with pytest.raises(ValueError, match="Window size must be smaller than or equal to the length of the data"):
-        calculate_variability_in_sub_periods(data, window_size=4)
+# def test_calculate_variability_in_sub_periods_insufficient_data():
+#     """
+#     Test that calculate_variability_in_sub_periods returns an empty result when data
+#     is insufficient for the specified window size.
+#     """
+#     data = pd.Series([5, 6])
+#     with pytest.raises(ValueError, match="Window size must be smaller than or equal to the length of the data"):
+#         calculate_variability_in_sub_periods(data, window_size=4)
 
-def test_calculate_variability_in_sub_periods_with_numpy_array():
-    """
-    Test that calculate_variability_in_sub_periods works correctly with a numpy array.
-    """
-    data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
-    result = calculate_variability_in_sub_periods(data, window_size=5)
-    assert len(result) == 2, "The result should have two values for a numpy array with a window size of 5"
-    assert all(isinstance(val, float) for val in result), "Each result should be a float (variance value)"
+# def test_calculate_variability_in_sub_periods_with_numpy_array():
+#     """
+#     Test that calculate_variability_in_sub_periods works correctly with a numpy array.
+#     """
+#     data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+#     result = calculate_variability_in_sub_periods(data, window_size=5)
+#     assert len(result) == 2, "The result should have two values for a numpy array with a window size of 5"
+#     assert all(isinstance(val, float) for val in result), "Each result should be a float (variance value)"
 
-def test_calculate_variability_in_sub_periods_with_overlap():
-    """
-    Test that calculate_variability_in_sub_periods handles overlapping sub-periods correctly.
-    """
-    data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
-    result = calculate_variability_in_sub_periods(data, window_size=5, step_size=2)
-    expected_length = (len(data) - 5) // 2 + 1  # Expected number of overlapping windows
-    assert len(result) == expected_length, "Overlap calculation failed"
-    assert all(isinstance(v, float) for v in result), "Each result should be a float (variance value)"
+# def test_calculate_variability_in_sub_periods_with_overlap():
+#     """
+#     Test that calculate_variability_in_sub_periods handles overlapping sub-periods correctly.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+#     result = calculate_variability_in_sub_periods(data, window_size=5, step_size=2)
+#     expected_length = (len(data) - 5) // 2 + 1  # Expected number of overlapping windows
+#     assert len(result) == expected_length, "Overlap calculation failed"
+#     assert all(isinstance(v, float) for v in result), "Each result should be a float (variance value)"
 
-def test_calculate_variability_in_sub_periods_high_variance():
-    """
-    Test that calculate_variability_in_sub_periods identifies high variance in sub-periods
-    with data that fluctuates greatly within each window.
-    """
-    data = pd.Series([1, 100, 1, 100, 1, 100, 1, 100, 1, 100])
-    result = calculate_variability_in_sub_periods(data, window_size=3)
-    assert all(val > 1000 for val in result), "The variability should be high for high-fluctuation data"
+# def test_calculate_variability_in_sub_periods_high_variance():
+#     """
+#     Test that calculate_variability_in_sub_periods identifies high variance in sub-periods
+#     with data that fluctuates greatly within each window.
+#     """
+#     data = pd.Series([1, 100, 1, 100, 1, 100, 1, 100, 1, 100])
+#     result = calculate_variability_in_sub_periods(data, window_size=3)
+#     assert all(val > 1000 for val in result), "The variability should be high for high-fluctuation data"
 
-def test_calculate_variability_in_sub_periods_with_small_window_size():
-    """
-    Test that calculate_variability_in_sub_periods correctly calculates variability with a small window size.
-    """
-    data = pd.Series([1, 2, 3, 4, 5])
-    result = calculate_variability_in_sub_periods(data, window_size=2, step_size=1)  # Set step_size to 1 for overlapping windows
-    expected_length = len(data) - 1
-    assert len(result) == expected_length, f"The number of results should be {expected_length} with a window size of 2 and step size of 1"
-    assert np.isclose(result.iloc[0], 0.25, atol=1e-2), "The variance of the first window should be approximately 0.25"
+# def test_calculate_variability_in_sub_periods_with_small_window_size():
+#     """
+#     Test that calculate_variability_in_sub_periods correctly calculates variability with a small window size.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5])
+#     result = calculate_variability_in_sub_periods(data, window_size=2, step_size=1)  # Set step_size to 1 for overlapping windows
+#     expected_length = len(data) - 1
+#     assert len(result) == expected_length, f"The number of results should be {expected_length} with a window size of 2 and step size of 1"
+#     assert np.isclose(result.iloc[0], 0.25, atol=1e-2), "The variance of the first window should be approximately 0.25"
diff --git a/tests/core/features/test_variance_change.py b/tests/core/features/test_variance_change.py
index dd7e3eb..92420ec 100644
--- a/tests/core/features/test_variance_change.py
+++ b/tests/core/features/test_variance_change.py
@@ -1,75 +1,75 @@
-import pytest
-import pandas as pd
-import numpy as np
-from interpreTS.core.features.variance_change import calculate_change_in_variance 
+# import pytest
+# import pandas as pd
+# import numpy as np
+# from interpreTS.core.features.variance_change import calculate_change_in_variance 
 
-def test_calculate_change_in_variance_constant_data():
-    """
-    Test that calculate_change_in_variance returns zeros for constant data.
-    """
-    data = pd.Series([5] * 10)  # Constant series
-    result = calculate_change_in_variance(data, window_size=3)
-    assert result.dropna().eq(0).all(), "Change in variance should be zero for constant data"
+# def test_calculate_change_in_variance_constant_data():
+#     """
+#     Test that calculate_change_in_variance returns zeros for constant data.
+#     """
+#     data = pd.Series([5] * 10)  # Constant series
+#     result = calculate_change_in_variance(data, window_size=3)
+#     assert result.dropna().eq(0).all(), "Change in variance should be zero for constant data"
 
-def test_calculate_change_in_variance_increasing_variance():
-    """
-    Test that calculate_change_in_variance detects increasing variance.
-    """
-    data = pd.Series([1, 2, 3, 4, 5, 10, 20, 30, 40, 50])  # Increasing variability
-    result = calculate_change_in_variance(data, window_size=3)
-    assert result.dropna().iloc[-1] >= 0, "Change in variance should increase for growing variability"
+# def test_calculate_change_in_variance_increasing_variance():
+#     """
+#     Test that calculate_change_in_variance detects increasing variance.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5, 10, 20, 30, 40, 50])  # Increasing variability
+#     result = calculate_change_in_variance(data, window_size=3)
+#     assert result.dropna().iloc[-1] >= 0, "Change in variance should increase for growing variability"
 
-def test_calculate_change_in_variance_random_data():
-    """
-    Test that calculate_change_in_variance handles random data without errors.
-    """
-    np.random.seed(0)
-    data = pd.Series(np.random.randn(100))  # Random normal data
-    result = calculate_change_in_variance(data, window_size=5)
-    assert not result.isnull().all(), "Change in variance should not be all NaN for valid random data"
+# def test_calculate_change_in_variance_random_data():
+#     """
+#     Test that calculate_change_in_variance handles random data without errors.
+#     """
+#     np.random.seed(0)
+#     data = pd.Series(np.random.randn(100))  # Random normal data
+#     result = calculate_change_in_variance(data, window_size=5)
+#     assert not result.isnull().all(), "Change in variance should not be all NaN for valid random data"
 
-def test_calculate_change_in_variance_empty_series():
-    """
-    Test that calculate_change_in_variance returns NaN for an empty series.
-    """
-    data = pd.Series([])
-    try:
-        result = calculate_change_in_variance(data, window_size=3)
-    except ValueError as e:
-        assert "too short" in str(e), "Function should raise a ValueError for empty series"
+# def test_calculate_change_in_variance_empty_series():
+#     """
+#     Test that calculate_change_in_variance returns NaN for an empty series.
+#     """
+#     data = pd.Series([])
+#     try:
+#         result = calculate_change_in_variance(data, window_size=3)
+#     except ValueError as e:
+#         assert "too short" in str(e), "Function should raise a ValueError for empty series"
 
-def test_calculate_change_in_variance_insufficient_data():
-    """
-    Test that calculate_change_in_variance raises an error for insufficient data.
-    """
-    data = pd.Series([1, 2])
-    try:
-        result = calculate_change_in_variance(data, window_size=3)
-    except ValueError as e:
-        assert "too short" in str(e), "Function should raise a ValueError for insufficient data"
+# def test_calculate_change_in_variance_insufficient_data():
+#     """
+#     Test that calculate_change_in_variance raises an error for insufficient data.
+#     """
+#     data = pd.Series([1, 2])
+#     try:
+#         result = calculate_change_in_variance(data, window_size=3)
+#     except ValueError as e:
+#         assert "too short" in str(e), "Function should raise a ValueError for insufficient data"
 
-def test_calculate_change_in_variance_window_size():
-    """
-    Test that calculate_change_in_variance respects the specified window size.
-    """
-    data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
-    window_size = 4
-    result = calculate_change_in_variance(data, window_size=window_size)
-    assert len(result.dropna()) == len(data) - window_size, "Result should have the correct length based on window size"
+# def test_calculate_change_in_variance_window_size():
+#     """
+#     Test that calculate_change_in_variance respects the specified window size.
+#     """
+#     data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+#     window_size = 4
+#     result = calculate_change_in_variance(data, window_size=window_size)
+#     assert len(result.dropna()) == len(data) - window_size, "Result should have the correct length based on window size"
 
-def test_calculate_change_in_variance_numpy_array():
-    """
-    Test that calculate_change_in_variance works with a numpy array.
-    """
-    data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
-    result = calculate_change_in_variance(data, window_size=3)
-    assert isinstance(result, pd.Series), "Result should be a pandas Series for numpy input"
-    assert len(result) == len(data), "Result should have the same length as the input data"
+# def test_calculate_change_in_variance_numpy_array():
+#     """
+#     Test that calculate_change_in_variance works with a numpy array.
+#     """
+#     data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+#     result = calculate_change_in_variance(data, window_size=3)
+#     assert isinstance(result, pd.Series), "Result should be a pandas Series for numpy input"
+#     assert len(result) == len(data), "Result should have the same length as the input data"
 
-def test_calculate_change_in_variance_decreasing_variance():
-    """
-    Test that calculate_change_in_variance detects decreasing variance.
-    """
-    data = pd.Series([50, 40, 30, 20, 10, 5, 4, 3, 2, 1])  # Decreasing variability
-    result = calculate_change_in_variance(data, window_size=3)
-    assert result.dropna().iloc[-1] <= 0, "Change in variance should decrease for shrinking variability"
+# def test_calculate_change_in_variance_decreasing_variance():
+#     """
+#     Test that calculate_change_in_variance detects decreasing variance.
+#     """
+#     data = pd.Series([50, 40, 30, 20, 10, 5, 4, 3, 2, 1])  # Decreasing variability
+#     result = calculate_change_in_variance(data, window_size=3)
+#     assert result.dropna().iloc[-1] <= 0, "Change in variance should decrease for shrinking variability"
diff --git a/tests/core/lp1.data.txt b/tests/core/lp1.data.txt
new file mode 100644
index 0000000..5a2082d
--- /dev/null
+++ b/tests/core/lp1.data.txt
@@ -0,0 +1,1582 @@
+normal
+	-1	-1	63	-3	-1	0
+	0	0	62	-3	-1	0
+	-1	-1	61	-3	0	0
+	-1	-1	63	-2	-1	0
+	-1	-1	63	-3	-1	0
+	-1	-1	63	-3	-1	0
+	-1	-1	63	-3	0	0
+	-1	-1	63	-3	-1	0
+	-1	-1	63	-3	-1	0
+	-1	-1	61	-3	0	0
+	-1	-1	61	-3	0	0
+	-1	-1	64	-3	-1	0
+	-1	-1	64	-3	-1	0
+	-1	-1	60	-3	0	0
+	-1	0	64	-2	-1	0
+
+
+normal
+	-1	-1	63	-2	-1	0
+	-1	-1	63	-3	-1	0
+	-1	-1	61	-3	0	0
+	0	-4	63	1	0	0
+	0	-1	59	-2	0	-1
+	-3	3	57	-8	-3	-1
+	-1	3	70	-10	-2	-1
+	0	-3	61	0	0	0
+	0	-2	53	-1	-2	0
+	0	-3	66	1	4	0
+	-3	3	58	-10	-5	0
+	-1	-1	66	-4	-2	0
+	-1	-2	67	-3	-1	0
+	0	1	66	-6	-3	-1
+	-1	-1	59	-3	-4	0
+
+
+normal
+	-1	0	57	-5	-3	0
+	0	-3	63	-1	0	0
+	-1	1	51	-4	-1	-1
+	-1	-2	68	-2	-2	0
+	-1	-1	65	-6	1	0
+	0	0	61	-5	-2	0
+	-1	1	61	-6	0	-1
+	0	-3	57	3	-4	0
+	-1	-1	59	-4	-4	0
+	1	-3	65	-1	1	0
+	-1	2	64	-7	-2	0
+	-1	1	66	-7	-3	-1
+	-1	0	61	-5	-5	0
+	-1	0	65	-6	-2	-1
+	-1	0	54	-4	-3	0
+
+
+normal
+	0	-1	59	-2	-1	-1
+	0	-3	61	-1	2	0
+	-2	1	56	-6	-3	0
+	1	-3	64	-1	4	0
+	-1	1	62	-7	1	-1
+	-1	0	60	-9	-5	-1
+	1	1	56	-5	0	0
+	1	-1	66	-4	2	1
+	-2	5	64	-15	-2	0
+	-1	2	58	-8	-4	0
+	0	1	70	-9	-2	-1
+	-1	1	64	-8	-6	-1
+	0	-1	67	-6	0	-1
+	0	-2	63	-4	0	0
+	-1	1	63	-8	-2	0
+
+
+normal
+	0	-2	65	-4	-2	0
+	-1	-2	56	-5	-3	0
+	0	0	58	-9	-1	0
+	-1	-1	56	-5	-3	0
+	-2	3	57	-12	-4	-1
+	-1	-2	65	-5	-2	0
+	-1	2	56	-9	-5	0
+	2	-2	60	-2	3	1
+	0	1	67	-9	-2	1
+	-1	2	60	-10	-5	0
+	0	-3	63	-3	-1	0
+	-1	-1	73	-8	-5	0
+	-1	0	57	-7	-4	-1
+	-1	0	59	-8	-4	-1
+	-1	1	57	-9	-4	-1
+
+
+normal
+	-1	2	57	-10	-3	0
+	-2	3	60	-12	-4	-1
+	-1	2	63	-12	-6	1
+	1	3	62	-11	0	0
+	-3	2	56	-9	-4	0
+	0	1	58	-8	-1	-1
+	-1	3	57	-11	-4	0
+	-2	3	61	-10	-5	0
+	-3	3	60	-11	-4	0
+	1	2	64	-9	0	-1
+	-1	2	60	-9	-5	0
+	-1	3	63	-12	-6	0
+	-1	0	52	-8	-2	0
+	-2	3	58	-13	-5	0
+	1	-2	59	-7	0	-1
+
+
+normal
+	-3	1	53	-10	-4	0
+	0	-2	65	-4	-1	0
+	-1	-1	56	-7	-3	0
+	0	-2	60	-6	0	0
+	-1	-1	57	-7	-4	0
+	-1	-1	56	-7	-3	0
+	-1	-1	61	-8	-5	0
+	-1	0	57	-6	-5	0
+	-2	-1	57	-7	-4	1
+	-1	0	53	-10	-5	-1
+	0	-2	70	-7	-5	0
+	-1	0	67	-10	-7	-1
+	0	-2	50	-3	-1	0
+	-1	-1	59	-9	-4	0
+	0	-2	61	-6	-1	0
+
+
+normal
+	2	0	69	-10	2	1
+	-2	1	58	-11	-4	0
+	-2	3	54	-12	-6	0
+	1	-1	62	-6	0	0
+	-1	1	63	-11	-3	-1
+	-1	0	50	-8	-1	-1
+	-1	0	60	-13	-5	0
+	-1	0	57	-11	-4	-1
+	-1	0	60	-8	-5	-1
+	-1	1	60	-8	-5	-1
+	1	0	60	-7	-1	0
+	-2	1	60	-12	-6	3
+	-1	0	63	-10	-3	1
+	-1	-1	54	-11	-3	0
+	0	-3	57	-5	1	0
+
+
+normal
+	-1	1	58	-11	-4	-1
+	0	0	64	-9	-3	0
+	0	0	61	-11	-2	0
+	-1	2	55	-13	-3	1
+	-1	1	51	-11	-4	0
+	0	3	58	-13	-4	0
+	-3	5	61	-18	-7	-1
+	2	1	69	-10	0	1
+	-1	1	61	-13	-5	-1
+	-2	3	57	-15	-6	-1
+	0	-2	57	-8	-4	1
+	-1	-2	58	-8	-4	1
+	-1	-1	56	-10	-3	0
+	0	0	57	-9	-4	0
+	-1	0	57	-9	-4	3
+
+
+normal
+	-1	-1	63	-3	-1	0
+	-1	-1	61	-2	-2	0
+	-1	-1	63	-3	0	0
+	-1	-1	64	-2	0	0
+	-1	-1	63	-2	-1	0
+	-1	-1	63	-3	0	0
+	-1	-1	63	-2	-1	0
+	-1	-1	63	-3	0	0
+	-1	-1	63	-3	-1	0
+	-1	-1	63	-3	0	0
+	0	0	63	-3	-1	0
+	-1	-1	63	-2	-1	0
+	-1	-1	63	-2	-1	0
+	-1	-1	64	-2	0	0
+	-1	-1	64	-3	-1	0
+
+
+normal
+	-1	-1	63	-3	0	0
+	-1	-1	63	-3	0	0
+	-1	-1	63	-2	-1	0
+	-2	1	52	-6	-3	0
+	1	-7	68	6	2	0
+	-1	-1	63	-5	-1	0
+	0	2	64	-5	1	0
+	-3	4	57	-8	-3	0
+	0	-3	65	1	0	0
+	0	-3	61	-1	-1	0
+	-1	0	57	-5	-3	0
+	0	-3	70	0	1	0
+	-2	2	58	-8	-4	-1
+	-1	0	70	-5	-2	-1
+	-1	0	64	-5	0	-1
+
+
+normal
+	1	-3	62	-1	2	0
+	-1	0	51	-3	-2	-1
+	1	0	70	-5	1	-1
+	-1	0	63	-7	-2	-1
+	0	1	63	-6	-2	-1
+	1	-4	66	1	-1	0
+	2	1	66	-5	0	0
+	-3	2	59	-7	-4	0
+	-1	0	61	-4	-3	-1
+	-2	0	63	-5	-6	1
+	-1	-1	60	-3	-5	0
+	1	-4	59	0	1	0
+	-1	-3	51	-1	-4	0
+	0	-3	69	-3	1	0
+	-2	2	60	-10	-5	0
+
+
+normal
+	0	-1	69	-4	2	-1
+	-3	4	60	-12	-4	0
+	0	0	69	-5	-1	0
+	-1	3	67	-11	-2	1
+	-2	2	61	-9	-5	0
+	0	-5	59	0	-1	0
+	0	-5	60	0	1	0
+	-2	1	57	-6	-3	0
+	-2	2	61	-9	-5	-1
+	-1	3	68	-9	-4	0
+	-2	4	60	-10	-5	0
+	1	2	66	-10	1	-1
+	-1	-1	58	-5	2	0
+	1	-4	52	0	4	0
+	-1	-2	54	-3	-3	-1
+
+
+normal
+	1	-2	57	-4	0	-1
+	-1	0	64	-9	-2	0
+	-1	1	66	-8	-2	-1
+	-2	2	64	-11	-6	-1
+	0	1	60	-6	-1	-1
+	-1	-1	56	-6	-3	0
+	0	-1	59	-4	-5	-1
+	1	-2	64	-7	-2	-1
+	-2	1	59	-8	-6	0
+	1	-2	63	-4	-1	0
+	-1	-1	47	-3	-2	0
+	1	-4	59	0	2	0
+	-1	-3	64	-4	-6	0
+	0	-2	60	-4	-1	0
+	0	-1	60	-6	0	-1
+
+
+normal
+	-1	1	67	-9	-4	-1
+	1	-1	64	-5	-1	-1
+	1	-1	72	-6	-2	0
+	-1	1	58	-11	-4	-1
+	0	-3	58	-5	1	0
+	-1	2	58	-9	-4	0
+	-2	1	57	-9	-3	0
+	-1	-1	61	-5	0	0
+	0	1	61	-9	-1	-1
+	-2	4	54	-10	-4	0
+	-2	3	60	-11	-6	0
+	1	-1	69	-8	0	0
+	-3	2	58	-11	-5	1
+	-2	2	67	-11	-7	0
+	-1	0	65	-9	-3	-1
+
+
+normal
+	0	2	67	-11	-3	0
+	-1	0	56	-7	-3	-1
+	-1	1	65	-10	-6	-1
+	-1	3	63	-13	-6	0
+	-2	2	59	-8	-4	0
+	-1	-1	60	-5	-5	0
+	-2	2	61	-13	-5	0
+	0	1	56	-8	-3	-1
+	-1	1	56	-8	-3	0
+	-2	1	56	-10	-3	0
+	-1	0	59	-9	-4	0
+	-1	0	57	-9	-4	-1
+	-1	0	59	-11	-4	-1
+	-2	2	54	-10	-5	1
+	-3	2	50	-13	-6	-1
+
+
+normal
+	-1	1	58	-8	-4	1
+	-2	0	57	-7	-3	1
+	0	0	63	-11	-6	0
+	-2	-1	64	-9	-6	1
+	-2	0	54	-9	-5	1
+	-1	-1	57	-9	-4	0
+	-2	2	58	-10	-5	1
+	0	-3	63	-7	-1	0
+	-1	0	57	-8	-3	1
+	0	0	60	-10	-5	0
+	-1	1	56	-10	-3	0
+	0	0	55	-8	-3	2
+	-1	-1	50	-7	-2	-1
+	-1	-2	57	-6	-4	0
+	0	2	63	-12	-2	1
+
+
+normal
+	1	0	60	-8	1	1
+	-1	1	57	-12	-3	-1
+	-1	1	53	-12	-6	-1
+	-1	1	60	-11	-5	-1
+	-1	3	53	-12	-2	1
+	-1	1	57	-12	-5	-1
+	1	-2	68	-12	-2	-1
+	-1	-2	59	-8	-1	0
+	-2	3	56	-15	-6	0
+	1	-2	60	-6	2	0
+	0	1	60	-14	-5	0
+	-1	2	57	-13	-4	-2
+	-1	1	58	-11	-4	-1
+	-1	2	58	-12	-4	0
+	-1	2	57	-13	-4	0
+
+
+collision
+	24	53	79	-200	109	2
+	69	14	48	-40	100	0
+	15	-14	55	24	11	2
+	-9	-20	62	19	-16	2
+	11	-8	53	6	13	0
+	10	2	66	-6	13	0
+	-8	4	68	-10	-8	1
+	-12	5	58	-10	-18	1
+	1	6	59	-11	1	0
+	3	3	64	-9	4	0
+	-2	1	71	-6	-3	0
+	2	1	59	-6	3	0
+	1	2	63	-7	-1	0
+	-3	-1	61	-4	-5	-1
+	-3	-2	64	-3	-5	-1
+
+
+collision
+	185	105	118	-180	374	12
+	-10	5	75	-36	34	-2
+	-1	-4	43	1	-8	0
+	-10	-2	64	3	-19	0
+	0	-2	66	1	0	0
+	0	1	58	-5	2	-1
+	0	-5	61	2	-2	1
+	0	-4	57	1	-4	0
+	-1	-1	59	-1	-4	0
+	-1	1	64	-5	-6	1
+	0	0	67	-6	-3	0
+	-4	0	61	-5	-7	0
+	-3	1	60	-6	-4	0
+	-1	0	57	-4	-4	-1
+	1	1	65	-6	2	0
+
+
+collision
+	-21	-50	46	-180	266	98
+	-119	2	146	5	-115	-14
+	-38	-10	43	-8	-27	-4
+	3	9	66	-5	-3	-2
+	5	12	59	-16	11	1
+	-9	2	73	-2	-13	0
+	0	-4	51	5	-2	0
+	13	-3	66	3	18	0
+	8	-1	66	1	12	1
+	-5	0	54	-1	-7	0
+	-3	-1	63	1	-5	-1
+	-7	-2	65	3	-8	0
+	-1	-1	61	2	-1	0
+	-1	1	65	-2	-3	0
+	4	1	64	-2	7	1
+
+
+collision
+	112	-54	85	-77	284	-3
+	-5	-36	56	123	-115	-29
+	5	-24	74	50	-19	-2
+	7	-12	65	5	26	1
+	-2	-7	57	11	-3	0
+	-4	5	66	-7	-8	0
+	-2	4	57	-2	0	0
+	-4	4	65	-8	-6	0
+	-3	3	52	-3	-3	1
+	-2	3	57	-3	-1	0
+	1	1	64	1	2	1
+	1	1	60	-1	3	0
+	0	0	56	0	3	0
+	-1	2	63	-3	-1	-1
+	-1	4	59	-2	-1	1
+
+
+collision
+	95	-4	38	125	111	-4
+	17	9	43	-18	48	-4
+	-29	-6	55	6	-45	4
+	-8	11	68	-17	-8	6
+	9	13	61	-18	14	6
+	-10	6	68	-9	-15	0
+	-8	3	74	-4	-10	0
+	3	4	65	-8	6	1
+	8	4	61	-6	11	0
+	4	-1	59	1	5	0
+	-3	0	61	0	-5	-1
+	-2	0	67	0	-7	1
+	-3	3	59	-5	-4	0
+	-3	0	67	-2	-7	1
+	-3	3	64	-7	-6	1
+
+
+collision
+	-127	83	69	-71	-148	-53
+	-134	53	108	-59	-173	-23
+	-49	54	79	-75	-60	8
+	-15	53	74	-67	-8	1
+	-7	31	75	-40	-12	-10
+	-14	15	60	-15	-20	-6
+	-4	9	51	-15	-2	11
+	8	7	58	-11	12	2
+	6	-1	63	0	9	-6
+	-1	2	52	-5	-2	-5
+	-4	1	59	-6	-7	5
+	-1	1	52	-2	-2	2
+	3	0	66	-2	1	-4
+	1	1	60	-3	2	-2
+	0	1	64	-4	1	4
+
+
+collision
+	-72	-24	84	120	-196	-15
+	-26	-10	37	12	-50	-3
+	-30	-17	67	16	-40	-4
+	0	-3	50	-1	-10	0
+	0	-3	53	-2	-1	-3
+	-5	-1	60	-6	-11	-1
+	0	-3	64	-3	-4	-1
+	6	-4	57	-1	4	0
+	5	-5	59	-2	5	-1
+	-2	-4	64	-1	-7	0
+	-1	-3	58	-3	-5	0
+	0	0	60	-9	-3	0
+	1	-1	53	-4	-4	-2
+	0	0	59	-6	-3	0
+	1	1	59	-10	-2	0
+
+
+collision
+	-133	-34	18	21	131	-41
+	21	6	79	-36	59	-2
+	14	17	69	-45	13	-5
+	6	1	56	-5	7	7
+	15	-3	51	0	17	-2
+	10	-4	52	-2	8	-3
+	5	-6	63	2	3	1
+	0	-4	61	-1	-3	-2
+	-1	-1	61	-5	-6	-1
+	-1	1	61	-10	-6	-1
+	1	0	66	-10	-4	1
+	1	-3	59	-3	-2	0
+	-1	2	59	-12	-6	0
+	0	1	58	-9	-5	-1
+	0	0	60	-8	-6	-1
+
+
+collision
+	-10	-2	27	-17	8	3
+	22	-4	61	-6	28	1
+	22	4	62	-12	24	1
+	11	-5	55	-1	10	0
+	3	-13	61	10	-1	1
+	6	-8	57	5	4	0
+	8	-3	57	-1	9	1
+	0	-5	60	-1	-4	0
+	-5	-4	57	-4	-11	1
+	-4	-3	66	-2	-8	-1
+	1	0	59	-9	-6	-1
+	-3	6	64	-21	-17	-3
+	3	0	59	-8	-3	0
+	-2	0	60	-9	-7	1
+	-2	2	61	-12	-6	0
+
+
+collision
+	5	23	157	-186	179	2
+	-25	8	93	-46	25	-5
+	-16	-8	56	19	-54	1
+	1	-1	50	-5	-8	-1
+	0	2	55	-10	3	0
+	-5	-2	60	-4	-11	0
+	-1	-6	58	1	-5	0
+	5	-4	64	-4	2	-2
+	6	-5	63	-1	2	0
+	-1	-3	58	-2	-5	0
+	-1	-4	57	-2	-6	-2
+	0	-4	61	-4	-6	0
+	2	-5	66	-3	0	0
+	1	-2	53	-4	-4	-1
+	1	-3	51	-2	-3	0
+
+
+collision
+	-14	-10	52	15	-77	0
+	-22	-14	47	8	-31	2
+	-3	9	62	-23	-1	-1
+	0	8	59	-19	-1	-1
+	-10	4	60	-13	-16	0
+	-1	4	57	-13	-3	-2
+	2	6	66	-15	1	0
+	1	4	57	-12	2	0
+	-1	2	53	-8	-5	0
+	-3	-1	57	-5	-7	-1
+	0	1	68	-8	-2	-1
+	-1	2	57	-10	-6	-1
+	-1	0	67	-9	-6	0
+	1	1	61	-9	-3	-1
+	1	0	65	-9	-2	-1
+
+
+collision
+	8	-17	50	16	-1	-2
+	2	-25	55	22	-1	-1
+	10	-17	50	18	9	-2
+	3	-17	60	11	3	-2
+	7	-10	65	8	7	1
+	1	-9	56	1	-1	0
+	3	-12	59	10	3	-1
+	3	-5	58	-1	2	0
+	0	-8	63	2	-3	0
+	1	-2	56	-5	-1	0
+	-1	-2	56	-4	-5	-2
+	1	0	61	-7	-2	0
+	0	0	57	-8	-6	-1
+	-1	0	49	-9	-3	-1
+	-1	3	63	-11	-3	-1
+
+
+collision
+	3	-33	32	41	2	-1
+	9	-25	54	26	7	0
+	7	-12	44	-2	11	-1
+	3	-16	54	12	2	1
+	1	-17	56	12	1	1
+	2	-9	65	3	-2	-1
+	3	-5	53	-3	3	1
+	4	-7	56	-2	-1	-1
+	2	-9	49	3	2	0
+	2	-8	55	-1	-4	-2
+	2	-6	59	-3	-2	-1
+	2	-5	53	-3	-1	0
+	2	-3	46	-8	-3	0
+	1	-2	59	-4	-2	-1
+	0	-2	54	-11	-5	0
+
+
+collision
+	2	-3	70	-3	-1	0
+	0	7	69	-21	14	-15
+	-20	-7	52	9	-41	0
+	0	-2	63	-7	3	0
+	2	0	62	-6	2	-1
+	-3	0	57	-6	-5	-1
+	-2	-1	54	-4	-7	0
+	3	-5	54	0	3	-1
+	4	-3	63	-5	3	-1
+	1	-3	63	-3	0	0
+	-1	-3	59	-3	-7	-1
+	1	-3	60	-3	0	0
+	0	0	60	-8	-1	0
+	-1	0	57	-8	-6	-1
+	-1	1	58	-9	-3	0
+
+
+collision
+	4	-14	59	82	-85	13
+	32	7	47	-32	59	3
+	-2	2	72	-1	-16	1
+	-1	2	59	-15	-1	0
+	-1	3	58	-12	-2	1
+	1	3	67	-10	-4	1
+	-4	6	63	-15	-7	-1
+	-5	4	61	-14	-10	0
+	1	4	66	-14	-3	-1
+	2	2	65	-10	-1	-1
+	0	3	63	-13	0	-2
+	-2	5	57	-13	-6	-1
+	-1	1	65	-10	-4	0
+	-1	2	65	-11	-4	0
+	-1	0	59	-8	-7	0
+
+
+collision
+	71	51	5	686	494	-137
+	21	37	115	-85	55	-4
+	63	-9	6	-34	159	-10
+	13	-17	73	23	14	-2
+	0	-11	52	12	-13	0
+	8	-10	64	10	9	1
+	6	-4	57	-2	5	0
+	-3	-2	72	-7	-5	1
+	-8	1	53	-9	-15	-1
+	-1	6	74	-16	-4	-1
+	3	4	65	-11	1	0
+	1	3	62	-11	-1	-1
+	-1	0	60	-8	-7	0
+	-1	0	59	-8	-7	0
+	1	-2	65	-5	0	0
+
+
+collision
+	-93	76	80	-123	-151	-1
+	-20	63	62	-108	-30	-1
+	11	44	57	-64	15	-1
+	11	16	66	-27	7	0
+	0	0	58	-8	-4	0
+	3	-2	61	-7	-1	0
+	8	-3	63	-5	8	-1
+	7	1	59	-11	7	1
+	-3	0	59	-9	-9	-1
+	-6	2	57	-13	-13	-1
+	-2	4	74	-17	-7	0
+	3	6	59	-17	2	0
+	2	4	59	-14	1	-1
+	-1	2	61	-11	-3	-1
+	-2	1	64	-10	-6	0
+
+
+obstruction
+	-8	20	-5	-26	-10	-1
+	-10	22	-4	-22	-9	-2
+	-10	17	-4	-16	-10	-1
+	-9	15	0	-11	-6	0
+	-3	19	-21	12	21	-2
+	-38	130	-786	191	315	29
+	-30	139	-1235	472	601	39
+	-31	31	-39	-11	-3	3
+	-14	18	-21	24	22	8
+	-3	14	5	6	5	-4
+	-6	8	3	12	4	-1
+	-3	3	4	16	6	-2
+	0	5	10	17	6	-3
+	-3	5	10	14	2	-2
+	-3	3	10	16	4	-3
+
+
+obstruction
+	11	-3	-301	-267	-88	-16
+	28	-103	-826	-278	-237	6
+	46	-217	-1218	-147	-345	40
+	17	-95	-621	-164	-226	40
+	-6	10	-77	-103	-56	-6
+	-5	13	-104	-129	-60	-1
+	1	6	-112	-142	-66	-2
+	1	5	-111	-146	-58	-5
+	3	4	-113	-146	-54	-4
+	3	4	-115	-143	-58	-4
+	1	3	-116	-145	-61	-5
+	2	3	-119	-149	-62	-5
+	2	3	-118	-150	-60	-5
+	2	3	-117	-148	-58	-5
+	2	3	-118	-148	-58	-5
+
+
+obstruction
+	5	-4	-345	-185	0	0
+	-21	-59	-1162	-239	2	-5
+	-22	-106	-1360	-82	27	1
+	8	-46	100	52	-6	-9
+	1	-38	38	49	1	-1
+	13	-13	56	7	17	-2
+	3	-13	54	8	1	-1
+	1	-9	58	5	-1	-1
+	4	-5	60	-1	3	-1
+	2	-4	61	-3	1	-1
+	-2	-1	58	-7	-6	-2
+	-4	0	60	-8	-9	-1
+	-3	0	59	-9	-6	-1
+	-1	1	61	-8	-4	-1
+	1	0	60	-8	-2	-1
+
+
+obstruction
+	-6	15	-414	-53	16	-5
+	-38	14	-1357	-192	71	-9
+	4	-3	-90	-28	-20	12
+	11	-2	73	-4	22	-2
+	4	-4	42	-4	2	0
+	7	-17	61	13	6	0
+	7	-6	54	0	7	-1
+	1	-9	57	3	-1	-1
+	-2	-12	58	6	-6	-2
+	-1	-11	53	5	-5	-1
+	2	-11	58	4	-1	-1
+	3	-8	58	0	0	-2
+	1	-7	57	0	-2	-1
+	1	-4	57	-4	-2	-2
+	3	-3	58	-5	1	-2
+
+
+obstruction
+	-31	0	-398	-259	4	25
+	-80	-63	-987	-286	57	20
+	-88	-121	-1299	-229	137	1
+	20	40	-45	-54	24	-4
+	0	27	30	-51	-10	-5
+	-9	9	49	-27	-6	-2
+	-3	5	49	-25	-3	-2
+	2	3	46	-21	3	-2
+	1	-1	39	-19	3	-2
+	0	-2	38	-17	-1	0
+	1	-3	38	-18	2	-1
+	1	-3	38	-19	4	-1
+	0	-2	38	-19	0	0
+	-1	1	43	-18	-1	0
+	-1	2	46	-19	-2	-1
+
+
+normal
+	0	2	50	-13	-4	-1
+	0	0	58	-8	-3	-2
+	0	0	67	-11	-3	-1
+	0	-1	52	-7	-4	-1
+	0	0	56	-8	-6	-2
+	-1	1	64	-11	-5	-1
+	0	0	68	-9	-5	-1
+	-1	3	59	-16	-8	-1
+	0	0	68	-13	-4	-1
+	-1	1	59	-11	-3	-1
+	0	0	56	-11	-6	-2
+	-1	2	60	-13	-3	-2
+	0	3	61	-15	-3	-1
+	-1	3	63	-16	-8	-1
+	-1	2	64	-14	-5	-1
+
+
+obstruction
+	-20	55	-918	-90	-77	-6
+	-26	76	-1352	-127	-96	-9
+	4	9	54	-25	2	-4
+	-5	-7	62	0	-13	0
+	-5	12	53	-22	-9	-2
+	-7	6	57	-16	-13	-1
+	-3	3	58	-15	-7	-1
+	2	5	56	-18	0	-1
+	2	6	58	-17	-2	-1
+	0	6	57	-18	-3	-1
+	-2	3	57	-14	-6	-1
+	-1	2	57	-13	-6	-1
+	-1	1	54	-12	-5	-1
+	-1	1	56	-11	-6	-1
+	-2	0	57	-11	-6	-1
+
+
+normal
+	0	2	61	-12	-2	5
+	-1	0	60	-6	-3	0
+	-1	1	53	-8	-5	3
+	1	-2	66	-6	-2	-1
+	1	-1	60	-9	-3	-1
+	0	0	64	-9	-1	-1
+	0	0	57	-8	-4	-1
+	-1	1	64	-12	-4	-1
+	-1	1	66	-9	-4	-1
+	0	1	66	-13	-5	-1
+	-1	1	59	-12	-4	-1
+	-1	1	66	-12	-5	0
+	0	1	65	-12	-3	-2
+	1	1	63	-10	-2	-1
+	-1	0	64	-9	-5	-1
+
+
+obstruction
+	-35	17	-1029	-232	27	1
+	-45	31	-1395	-151	12	-11
+	10	-20	22	12	9	-1
+	-1	-24	62	20	-9	0
+	1	2	51	-13	-4	-2
+	-1	-4	59	-5	-7	0
+	1	1	56	-12	-4	-2
+	4	4	58	-15	3	-1
+	3	4	62	-16	0	-1
+	0	8	57	-19	-6	-1
+	-4	8	60	-20	-9	-1
+	-4	7	59	-18	-8	-1
+	-3	6	59	-17	-6	-1
+	-2	5	58	-17	-6	-1
+	-2	4	59	-16	-6	-1
+
+
+obstruction
+	1	0	57	8	5	7
+	-1	0	54	11	6	8
+	-11	38	-364	207	62	4
+	-77	175	-1133	383	-14	-25
+	-90	142	-1130	523	-21	-36
+	-37	59	-127	22	25	33
+	-2	6	-53	86	18	3
+	4	2	-17	53	38	10
+	3	1	-15	53	30	7
+	3	2	-23	56	33	10
+	4	5	-36	61	38	12
+	2	5	-36	60	37	10
+	3	4	-27	59	34	10
+	2	2	-20	58	33	9
+	3	2	-21	59	32	9
+
+
+obstruction
+	-6	27	-288	140	23	-2
+	-80	162	-1077	385	-38	-33
+	-102	158	-1264	543	-43	-43
+	64	-61	-95	142	91	15
+	-2	3	-67	93	45	22
+	7	6	-90	111	37	-1
+	5	6	-101	112	47	7
+	4	6	-108	116	49	8
+	2	3	-97	114	45	7
+	3	2	-93	110	45	7
+	4	2	-91	109	48	7
+	5	4	-97	109	52	10
+	5	5	-100	110	53	9
+	4	4	-99	108	53	10
+	5	5	-97	109	53	9
+
+
+obstruction
+	-13	-12	-558	-450	-108	21
+	-19	-69	-738	-430	-128	23
+	-20	-148	-923	-396	-156	36
+	-32	-176	-1168	-495	-210	52
+	-36	-192	-1286	-560	-232	55
+	27	-68	-588	-331	-39	17
+	-6	-72	-588	-378	-65	2
+	1	-35	-603	-403	-68	13
+	3	-48	-581	-381	-52	6
+	1	-46	-598	-397	-57	6
+	2	-49	-590	-390	-64	10
+	2	-46	-594	-393	-60	8
+	2	-47	-584	-387	-56	8
+	2	-45	-586	-386	-58	8
+	1	-45	-581	-383	-59	8
+
+
+obstruction
+	3	-10	-7	-44	1	5
+	-1	-86	-628	-338	-98	16
+	-35	-79	-685	-418	-206	46
+	-60	-113	-800	-453	-302	76
+	-78	-159	-1032	-535	-395	104
+	-92	-195	-1274	-672	-468	123
+	-66	-110	-614	-340	-284	83
+	27	-38	-640	-498	-38	3
+	4	-44	-654	-476	-88	9
+	11	-50	-606	-445	-70	3
+	13	-63	-598	-425	-63	2
+	11	-58	-601	-429	-64	3
+	10	-53	-595	-425	-63	3
+	10	-56	-599	-427	-65	3
+	10	-57	-599	-426	-67	4
+
+
+obstruction
+	-1	-86	-628	-338	-98	16
+	-35	-79	-685	-418	-206	46
+	-78	-159	-1032	-535	-395	104
+	-60	-113	-800	-453	-302	76
+	-92	-195	-1274	-672	-468	123
+	-66	-110	-614	-340	-284	83
+	27	-38	-640	-498	-38	3
+	4	-44	-654	-476	-88	9
+	11	-50	-606	-445	-70	3
+	13	-63	-598	-425	-63	2
+	11	-58	-601	-429	-64	3
+	10	-53	-595	-425	-63	3
+	10	-56	-599	-427	-65	3
+	10	-57	-599	-426	-67	4
+	11	-58	-601	-429	-64	3
+
+
+obstruction
+	-37	26	-779	-150	5	3
+	-51	23	-1340	-185	1	4
+	-7	31	0	-51	-16	-1
+	-7	32	52	-50	-12	-1
+	-2	21	58	-37	-4	0
+	-5	12	58	-26	-10	0
+	-3	8	57	-18	-8	0
+	-1	6	56	-18	-8	0
+	-1	6	56	-18	-8	0
+	0	4	58	-14	-4	0
+	0	0	59	-11	-3	0
+	1	1	59	-10	-2	0
+	0	0	58	-10	-2	0
+	-1	-1	58	-8	-5	0
+	-2	-1	54	-8	-7	0
+
+
+obstruction
+	-18	-9	46	-4	-11	-2
+	-6	-12	62	8	-16	2
+	35	20	-650	-97	-427	-13
+	68	47	-1145	-131	-633	-32
+	52	25	-877	-117	-530	-17
+	-16	6	0	5	-45	-4
+	-8	-16	72	11	-14	-1
+	-6	1	60	-12	-13	-1
+	-10	-3	58	-5	-16	-1
+	-8	-2	55	-7	-14	0
+	-5	-2	58	-5	-11	0
+	-2	-1	57	-7	-9	-1
+	1	2	53	-10	-7	0
+	-1	2	56	-11	-8	-1
+	-1	0	56	-10	-8	0
+
+
+obstruction
+	-21	1	-185	-202	3	11
+	-43	-86	-750	-315	127	10
+	-104	-105	-1173	-221	230	16
+	-134	-118	-1194	-183	195	15
+	-53	-5	-236	-273	26	9
+	-29	-9	-256	-267	12	-2
+	-17	1	-217	-245	27	3
+	-8	6	-210	-242	31	3
+	-9	6	-217	-253	34	4
+	-10	6	-225	-258	35	5
+	-7	6	-226	-259	38	4
+	-4	9	-217	-252	40	3
+	-4	8	-213	-249	39	4
+	-8	7	-216	-249	37	3
+	-8	7	-218	-252	35	3
+
+
+fr_collision
+	-12	41	-133	-150	-53	-3
+	-10	40	-136	-145	-51	-3
+	-11	39	-142	-148	-54	-3
+	-12	43	-155	-158	-57	-3
+	-12	49	-169	-171	-58	-4
+	-14	51	-182	-175	-64	-4
+	-12	54	-195	-184	-60	-5
+	-15	54	-216	-188	-66	-4
+	-14	59	-235	-204	-66	-6
+	-14	62	-256	-213	-67	-5
+	-13	67	-278	-226	-67	-6
+	-15	68	-303	-233	-71	-6
+	-16	74	-328	-247	-75	-7
+	-15	77	-359	-259	-76	-7
+	-16	83	-394	-274	-79	-8
+
+
+obstruction
+	-17	99	-511	-319	-87	-10
+	-20	107	-554	-340	-91	-12
+	-19	113	-601	-357	-94	-12
+	-21	121	-657	-374	-99	-12
+	-19	127	-728	-391	-100	-14
+	-21	134	-800	-407	-105	-14
+	-21	137	-878	-419	-109	-15
+	-25	142	-966	-427	-118	-15
+	-24	145	-1083	-431	-115	-15
+	-25	151	-1180	-441	-124	-14
+	-24	134	-1287	-390	-121	-15
+	-25	127	-1409	-359	-124	-14
+	-25	123	-1491	-346	-127	-14
+	-31	141	-589	-360	-74	-16
+	-24	81	-481	-284	-148	-8
+
+
+fr_collision
+	4	8	41	-28	10	0
+	4	7	33	-24	13	0
+	5	10	37	-31	14	0
+	4	8	27	-26	13	0
+	6	9	37	-30	15	0
+	6	11	29	-32	15	0
+	7	8	26	-28	18	0
+	6	10	23	-31	17	0
+	6	9	15	-28	17	1
+	8	11	24	-31	17	1
+	6	11	16	-32	17	1
+	7	12	12	-32	24	0
+	9	8	6	-28	22	1
+	8	11	7	-34	22	1
+	9	12	2	-32	23	0
+
+
+fr_collision
+	6	9	15	-28	17	1
+	8	11	24	-31	17	1
+	6	11	16	-32	17	1
+	7	12	12	-32	24	0
+	9	8	6	-28	22	1
+	8	11	7	-34	22	1
+	9	13	0	-33	22	2
+	8	12	-8	-35	20	1
+	11	14	-21	-36	27	1
+	12	13	-13	-35	29	0
+	11	13	-16	-37	30	2
+	11	14	-24	-35	27	1
+	14	13	-26	-36	32	2
+	12	14	-31	-36	29	3
+	14	15	-35	-38	35	1
+
+
+fr_collision
+	14	13	-26	-36	32	2
+	12	14	-31	-36	29	3
+	14	15	-35	-38	35	1
+	12	16	-52	-37	31	2
+	14	19	-52	-45	36	1
+	12	17	-63	-42	30	2
+	15	16	-64	-41	37	2
+	16	18	-83	-45	39	1
+	17	15	-91	-37	36	2
+	14	15	-99	-41	32	2
+	16	19	-113	-42	38	1
+	16	20	-132	-42	36	3
+	17	17	-139	-40	39	2
+	16	19	-160	-43	39	3
+	20	19	-174	-43	45	2
+
+
+obstruction
+	30	22	-325	-46	66	4
+	31	23	-368	-48	68	4
+	36	23	-415	-47	78	4
+	37	28	-476	-53	83	5
+	42	28	-540	-54	92	5
+	45	32	-606	-62	97	6
+	50	34	-702	-65	110	6
+	55	37	-812	-69	116	6
+	58	45	-924	-83	126	6
+	64	48	-1082	-89	141	6
+	70	54	-1251	-101	151	6
+	74	61	-1436	-109	156	6
+	74	61	-1437	-111	157	8
+	29	-24	-346	20	6	-2
+	19	-6	-380	32	25	1
+
+
+fr_collision
+	0	1	70	-10	-2	-1
+	-1	1	60	-4	-1	0
+	1	1	53	-6	3	1
+	2	1	51	-2	8	1
+	2	2	57	-4	9	2
+	2	2	45	0	13	1
+	2	2	29	3	19	3
+	5	3	22	7	30	4
+	3	7	3	6	36	5
+	7	8	-4	14	50	8
+	7	9	-22	20	56	9
+	9	12	-34	24	72	10
+	13	13	-49	33	87	12
+	16	12	-69	49	107	13
+	16	11	-94	64	122	17
+
+
+obstruction
+	18	14	-113	74	140	12
+	20	11	-139	89	154	13
+	21	10	-157	99	165	16
+	19	15	-177	103	170	21
+	20	17	-192	105	178	22
+	13	21	-227	109	171	21
+	12	23	-234	108	170	20
+	5	27	-242	102	155	18
+	1	37	-243	76	144	18
+	-8	44	-280	70	131	16
+	-12	50	-304	65	132	16
+	-12	55	-325	64	137	17
+	-18	65	-359	57	138	16
+	-22	69	-399	66	138	16
+	-25	78	-429	60	144	17
+
+
+obstruction
+	-26	87	-454	51	150	18
+	-29	87	-475	61	150	19
+	-29	82	-476	76	150	18
+	-32	77	-498	107	150	16
+	-31	68	-515	153	163	13
+	-37	66	-589	198	166	13
+	-40	64	-637	238	178	12
+	-43	60	-669	273	186	9
+	-49	60	-727	299	188	7
+	-77	80	-807	305	153	0
+	-109	110	-968	318	141	-8
+	-141	139	-1107	336	118	-15
+	-184	177	-1241	311	77	-22
+	-226	212	-1371	312	19	-38
+	-260	236	-1501	327	2	-50
+
+
+obstruction
+	-254	219	-1428	308	-20	-51
+	-246	205	-1334	293	-48	-57
+	-247	203	-1302	291	-60	-61
+	-249	200	-1293	298	-70	-64
+	-251	195	-1286	279	-80	-62
+	-250	194	-1278	291	-85	-65
+	-249	192	-1266	290	-89	-67
+	-250	190	-1259	296	-95	-68
+	-248	190	-1252	295	-92	-68
+	-248	188	-1249	290	-93	-68
+	-248	185	-1248	277	-100	-64
+	-243	187	-1241	306	-112	-78
+	-249	181	-1238	276	-89	-59
+	-247	186	-1232	285	-83	-63
+	-241	183	-1227	307	-95	-71
+
+
+fr_collision
+	0	0	50	-11	-7	0
+	1	-3	47	-9	-7	0
+	1	0	42	-15	-6	-1
+	-1	1	34	-18	-10	0
+	-1	-1	46	-13	-11	1
+	-1	-1	44	-14	-9	2
+	-3	-1	37	-13	-13	2
+	-5	-1	36	-17	-24	2
+	-4	-4	30	-14	-21	2
+	-2	-6	22	-14	-22	3
+	-5	-6	9	-20	-27	3
+	-5	-7	-2	-25	-33	4
+	-5	-4	-11	-39	-38	3
+	-9	-4	-14	-46	-48	2
+	-12	-2	-33	-55	-59	4
+
+
+obstruction
+	-14	-4	-51	-62	-70	6
+	-14	-9	-67	-62	-79	9
+	-16	-9	-84	-69	-87	9
+	-14	-8	-103	-83	-87	8
+	-11	-6	-124	-103	-84	6
+	-7	-6	-149	-122	-79	4
+	0	-8	-177	-134	-71	1
+	2	-9	-215	-152	-69	-1
+	5	-10	-260	-183	-78	-1
+	6	-10	-323	-220	-97	0
+	8	-12	-396	-261	-115	1
+	10	-11	-477	-306	-134	-1
+	13	-22	-605	-370	-171	-3
+	17	-49	-768	-396	-215	3
+	24	-127	-866	-259	-238	25
+
+
+obstruction
+	8	-12	-396	-261	-115	1
+	6	-10	-323	-220	-97	0
+	10	-11	-477	-306	-134	-1
+	17	-49	-768	-396	-215	3
+	13	-22	-605	-370	-171	-3
+	24	-127	-866	-259	-238	25
+	32	-183	-1053	-219	-290	43
+	37	-264	-1242	-126	-343	64
+	47	-343	-1407	-36	-385	86
+	45	-353	-1267	-6	-404	97
+	37	-10	-335	-335	-46	-18
+	8	7	-341	-296	-154	6
+	1	9	-338	-312	-128	-11
+	5	9	-341	-312	-109	-14
+	5	8	-343	-312	-117	-9
+
+
+obstruction
+	-1	-1	61	-5	-1	-1
+	-2	-1	58	-6	-4	0
+	6	4	-49	-57	-27	-2
+	14	13	-887	-220	-184	-14
+	20	-25	-1326	-166	-275	-4
+	-21	29	34	-61	-45	-3
+	3	-9	67	26	3	0
+	8	4	56	-11	10	-1
+	2	-2	59	-4	1	-1
+	-1	-4	54	-5	-3	-1
+	2	-2	58	-5	-2	-1
+	1	0	59	-7	-1	0
+	-1	1	61	-8	-4	0
+	-2	2	63	-8	-5	-1
+	-1	2	61	-9	-4	-1
+
+
+obstruction
+	-3	0	44	-11	-8	-2
+	0	-4	30	-5	-6	-2
+	-3	1	33	-15	-8	-2
+	-2	-1	23	-13	-9	-2
+	-3	0	15	-16	-14	-1
+	-2	0	-2	-19	-15	-2
+	-3	-1	-59	-27	-23	-2
+	-4	-2	-110	-33	-29	-2
+	-4	-3	-189	-46	-36	-3
+	-4	0	-297	-69	-39	-6
+	-1	3	-457	-106	-44	-9
+	0	7	-683	-144	-52	-14
+	2	12	-991	-197	-70	-20
+	0	6	-1368	-190	-80	-24
+	-3	-10	-1547	-127	-70	-25
+
+
+normal
+	-1	2	56	-11	-2	-1
+	-1	0	58	-8	-6	0
+	-4	1	57	-13	-8	-1
+	-2	1	53	-12	-7	-1
+	-2	1	51	-11	-6	-1
+	-2	2	57	-14	-8	-1
+	-2	0	58	-12	-8	-1
+	-1	2	54	-14	-8	-1
+	-2	3	57	-17	-8	0
+	-2	5	53	-20	-7	-1
+	-3	2	53	-16	-9	-1
+	-2	2	52	-18	-9	-1
+	-1	-1	54	-12	-8	0
+	-2	1	56	-16	-8	-1
+	-1	0	50	-16	-9	0
+
+
+fr_collision
+	-6	8	38	-45	-21	-1
+	-5	7	41	-42	-20	1
+	-5	7	40	-44	-22	-1
+	-8	10	31	-50	-25	0
+	-5	11	41	-55	-25	0
+	-7	10	34	-56	-29	1
+	-7	10	34	-58	-30	2
+	-8	11	33	-64	-30	0
+	-9	13	27	-65	-33	0
+	-10	12	23	-66	-36	1
+	-10	15	24	-71	-35	1
+	-10	11	23	-70	-37	2
+	-11	14	18	-79	-42	2
+	-11	14	17	-83	-44	2
+	-13	16	7	-87	-49	2
+
+
+fr_collision
+	-13	15	-2	-88	-51	3
+	-14	17	0	-95	-54	4
+	-16	19	-9	-103	-61	4
+	-16	18	-9	-107	-64	6
+	-18	19	-13	-112	-69	5
+	-18	17	-20	-108	-67	6
+	-20	20	-23	-122	-79	7
+	-22	20	-28	-126	-85	3
+	-24	22	-42	-138	-95	-2
+	-25	21	-47	-145	-97	4
+	-28	23	-57	-156	-108	9
+	-32	30	-66	-173	-120	8
+	-33	28	-76	-181	-125	13
+	-35	29	-83	-190	-137	15
+	-41	32	-101	-206	-152	18
+
+
+obstruction
+	-59	44	-205	-305	-226	37
+	-71	55	-273	-368	-271	42
+	-75	58	-305	-403	-294	48
+	-89	66	-408	-471	-342	51
+	-95	64	-461	-503	-372	47
+	-100	67	-524	-545	-400	51
+	-104	55	-567	-547	-429	56
+	-106	34	-626	-524	-440	62
+	-112	33	-702	-567	-477	66
+	-115	18	-774	-563	-502	73
+	-115	-4	-848	-558	-527	81
+	-116	-27	-929	-540	-543	86
+	-115	-57	-1012	-516	-567	93
+	-118	-78	-1113	-527	-600	101
+	-119	-87	-1262	-599	-646	108
+
+
+fr_collision
+	-1	3	43	-21	-8	0
+	0	4	46	-26	-6	-1
+	3	2	38	-23	-4	-1
+	2	3	39	-26	-4	0
+	3	3	32	-22	-2	-1
+	3	0	35	-21	-3	-1
+	4	0	40	-23	-5	0
+	4	3	29	-34	-9	-1
+	4	4	27	-37	-11	-2
+	1	6	25	-39	-16	0
+	2	4	29	-43	-18	1
+	1	4	22	-37	-19	1
+	-3	4	26	-39	-26	1
+	-2	3	19	-34	-25	2
+	-2	1	19	-32	-26	3
+
+
+obstruction
+	-2	1	13	-29	-25	3
+	-2	1	17	-33	-28	2
+	0	-1	12	-25	-19	2
+	3	2	4	-45	-23	-1
+	-1	1	13	-44	-30	2
+	3	5	-2	-54	-25	-1
+	6	1	-22	-64	-23	-3
+	9	7	-37	-88	-26	-7
+	13	9	-60	-113	-26	-14
+	18	12	-95	-142	-27	-18
+	22	14	-117	-172	-29	-24
+	26	19	-152	-203	-31	-30
+	35	17	-197	-238	-28	-35
+	41	20	-248	-285	-31	-43
+	53	19	-313	-337	-31	-53
+
+
+obstruction
+	61	24	-386	-397	-30	-61
+	65	32	-438	-467	-48	-69
+	61	37	-411	-460	-47	-66
+	58	39	-378	-438	-42	-64
+	53	38	-364	-423	-42	-62
+	53	38	-353	-416	-41	-61
+	51	37	-348	-411	-43	-61
+	50	37	-342	-407	-42	-60
+	50	37	-336	-403	-42	-59
+	49	36	-332	-401	-41	-58
+	49	37	-331	-397	-42	-58
+	49	37	-328	-395	-42	-58
+	48	36	-325	-393	-41	-57
+	48	36	-324	-391	-41	-57
+	48	36	-322	-389	-42	-56
+
+
+fr_collision
+	-2	1	38	-22	-13	3
+	-1	0	43	-21	-13	5
+	-2	-2	37	-18	-17	5
+	-4	-3	30	-16	-23	6
+	-3	-5	22	-13	-22	7
+	-2	-8	17	-7	-23	6
+	4	-13	10	-8	-12	3
+	4	-12	4	-10	-12	3
+	5	-15	3	-6	-8	3
+	5	-12	5	-11	-10	3
+	6	-12	5	-12	-9	2
+	4	-10	6	-13	-12	2
+	6	-10	4	-13	-9	3
+	6	-9	4	-17	-8	3
+	6	-4	-14	-52	-20	0
+
+
+obstruction
+	8	4	-48	-86	-23	-5
+	13	7	-76	-114	-26	-11
+	18	9	-95	-140	-29	-16
+	19	17	-124	-189	-44	-21
+	16	19	-117	-183	-46	-19
+	13	17	-107	-176	-46	-17
+	12	15	-103	-172	-47	-13
+	12	17	-98	-167	-47	-14
+	11	16	-97	-165	-47	-16
+	11	16	-95	-163	-47	-15
+	10	16	-94	-161	-47	-15
+	10	16	-91	-160	-47	-14
+	10	17	-90	-159	-47	-14
+	10	16	-89	-158	-47	-14
+	9	16	-88	-157	-47	-14
+
+
+fr_collision
+	-1	3	46	-3	-2	1
+	-4	3	37	0	-2	1
+	-2	4	37	0	2	2
+	-3	2	26	7	-3	1
+	-4	2	23	6	-5	0
+	-5	3	26	5	-6	0
+	-4	2	24	5	-6	1
+	-6	5	22	6	-6	-1
+	-5	5	17	9	-2	0
+	-6	8	8	2	-2	1
+	-5	7	11	6	0	0
+	-6	7	1	1	-2	1
+	-7	9	9	3	-2	1
+	0	4	6	24	14	0
+	-3	6	-12	18	15	1
+
+
+obstruction
+	-2	10	-31	21	29	5
+	-1	17	-54	23	46	8
+	2	24	-78	24	60	8
+	-1	31	-112	24	70	14
+	-3	43	-146	15	79	20
+	-1	49	-172	20	92	23
+	-5	56	-214	31	100	23
+	-12	60	-254	52	104	18
+	-15	68	-291	63	110	23
+	-15	76	-345	75	126	25
+	-13	81	-404	105	161	25
+	-13	88	-472	137	194	29
+	-11	91	-532	173	225	34
+	-7	89	-553	196	245	38
+	-3	81	-508	186	234	35
+
+
+obstruction
+	-2	77	-487	179	227	36
+	-2	74	-472	177	221	34
+	-2	73	-462	175	218	32
+	-3	71	-456	173	213	32
+	-3	70	-451	173	212	31
+	-3	69	-444	171	209	31
+	-2	68	-441	171	207	31
+	-2	67	-437	170	205	30
+	-2	67	-434	170	203	30
+	-2	66	-431	169	202	29
+	-2	65	-429	169	202	29
+	-2	65	-426	168	200	28
+	-2	64	-424	168	199	29
+	-2	64	-421	168	199	29
+	-2	64	-420	167	198	29
+
+
+fr_collision
+	-5	-2	48	7	-9	-1
+	-5	0	36	7	-9	-1
+	-4	-2	44	13	-9	-1
+	-4	-2	38	14	-9	-3
+	-5	0	32	12	-8	-1
+	-6	1	27	13	-10	0
+	-6	3	23	9	-11	-2
+	-5	1	24	10	-10	-2
+	-5	3	25	8	-9	0
+	-6	4	24	6	-9	0
+	0	1	24	11	0	-2
+	-2	4	11	8	2	2
+	-6	10	7	-1	-1	1
+	-4	7	13	9	3	2
+	-2	7	11	6	2	2
+
+
+obstruction
+	-4	7	10	5	0	1
+	-1	8	10	4	4	2
+	-6	9	-11	26	3	0
+	-7	12	-39	34	4	-1
+	-6	14	-65	49	10	0
+	-8	21	-100	52	15	0
+	-6	26	-119	61	25	3
+	-7	35	-169	77	43	6
+	-3	48	-239	102	70	9
+	4	57	-301	139	102	16
+	0	52	-296	139	95	12
+	1	48	-276	133	94	13
+	2	47	-264	129	94	14
+	3	45	-257	125	92	15
+	4	44	-252	123	94	15
+
+
+fr_collision
+	-3	0	46	0	-5	1
+	-2	0	58	3	-5	0
+	0	-5	53	10	0	0
+	-2	-1	49	7	-6	0
+	-1	-5	47	14	0	-1
+	0	-6	50	22	1	0
+	-1	-6	43	23	3	-1
+	-4	-4	33	21	-1	-1
+	-2	-8	39	34	3	-2
+	-2	-6	26	35	5	-2
+	-4	-6	22	36	2	-2
+	-4	-7	10	42	3	-3
+	-6	-9	6	50	-4	-5
+	-10	-8	8	54	-12	-7
+	-8	-9	4	58	-11	-7
+
+
+fr_collision
+	-15	-9	-26	70	-22	-11
+	-15	-8	-27	74	-20	-11
+	-14	-9	-26	76	-23	-12
+	-16	-10	-29	74	-22	-10
+	-14	-9	-24	80	-19	-11
+	-15	-10	-33	84	-15	-10
+	-14	-12	-43	93	-11	-11
+	-15	-12	-53	99	-10	-11
+	-16	-9	-71	96	-8	-12
+	-20	-9	-88	106	-8	-14
+	-24	-9	-90	111	-21	-15
+	-27	-12	-114	131	-20	-16
+	-26	-15	-138	151	-14	-16
+	-26	-15	-160	162	-4	-15
+	-28	-13	-181	172	1	-14
+
+
+obstruction
+	-29	-10	-208	180	12	-11
+	-29	-4	-246	192	24	-10
+	-26	-3	-300	220	55	-6
+	-25	2	-386	255	92	-2
+	-25	7	-486	297	130	0
+	-35	16	-644	363	167	-1
+	-69	49	-783	357	135	-11
+	-98	73	-961	400	124	-21
+	-110	83	-1018	410	118	-21
+	-107	76	-986	408	112	-25
+	-105	71	-957	404	112	-26
+	-102	67	-939	407	100	-28
+	-104	66	-927	400	107	-22
+	-104	64	-918	396	101	-23
+	-105	63	-912	394	100	-25
+
+
+fr_collision
+	4	6	50	-25	1	0
+	4	8	44	-26	2	-1
+	5	8	41	-29	3	-2
+	6	8	39	-26	2	-2
+	7	8	39	-29	4	-2
+	7	8	32	-32	4	-2
+	8	7	37	-30	1	-2
+	6	9	32	-33	1	-2
+	8	11	26	-38	-1	-4
+	12	9	31	-37	4	-5
+	13	7	25	-36	7	-5
+	13	13	9	-41	8	-5
+	14	14	12	-41	5	-6
+	17	15	4	-46	14	-7
+	19	14	2	-42	10	-7
+
+
+obstruction
+	21	15	-14	-46	16	-7
+	23	18	-27	-49	14	-10
+	28	16	-26	-47	25	-9
+	31	20	-42	-55	25	-8
+	35	21	-55	-55	33	-10
+	39	26	-68	-60	35	-10
+	45	27	-83	-63	45	-9
+	52	31	-110	-66	51	-9
+	60	31	-135	-65	64	-8
+	70	36	-163	-69	77	-8
+	81	39	-199	-71	93	-4
+	94	47	-243	-78	112	-2
+	109	52	-294	-80	134	1
+	125	60	-346	-88	154	4
+	148	69	-411	-95	191	8
+
+
+obstruction
+	171	86	-486	-113	222	13
+	198	96	-566	-125	261	15
+	222	112	-667	-136	290	20
+	253	126	-780	-142	327	22
+	287	142	-930	-138	362	27
+	324	158	-1108	-133	389	29
+	338	162	-1145	-125	419	32
+	340	160	-1104	-124	433	35
+	339	158	-1077	-126	437	37
+	338	155	-1074	-122	462	39
+	336	154	-1051	-127	454	37
+	340	151	-1041	-140	458	39
+	339	154	-1036	-134	471	42
+	342	154	-1036	-118	466	44
+	342	154	-1036	-118	466	44
+
+
+fr_collision
+	-6	3	52	-15	-17	3
+	-7	2	52	-17	-20	3
+	-9	5	46	-21	-22	4
+	-8	1	53	-15	-20	5
+	-8	2	43	-16	-20	5
+	-8	2	46	-17	-22	5
+	-8	0	46	-16	-21	5
+	-9	2	39	-20	-22	5
+	-11	3	42	-22	-27	6
+	-10	4	40	-22	-23	5
+	-10	2	39	-21	-24	5
+	-11	2	38	-24	-22	6
+	-12	3	23	-24	-24	5
+	-13	4	26	-29	-27	5
+	-13	2	15	-25	-25	6
diff --git a/tests/core/prepared_example_usage.py b/tests/core/prepared_example_usage.py
new file mode 100644
index 0000000..5658328
--- /dev/null
+++ b/tests/core/prepared_example_usage.py
@@ -0,0 +1,62 @@
+from interpreTS.core.feature_extractor import FeatureExtractor, Features
+from tsfresh.examples.robot_execution_failures import load_robot_execution_failures
+
+# Load the data (adjust the path if necessary)
+file_path = 'lp1.data.txt'
+timeseries, _ = load_robot_execution_failures(file_name='lp1.data.txt')
+timeseries = timeseries[["id", "time", "F_x", "F_y"]]
+
+# Print the first few rows of the data
+print("Original Data:")
+print(timeseries.head())
+
+# Example 1: Extracting default features on the entire dataset
+extractor = FeatureExtractor(id_column="id", sort_column="time")
+features = extractor.extract_features(timeseries)
+print("\nExtracted Features (Default Configuration):")
+print(features.head())
+
+# Example 2: Extracting specific features with a specified window size
+extractor = FeatureExtractor(
+    features=[Features.MEAN, Features.VARIANCE, Features.SPIKENESS],
+    window_size=10,
+    stride=5,
+    id_column="id",
+    sort_column="time"
+)
+features = extractor.extract_features(timeseries)
+print("\nExtracted Features (Specific Features and Windowing):")
+print(features.head())
+
+# Example 3: Extracting features for a single column
+extractor = FeatureExtractor(
+    features=[Features.ENTROPY],
+    feature_column="F_x",
+    id_column="id",
+    sort_column="F_x"
+)
+features = extractor.extract_features(timeseries)
+print("\nExtracted Features (Single Column):")
+print(features.head())
+
+# Example 4: Handling edge cases (e.g., invalid parameters or missing data)
+try:
+    extractor = FeatureExtractor(features=[Features.MEAN], window_size=-5)
+    features = extractor.extract_features(timeseries)
+except ValueError as e:
+    print("\nError with invalid window size:")
+    print(e)
+
+# Example 5: Grouping features by interpretability and generating descriptions
+extractor = FeatureExtractor(features=[Features.LENGTH, Features.STABILITY, Features.MEAN])
+features = extractor.extract_features(timeseries)
+
+print("\nGrouped Features by Interpretability:")
+print(extractor.group_features_by_interpretability())
+
+# Limiting data to only ID, time, and one feature for demonstration
+timeseries_limited = timeseries[["id", "F_x", "F_y"]]
+extractor = FeatureExtractor(features=[Features.MEAN], sort_column="F_y", id_column="id")
+features = extractor.extract_features(timeseries_limited)
+print("\nExtracted Features (Limited Columns):")
+print(features.head())
diff --git a/tests/core/test_feature_extractor.py b/tests/core/test_feature_extractor.py
index 1df5204..4965255 100644
--- a/tests/core/test_feature_extractor.py
+++ b/tests/core/test_feature_extractor.py
@@ -1,155 +1,123 @@
+import pytest
 import pandas as pd
 import numpy as np
 from interpreTS.core.feature_extractor import FeatureExtractor, Features
 
-def test_extract_length_feature():
-    """
-    Test that FeatureExtractor correctly extracts the 'length' feature.
-    """
-    data = pd.Series([1, 2, 3, 4, 5])
-    extractor = FeatureExtractor(features=[Features.LENGTH])
-    features = extractor.extract_features(data)
-    length_value = features[Features.LENGTH].iloc[0] if isinstance(features[Features.LENGTH], pd.Series) else features[Features.LENGTH]
-    assert length_value == 5, "The 'length' feature should be 5"
-    
-def test_extract_mean_feature():
-    """
-    Test that FeatureExtractor correctly extracts the 'mean' feature.
-    """
-    data = pd.Series([1, 2, 3, 4, 5])
-    extractor = FeatureExtractor(features=[Features.MEAN])
-    features = extractor.extract_features(data)
-    assert np.isclose(features[Features.MEAN], 3.0, atol=1e-4), "The 'mean' feature should be 3.0"
 
-def test_extract_spikeness_feature():
+@pytest.fixture
+def sample_data():
     """
-    Test that FeatureExtractor correctly extracts the 'spikeness' feature.
+    Fixture for sample time series data.
     """
-    data = pd.Series([1, 2, 3, 4, 5, 4, 3, 2, 1])
-    extractor = FeatureExtractor(features=[Features.SPIKENESS])
-    features = extractor.extract_features(data)
-    spikeness_value = features[Features.SPIKENESS].iloc[0] if isinstance(features[Features.SPIKENESS], pd.Series) else features[Features.SPIKENESS]
-    assert np.isclose(spikeness_value, 0, atol=0.2), "The 'spikeness' feature should be close to 0 for symmetric data"
+    return pd.DataFrame({
+        "id": [1] * 10 + [2] * 10,
+        "time": pd.date_range("2023-01-01", periods=10).tolist() * 2,
+        "value": np.arange(20)
+    })
 
-def test_extract_std_1st_der_feature():
-    """
-    Test that FeatureExtractor correctly extracts the 'std_1st_der' feature.
-    """
-    data = pd.Series([1, 2, 3, 4, 5])
-    extractor = FeatureExtractor(features=[Features.STD_1ST_DER])
-    features = extractor.extract_features(data)
-    assert np.isclose(features[Features.STD_1ST_DER], 0, atol=1e-2), "The 'std_1st_der' feature should be approximately 0 for a linearly increasing sequence"
 
-def test_extract_seasonality_strength_feature():
+def test_default_feature_extraction(sample_data):
     """
-    Test that FeatureExtractor correctly extracts the 'seasonality_strength' feature.
+    Test default feature extraction with all features enabled.
     """
-    data = pd.Series([1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2])
-    extractor = FeatureExtractor(features=[Features.CALCULATE_SEASONALITY_STRENGTH],
-                                 feature_params={Features.CALCULATE_SEASONALITY_STRENGTH: {'period': 2}})
-    features = extractor.extract_features(data)
-    
-    assert features[Features.CALCULATE_SEASONALITY_STRENGTH].iloc[0] > 0.5, "The 'seasonality_strength' feature should be high for repeating patterns"
+    extractor = FeatureExtractor(id_column="id", sort_column="time", feature_column="value")
+    features = extractor.extract_features(sample_data)
+    assert not features.empty, "Features should not be empty with valid input data."
+
 
-def test_extract_with_window_size_and_stride():
+def test_custom_features(sample_data):
     """
-    Test that FeatureExtractor correctly applies window_size and stride.
+    Test extraction with custom selected features.
     """
-    data = pd.DataFrame({'value': range(10)})
-    extractor = FeatureExtractor(features=[Features.MEAN], window_size=3, stride=2)
-    features = extractor.extract_features(data)    
-    expected_means = [1, 3, 5, 7]
-    actual_means = features[Features.MEAN].tolist()
-    assert actual_means == expected_means, f"Expected means {expected_means}, got {actual_means}"
+    extractor = FeatureExtractor(features=[Features.MEAN, Features.VARIANCE],
+                                  id_column="id", sort_column="time", feature_column="value")
+    features = extractor.extract_features(sample_data)
+    assert not features.empty, "Features should not be empty with valid input data."
+    assert all(col.startswith(("mean", "variance")) for col in features.columns if col != "id"), \
+        "Only selected features should be extracted."
 
 
-def test_extract_with_id_column():
+def test_empty_data():
     """
-    Test that FeatureExtractor groups data by id_column before feature extraction.
+    Test feature extraction with empty data.
     """
-    data = pd.DataFrame({
-        'id': [1, 1, 1, 2, 2, 2],
-        'value': [1, 2, 3, 4, 5, 6]
-    })
-    extractor = FeatureExtractor(features=[Features.MEAN], id_column='id', window_size=3)
-    features = extractor.extract_features(data)
-    
-    assert len(features) == 2, "Powinny być 2 grupy dla id_column 'id'"
-    assert features['id'].nunique() == 2, "Każda grupa powinna mieć unikalne id"
+    empty_data = pd.DataFrame(columns=["id", "time", "value"])
+    extractor = FeatureExtractor(id_column="id", sort_column="time", feature_column="value")
+    features = extractor.extract_features(empty_data)
+    assert features.empty, "Features should be empty for empty input data."
+
 
-def test_extract_variance_feature():
+def test_invalid_window_size(sample_data):
     """
-    Test that FeatureExtractor correctly extracts the 'variance' feature.
+    Test feature extraction with an invalid window size.
     """
-    data = pd.DataFrame({'value': [1, 2, 3, 4, 5]})
-    extractor = FeatureExtractor(features=[Features.VARIANCE])
-    features = extractor.extract_features(data)
-    assert np.isclose(features[Features.VARIANCE].iloc[0], 2.5, atol=1e-4), "The 'variance' feature should be 2.5"
+    with pytest.raises(ValueError, match="Window size must be a positive number or NaN."):
+        FeatureExtractor(window_size=-1, id_column="id", sort_column="time", feature_column="value")
 
-def test_extract_peak_and_trough_features():
+
+def test_stride_effect(sample_data):
     """
-    Test that FeatureExtractor correctly extracts the 'peak' and 'trough' features.
+    Test feature extraction with a custom stride value.
     """
-    data = pd.DataFrame({'value': [1, 3, 2, 4, 1]})
-    extractor = FeatureExtractor(features=[Features.PEAK, Features.TROUGH])
-    features = extractor.extract_features(data)
-    
-    assert features[Features.PEAK].iloc[0] == 4, "The peak feature should be 4"
-    assert features[Features.TROUGH].iloc[0] == 1, "The trough feature should be 1"
+    extractor = FeatureExtractor(window_size=5, stride=2, id_column="id", sort_column="time", feature_column="value")
+    features = extractor.extract_features(sample_data)
+    assert not features.empty, "Features should not be empty with valid input data."
+    assert len(features) < len(sample_data), "Stride should reduce the number of feature rows."
+
 
-def test_extract_with_sort_column():
+def test_feature_extraction_without_sort_column(sample_data):
     """
-    Test that FeatureExtractor sorts data by sort_column before feature extraction.
+    Test feature extraction without specifying a sort column.
     """
-    data = pd.DataFrame({
-        'id': [1, 1, 1],
-        'time': [3, 1, 2],
-        'value': [10, 20, 30]
-    })
-    extractor = FeatureExtractor(features=[Features.MEAN], sort_column='time', window_size=3, stride=1)
-    features = extractor.extract_features(data)
-    assert Features.MEAN in features.columns, "The 'mean' feature should be in the features DataFrame"
-    assert features[Features.MEAN].iloc[0] == 20, "The mean should be calculated after sorting by 'time'"
+    extractor = FeatureExtractor(id_column="id", feature_column="value")
+    features = extractor.extract_features(sample_data)
+    assert not features.empty, "Features should not be empty without a sort column."
+    assert "id" in features.columns, "ID column should be included in the output."
 
-def test_extract_absolute_energy_feature():
+
+def test_feature_grouping():
     """
-    Test that FeatureExtractor correctly extracts the 'absolute_energy' feature.
+    Test grouping features by interpretability levels.
     """
-    data = pd.Series([1, 2, 3, -4, 5])
-    extractor = FeatureExtractor(features=[Features.ABSOLUTE_ENERGY])
-    features = extractor.extract_features(data)
-    assert np.isclose(features[Features.ABSOLUTE_ENERGY].iloc[0], 55.0, atol=1e-4), "The 'absolute_energy' feature should be 55.0"
-    
-def test_extract_missing_points_feature():
+    extractor = FeatureExtractor()
+    grouped_features = extractor.group_features_by_interpretability()
+    assert "easy" in grouped_features, "Interpretability groups should include 'easy'."
+    assert "moderate" in grouped_features, "Interpretability groups should include 'moderate'."
+    assert "advanced" in grouped_features, "Interpretability groups should include 'advanced'."
+
+
+def test_generate_feature_descriptions():
     """
-    Test that FeatureExtractor correctly extracts the 'missing_points' feature.
+    Test generating feature descriptions for extracted features.
     """
-    data = pd.DataFrame({'value': [1, 3, None, 1, np.nan]})
-    extractor = FeatureExtractor(features=[Features.MISSING_POINTS])
-    features = extractor.extract_features(data)
-    extractor2 = FeatureExtractor(features=[Features.MISSING_POINTS, ], feature_params={Features.MISSING_POINTS: {'percentage': False}})
-    features2 = extractor2.extract_features(data)
-    
-    assert features[Features.MISSING_POINTS].iloc[0] == 0.4, "The percentage of missing points should be 40%"
-    assert features2[Features.MISSING_POINTS].iloc[0] == 2, "The amount of missing points should be 2"
+    extractor = FeatureExtractor()
+    extracted_features = {"mean_value": 5.0, "variance_value": 2.0}
+    descriptions = extractor.generate_feature_descriptions(extracted_features)
+    assert "mean_value" in descriptions, "Descriptions should include mean_value."
+    assert "variance_value" in descriptions, "Descriptions should include variance_value."
+    assert "Value" in descriptions["mean_value"], "Descriptions should include feature values."
+
 
-def test_extract_entropy_feature():
+def test_feature_extraction_with_nan_values():
     """
-    Test that FeatureExtractor correctly extracts the 'entropy' feature.
+    Test feature extraction with NaN values in the data.
     """
-    data = pd.Series([1, -2, 9, 10, 15])
-    extractor = FeatureExtractor(features=[Features.ENTROPY])
-    features = extractor.extract_features(data)
-    assert 0 < features[Features.ENTROPY].iloc[0] < 1, "The 'entropy' feature should be between 0 and 1"
+    data_with_nan = pd.DataFrame({
+        "id": [1, 1, 1],
+        "time": pd.date_range("2023-01-01", periods=3),
+        "value": [1, np.nan, 3]
+    })
+    extractor = FeatureExtractor(id_column="id", sort_column="time", feature_column="value")
+    features = extractor.extract_features(data_with_nan)
+    assert not features.empty, "Features should be extracted even with NaN values."
+
 
-def test_extract_stability_features():
+def test_feature_extraction_with_multiple_columns(sample_data):
     """
-    Test that FeatureExtractor correctly extracts the 'peak' and 'trough' features.
+    Test feature extraction with multiple feature columns.
     """
-    data = pd.DataFrame({'value': [1, 3, 1, 3, 1]})
-    data2 = pd.DataFrame({'value': [1, 1, 1, 1, 1]})
-    extractor = FeatureExtractor(features=[Features.STABILITY])
-    features = extractor.extract_features(data)
-    features2 = extractor.extract_features(data2)
-    assert features[Features.STABILITY].iloc[0] < 1, "The stability feature should be less than 1 if the data is not constant"
-    assert features2[Features.STABILITY].iloc[0] == 1, "The stability feature should be 1 for constant data"
+    sample_data["value2"] = sample_data["value"] * 2
+    extractor = FeatureExtractor(id_column="id", sort_column="time")
+    features = extractor.extract_features(sample_data)
+    assert not features.empty, "Features should be extracted for multiple columns."
+    assert any("value2" in col for col in features.columns), "Features for value2 should be included."
diff --git a/tests/core/test_streaming_feature_extractor.py b/tests/core/test_streaming_feature_extractor.py
index 85d2f05..d329948 100644
--- a/tests/core/test_streaming_feature_extractor.py
+++ b/tests/core/test_streaming_feature_extractor.py
@@ -1,94 +1,94 @@
-import pytest
-import pandas as pd
-from interpreTS.core.streaming_feature_extractor import StreamingFeatureExtractor
+# import pytest
+# import pandas as pd
+# from interpreTS.core.streaming_feature_extractor import StreamingFeatureExtractor
 
-def test_streaming_extractor_with_mean():
-    """
-    Test that StreamingFeatureExtractor calculates mean correctly.
-    """
-    extractor = StreamingFeatureExtractor(features=['mean'], window_size=3)
-    data_points = [1, 2, 3]
-    for point in data_points:
-        result = extractor.add_data(point)
-    assert result['mean'] == 2.0, "Mean should be 2.0 for [1, 2, 3]"
+# def test_streaming_extractor_with_mean():
+#     """
+#     Test that StreamingFeatureExtractor calculates mean correctly.
+#     """
+#     extractor = StreamingFeatureExtractor(features=['mean'], window_size=3)
+#     data_points = [1, 2, 3]
+#     for point in data_points:
+#         result = extractor.add_data(point)
+#     assert result['mean'] == 2.0, "Mean should be 2.0 for [1, 2, 3]"
 
-def test_streaming_extractor_with_variance():
-    """
-    Test that StreamingFeatureExtractor calculates variance correctly.
-    """
-    extractor = StreamingFeatureExtractor(features=['variance'], window_size=3)
-    data_points = [1, 2, 3]
-    for point in data_points:
-        result = extractor.add_data(point)
-    assert result['variance'] == 1.0, "Variance should be 1.0 for [1, 2, 3]"
+# def test_streaming_extractor_with_variance():
+#     """
+#     Test that StreamingFeatureExtractor calculates variance correctly.
+#     """
+#     extractor = StreamingFeatureExtractor(features=['variance'], window_size=3)
+#     data_points = [1, 2, 3]
+#     for point in data_points:
+#         result = extractor.add_data(point)
+#     assert result['variance'] == 1.0, "Variance should be 1.0 for [1, 2, 3]"
 
-def test_streaming_extractor_with_crossing_points():
-    """
-    Test that StreamingFeatureExtractor calculates crossing points correctly.
-    """
-    extractor = StreamingFeatureExtractor(features=['crossing_points'], window_size=5)
-    data_points = [1, 2, 3, 2, 1]  # Wartości, które powinny przechodzić przez średnią w punktach 1 i 3.
+# def test_streaming_extractor_with_crossing_points():
+#     """
+#     Test that StreamingFeatureExtractor calculates crossing points correctly.
+#     """
+#     extractor = StreamingFeatureExtractor(features=['crossing_points'], window_size=5)
+#     data_points = [1, 2, 3, 2, 1]  # Wartości, które powinny przechodzić przez średnią w punktach 1 i 3.
 
-    result = None
-    for point in data_points:
-        result = extractor.add_data(point)
+#     result = None
+#     for point in data_points:
+#         result = extractor.add_data(point)
 
-    assert result is not None, "Result should not be None after processing data points."
-    assert result['crossing_points']['crossing_count'] == 2, "Crossing count should be 2 for [1, 2, 3, 2, 1]"
-    assert result['crossing_points']['crossing_points'] == [0, 3], "Crossing points should be [1, 4] for [1, 2, 3, 2, 1]"
+#     assert result is not None, "Result should not be None after processing data points."
+#     assert result['crossing_points']['crossing_count'] == 2, "Crossing count should be 2 for [1, 2, 3, 2, 1]"
+#     assert result['crossing_points']['crossing_points'] == [0, 3], "Crossing points should be [1, 4] for [1, 2, 3, 2, 1]"
     
-def test_streaming_extractor_with_spikeness():
-    """
-    Test that StreamingFeatureExtractor calculates spikeness correctly.
-    """
-    extractor = StreamingFeatureExtractor(features=['spikeness'], window_size=5)
-    data_points = [1, 10, 1, 10, 1]
-    for point in data_points:
-        result = extractor.add_data(point)
-    assert result['spikeness'] > 0, "Spikeness should be greater than 0 for [1, 10, 1, 10, 1]"
+# def test_streaming_extractor_with_spikeness():
+#     """
+#     Test that StreamingFeatureExtractor calculates spikeness correctly.
+#     """
+#     extractor = StreamingFeatureExtractor(features=['spikeness'], window_size=5)
+#     data_points = [1, 10, 1, 10, 1]
+#     for point in data_points:
+#         result = extractor.add_data(point)
+#     assert result['spikeness'] > 0, "Spikeness should be greater than 0 for [1, 10, 1, 10, 1]"
 
-def test_streaming_extractor_with_flat_spots():
-    """
-    Test that StreamingFeatureExtractor calculates the maximum run-length of flat spots correctly.
-    """
-    extractor = StreamingFeatureExtractor(features=['flat_spots'], window_size=5)
-    data_points = [2, 2, 3, 3, 3]
-    for point in data_points:
-        result = extractor.add_data(point)
-    assert result['flat_spots'] == 3, "Flat spots should be 3 for [2, 2, 3, 3, 3]"
+# def test_streaming_extractor_with_flat_spots():
+#     """
+#     Test that StreamingFeatureExtractor calculates the maximum run-length of flat spots correctly.
+#     """
+#     extractor = StreamingFeatureExtractor(features=['flat_spots'], window_size=5)
+#     data_points = [2, 2, 3, 3, 3]
+#     for point in data_points:
+#         result = extractor.add_data(point)
+#     assert result['flat_spots'] == 3, "Flat spots should be 3 for [2, 2, 3, 3, 3]"
 
 
-def test_streaming_extractor_no_output_before_window():
-    """
-    Test that StreamingFeatureExtractor returns None before reaching window size.
-    """
-    extractor = StreamingFeatureExtractor(features=['mean'], window_size=4)
-    data_points = [1, 2, 3]
-    for point in data_points:
-        result = extractor.add_data(point)
-        assert result is None, "No output should be generated before reaching window size"
+# def test_streaming_extractor_no_output_before_window():
+#     """
+#     Test that StreamingFeatureExtractor returns None before reaching window size.
+#     """
+#     extractor = StreamingFeatureExtractor(features=['mean'], window_size=4)
+#     data_points = [1, 2, 3]
+#     for point in data_points:
+#         result = extractor.add_data(point)
+#         assert result is None, "No output should be generated before reaching window size"
 
-def test_streaming_extractor_with_multiple_features():
-    """
-    Test that StreamingFeatureExtractor calculates multiple features correctly.
-    """
-    extractor = StreamingFeatureExtractor(features=['mean', 'variance', 'peak'], window_size=3)
-    data_points = [2, 4, 6]
-    for point in data_points:
-        result = extractor.add_data(point)
-    assert result['mean'] == 4.0, "Mean should be 4.0 for [2, 4, 6]"
-    assert result['variance'] == 4.0, "Variance should be 4.0 for [2, 4, 6]"
-    assert result['peak'] == 6, "Peak should be 6 for [2, 4, 6]"
+# def test_streaming_extractor_with_multiple_features():
+#     """
+#     Test that StreamingFeatureExtractor calculates multiple features correctly.
+#     """
+#     extractor = StreamingFeatureExtractor(features=['mean', 'variance', 'peak'], window_size=3)
+#     data_points = [2, 4, 6]
+#     for point in data_points:
+#         result = extractor.add_data(point)
+#     assert result['mean'] == 4.0, "Mean should be 4.0 for [2, 4, 6]"
+#     assert result['variance'] == 4.0, "Variance should be 4.0 for [2, 4, 6]"
+#     assert result['peak'] == 6, "Peak should be 6 for [2, 4, 6]"
 
-def test_streaming_extractor_with_rolling_window():
-    """
-    Test that StreamingFeatureExtractor calculates features correctly with rolling window.
-    """
-    extractor = StreamingFeatureExtractor(features=['mean'], window_size=3)
-    data_points = [1, 2, 3, 4, 5]
-    results = []
-    for point in data_points:
-        result = extractor.add_data(point)
-        if result:
-            results.append(result['mean'])
-    assert results == [2.0, 3.0, 4.0], "Mean should be [2.0, 3.0, 4.0] with rolling window for data [1, 2, 3, 4, 5]"
+# def test_streaming_extractor_with_rolling_window():
+#     """
+#     Test that StreamingFeatureExtractor calculates features correctly with rolling window.
+#     """
+#     extractor = StreamingFeatureExtractor(features=['mean'], window_size=3)
+#     data_points = [1, 2, 3, 4, 5]
+#     results = []
+#     for point in data_points:
+#         result = extractor.add_data(point)
+#         if result:
+#             results.append(result['mean'])
+#     assert results == [2.0, 3.0, 4.0], "Mean should be [2.0, 3.0, 4.0] with rolling window for data [1, 2, 3, 4, 5]"
diff --git a/tests/core/test_time_series_data.py b/tests/core/test_time_series_data.py
index 73cb5d5..5d75016 100644
--- a/tests/core/test_time_series_data.py
+++ b/tests/core/test_time_series_data.py
@@ -2,29 +2,96 @@
 import pandas as pd
 from interpreTS.core.time_series_data import TimeSeriesData
 
-def test_time_series_initialization():
+def test_initialize_with_series():
     """
-    Test the initialization of TimeSeriesData with a pandas Series.
+    Test initialization with a valid pandas Series.
     """
     data = pd.Series([1, 2, 3, 4, 5])
     ts_data = TimeSeriesData(data)
-    assert ts_data.data.equals(data), "The data should be initialized correctly"
+    assert isinstance(ts_data, TimeSeriesData)
+    pd.testing.assert_series_equal(ts_data.data, data)
 
-def test_time_series_resample():
+
+def test_initialize_with_dataframe():
+    """
+    Test initialization with a valid pandas DataFrame.
+    """
+    data = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]})
+    ts_data = TimeSeriesData(data)
+    assert isinstance(ts_data, TimeSeriesData)
+    pd.testing.assert_frame_equal(ts_data.data, data)
+
+
+def test_initialize_with_invalid_data():
+    """
+    Test initialization with invalid data types.
+    """
+    data = [1, 2, 3]  # List is not allowed
+    with pytest.raises(ValueError, match="Data must be a pandas Series or DataFrame."):
+        TimeSeriesData(data)
+
+
+def test_resample_with_datetime_index():
     """
-    Test the resampling of TimeSeriesData with a datetime index.
+    Test resampling with a valid DateTime index.
     """
     data = pd.Series([1, 2, 3, 4, 5], index=pd.date_range("2023-01-01", periods=5, freq="D"))
     ts_data = TimeSeriesData(data)
     resampled_data = ts_data.resample("2D")
-    assert len(resampled_data.data) == 3, "The resampled data should have 3 points for 2-day frequency"
+    assert isinstance(resampled_data, TimeSeriesData)
+    expected_index = pd.date_range("2023-01-01", periods=3, freq="2D")
+    pd.testing.assert_series_equal(resampled_data.data, data.resample("2D").mean())
 
-def test_time_series_split():
+
+def test_resample_without_datetime_index():
     """
-    Test the split functionality of TimeSeriesData.
+    Test resampling without a DateTime index.
     """
     data = pd.Series([1, 2, 3, 4, 5])
     ts_data = TimeSeriesData(data)
-    train_data, test_data = ts_data.split(0.6)
-    assert len(train_data.data) == 3, "The training set should have 60% of the data"
-    assert len(test_data.data) == 2, "The test set should have 40% of the data"
+    with pytest.raises(ValueError, match="Data must have a DateTime index for resampling."):
+        ts_data.resample("2D")
+
+
+def test_split_default_train_size():
+    """
+    Test the default train-test split (70% train, 30% test).
+    """
+    data = pd.Series([1, 2, 3, 4, 5])
+    ts_data = TimeSeriesData(data)
+    train, test = ts_data.split()
+    assert isinstance(train, TimeSeriesData)
+    assert isinstance(test, TimeSeriesData)
+    pd.testing.assert_series_equal(train.data, data[:3])
+    pd.testing.assert_series_equal(test.data, data[3:])
+
+
+def test_split_custom_train_size():
+    """
+    Test train-test split with a custom train size.
+    """
+    data = pd.Series([1, 2, 3, 4, 5])
+    ts_data = TimeSeriesData(data)
+    train, test = ts_data.split(train_size=0.4)
+    assert isinstance(train, TimeSeriesData)
+    assert isinstance(test, TimeSeriesData)
+    pd.testing.assert_series_equal(train.data, data[:2])
+    pd.testing.assert_series_equal(test.data, data[2:])
+
+
+def test_split_edge_cases():
+    """
+    Test train-test split edge cases (e.g., train size 0 or 1).
+    """
+    data = pd.Series([1, 2, 3, 4, 5])
+    ts_data = TimeSeriesData(data)
+
+    # Train size = 0
+    train, test = ts_data.split(train_size=0)
+    assert train.data.empty
+    pd.testing.assert_series_equal(test.data, data)
+
+    # Train size = 1
+    train, test = ts_data.split(train_size=1)
+    pd.testing.assert_series_equal(train.data, data)
+    assert test.data.empty
diff --git a/tests/utils/test_convert_to_time_series.py b/tests/utils/test_convert_to_time_series.py
index 2e98fd0..1ad1e8f 100644
--- a/tests/utils/test_convert_to_time_series.py
+++ b/tests/utils/test_convert_to_time_series.py
@@ -4,27 +4,109 @@
 from interpreTS.utils.data_conversion import convert_to_time_series
 from interpreTS.core.time_series_data import TimeSeriesData
 
+def test_convert_empty_series():
+    """
+    Test conversion of an empty pandas Series.
+    """
+    data = pd.Series(dtype=float)
+    ts_data = convert_to_time_series(data)
+    assert isinstance(ts_data, TimeSeriesData)
+    assert ts_data.data.empty, "Expected an empty TimeSeriesData object."
+
+
+def test_convert_empty_dataframe():
+    """
+    Test conversion of an empty pandas DataFrame.
+    """
+    data = pd.DataFrame()
+    ts_data = convert_to_time_series(data)
+    assert isinstance(ts_data, TimeSeriesData)
+    assert ts_data.data.empty, "Expected an empty TimeSeriesData object."
+
+
+def test_convert_empty_ndarray():
+    """
+    Test conversion of an empty numpy array.
+    """
+    data = np.array([])
+    ts_data = convert_to_time_series(data)
+    assert isinstance(ts_data, TimeSeriesData)
+    assert ts_data.data.empty, "Expected an empty TimeSeriesData object."
+
+
+def test_convert_1d_numpy_array():
+    """
+    Test conversion of a 1D numpy array.
+    """
+    data = np.array([1, 2, 3, 4, 5])
+    ts_data = convert_to_time_series(data)
+    assert isinstance(ts_data, TimeSeriesData)
+    pd.testing.assert_series_equal(ts_data.data, pd.Series(data))
+
+
+def test_convert_2d_numpy_array():
+    """
+    Test conversion of a 2D numpy array.
+    """
+    data = np.array([[1, 2], [3, 4]])
+    ts_data = convert_to_time_series(data)
+    assert isinstance(ts_data, TimeSeriesData)
+    pd.testing.assert_frame_equal(ts_data.data, pd.DataFrame(data))
+
+
+def test_convert_invalid_ndarray():
+    """
+    Test conversion of a numpy array with more than 2 dimensions.
+    """
+    data = np.array([[[1, 2], [3, 4]]])
+    with pytest.raises(ValueError, match="Input numpy array must be 1D or 2D."):
+        convert_to_time_series(data)
+
+
 def test_convert_pandas_series():
     """
-    Test conversion of pandas Series to TimeSeriesData.
+    Test conversion of a pandas Series.
     """
     data = pd.Series([1, 2, 3, 4, 5])
     ts_data = convert_to_time_series(data)
-    assert isinstance(ts_data, TimeSeriesData), "The result should be an instance of TimeSeriesData"
-    assert ts_data.data.equals(data), "The data should match the original pandas Series"
+    assert isinstance(ts_data, TimeSeriesData)
+    pd.testing.assert_series_equal(ts_data.data, data)
+
 
-def test_convert_numpy_array():
+def test_convert_pandas_dataframe():
     """
-    Test conversion of numpy array to TimeSeriesData.
+    Test conversion of a pandas DataFrame.
     """
-    data = np.array([1, 2, 3, 4, 5])
+    data = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]})
     ts_data = convert_to_time_series(data)
-    assert isinstance(ts_data, TimeSeriesData), "The result should be an instance of TimeSeriesData"
-    assert ts_data.data.equals(pd.Series(data)), "The data should match the converted pandas Series"
+    assert isinstance(ts_data, TimeSeriesData)
+    pd.testing.assert_frame_equal(ts_data.data, data)
+
 
 def test_convert_invalid_type():
     """
-    Test that convert_to_time_series raises an error with invalid data types.
+    Test conversion of an unsupported data type.
     """
-    with pytest.raises(TypeError):
-        convert_to_time_series("invalid data")
+    data = "invalid data"
+    with pytest.raises(TypeError, match="Data must be of type pandas DataFrame, Series, or numpy array."):
+        convert_to_time_series(data)
+
+
+def test_convert_mixed_type_1d_numpy_array():
+    """
+    Test conversion of a 1D numpy array with mixed types.
+    """
+    data = np.array([1, "two", 3.0])
+    ts_data = convert_to_time_series(data)
+    assert isinstance(ts_data, TimeSeriesData)
+    pd.testing.assert_series_equal(ts_data.data, pd.Series(data))
+
+
+def test_convert_mixed_type_2d_numpy_array():
+    """
+    Test conversion of a 2D numpy array with mixed types.
+    """
+    data = np.array([[1, "two"], [3.0, 4]])
+    ts_data = convert_to_time_series(data)
+    assert isinstance(ts_data, TimeSeriesData)
+    pd.testing.assert_frame_equal(ts_data.data, pd.DataFrame(data))
diff --git a/tests/utils/test_validate_time_series_data.py b/tests/utils/test_validate_time_series_data.py
index 3aa81b3..01046cf 100644
--- a/tests/utils/test_validate_time_series_data.py
+++ b/tests/utils/test_validate_time_series_data.py
@@ -1,43 +1,96 @@
 import pytest
 import pandas as pd
 import numpy as np
+from interpreTS.utils.data_conversion import convert_to_time_series
+from interpreTS.core.time_series_data import TimeSeriesData
 
-from interpreTS.utils.data_validation import validate_time_series_data
-
-def test_validate_pandas_series():
-    """
-    Test validation of a valid pandas Series.
-    """
-    data = pd.Series([1, 2, 3, 4, 5], index=pd.date_range("2023-01-01", periods=5))
-    assert validate_time_series_data(data) == True, "The validation should pass for a valid pandas Series"
-
-def test_validate_with_nan_values():
-    """
-    Test that validation raises an error for data containing NaN values.
-    """
-    data = pd.Series([1, np.nan, 3, 4, 5], index=pd.date_range("2023-01-01", periods=5))
-    with pytest.raises(ValueError):
-        validate_time_series_data(data)
-
-def test_validate_without_datetime_index():
-    """
-    Test that validation raises an error for a Series without DateTime index.
-    """
+
+def test_convert_to_time_series_with_dataframe():
+    """Test conversion of a DataFrame to TimeSeriesData."""
+    data = pd.DataFrame({"value": [1, 2, 3, 4, 5]})
+    ts_data = convert_to_time_series(data)
+    assert isinstance(ts_data, TimeSeriesData), "Expected TimeSeriesData instance."
+    assert ts_data.data.equals(data), "Data mismatch after conversion."
+
+
+def test_convert_to_time_series_with_series():
+    """Test conversion of a Series to TimeSeriesData."""
     data = pd.Series([1, 2, 3, 4, 5])
-    with pytest.raises(ValueError):
-        validate_time_series_data(data, require_datetime_index=True)
+    ts_data = convert_to_time_series(data)
+    assert isinstance(ts_data, TimeSeriesData), "Expected TimeSeriesData instance."
+    assert ts_data.data.equals(data), "Data mismatch after conversion."
 
-def test_validate_numpy_array():
-    """
-    Test validation of a valid numpy array.
-    """
+
+def test_convert_to_time_series_with_ndarray():
+    """Test conversion of a numpy array to TimeSeriesData."""
     data = np.array([1, 2, 3, 4, 5])
-    assert validate_time_series_data(data) == True, "The validation should pass for a valid numpy array"
-
-def test_validate_invalid_type():
-    """
-    Test that validation raises an error for an invalid data type.
-    """
-    data = "invalid data"
-    with pytest.raises(TypeError):
-        validate_time_series_data(data)
+    ts_data = convert_to_time_series(data)
+    assert isinstance(ts_data, TimeSeriesData), "Expected TimeSeriesData instance."
+    expected_data = pd.Series(data)
+    assert ts_data.data.equals(expected_data), "Data mismatch after conversion."
+
+
+def test_convert_to_time_series_with_empty_dataframe():
+    """Test conversion of an empty DataFrame to TimeSeriesData."""
+    data = pd.DataFrame()
+    ts_data = convert_to_time_series(data)
+    assert isinstance(ts_data, TimeSeriesData), "Expected TimeSeriesData instance."
+    assert ts_data.data.equals(data), "Data mismatch after conversion."
+
+
+def test_convert_to_time_series_with_empty_series():
+    """Test conversion of an empty Series to TimeSeriesData."""
+    data = pd.Series(dtype=float)
+    ts_data = convert_to_time_series(data)
+    assert isinstance(ts_data, TimeSeriesData), "Expected TimeSeriesData instance."
+    assert ts_data.data.equals(data), "Data mismatch after conversion."
+
+
+def test_convert_to_time_series_with_empty_ndarray():
+    """Test conversion of an empty numpy array to TimeSeriesData."""
+    data = np.array([])
+    ts_data = convert_to_time_series(data)
+    assert isinstance(ts_data, TimeSeriesData), "Expected TimeSeriesData instance."
+    expected_data = pd.Series(data)
+    assert ts_data.data.equals(expected_data), "Data mismatch after conversion."
+
+
+def test_convert_to_time_series_with_invalid_type():
+    """Test conversion with an invalid data type."""
+    data = {"value": [1, 2, 3, 4, 5]}  # Dictionary is not a valid type
+    with pytest.raises(TypeError, match="Data must be of type pandas DataFrame, Series, or numpy array."):
+        convert_to_time_series(data)
+
+
+def test_convert_to_time_series_with_mixed_dataframe():
+    """Test conversion of a DataFrame with mixed data types to TimeSeriesData."""
+    data = pd.DataFrame({"value": [1, 2, 3, "a", 5]})
+    ts_data = convert_to_time_series(data)
+    assert isinstance(ts_data, TimeSeriesData), "Expected TimeSeriesData instance."
+    assert ts_data.data.equals(data), "Data mismatch after conversion."
+
+
+def test_convert_to_time_series_with_large_ndarray():
+    """Test conversion of a large numpy array to TimeSeriesData."""
+    data = np.random.rand(10**6)
+    ts_data = convert_to_time_series(data)
+    assert isinstance(ts_data, TimeSeriesData), "Expected TimeSeriesData instance."
+    expected_data = pd.Series(data)
+    assert ts_data.data.equals(expected_data), "Data mismatch after conversion."
+
+
+def test_convert_to_time_series_with_nan_values():
+    """Test conversion of data containing NaN values to TimeSeriesData."""
+    data = pd.Series([1, np.nan, 3, 4, 5])
+    ts_data = convert_to_time_series(data)
+    assert isinstance(ts_data, TimeSeriesData), "Expected TimeSeriesData instance."
+    assert ts_data.data.equals(data), "Data mismatch after conversion."
+
+
+def test_convert_to_time_series_with_datetime_index():
+    """Test conversion of a time series with a datetime index."""
+    dates = pd.date_range("2023-01-01", periods=5)
+    data = pd.Series([1, 2, 3, 4, 5], index=dates)
+    ts_data = convert_to_time_series(data)
+    assert isinstance(ts_data, TimeSeriesData), "Expected TimeSeriesData instance."
+    assert ts_data.data.equals(data), "Data mismatch after conversion."