Skip to content
Snippets Groups Projects
Commit d1d3ca00 authored by Pierre LOTTE's avatar Pierre LOTTE
Browse files

More structure and start of working dimensions/anomalies

parent 05bbad4a
No related branches found
No related tags found
No related merge requests found
"""
This module is in charge of the generation of anomalies.
"""
from .noise import NoiseAnomaly
ANOMALY_CLASSES = {
"NOISE": NoiseAnomaly,
}
"""
This module defines the basic behavior of an anomaly generator.
"""
from typing import Tuple
import numpy as np
class BaseAnomaly():
"""
This class defines the behavior that every anomaly generator should have.
"""
def __init__(self, configuration: dict, data: np.array, idx: int) -> "BaseAnomaly":
"""
:params configuration: (dict) The configuration of the anomaly to generate
"""
self.start = 0
self.end = 0
self.length = configuration["length"]
self.params = configuration
self.data = data
self.idx = idx
def inject(self) -> Tuple[np.array, np.array]:
"""
This method implements the anopmaly injection behavior. Each subclass must implement this method.
"""
raise NotImplementedError("Please implement the behavior of the 'inject' method for this class")
def find_anomaly_index(self) -> Tuple[int, int]:
"""
This method will find the starting and ending indices of the anomaly to inject.
"""
return 0, 100
"""
This module descibes the noise anomalies.
"""
import numpy as np
from .base import BaseAnomaly
class NoiseAnomaly(BaseAnomaly):
"""
This class is in charge of adding noise to a given time series.
"""
def inject(self) -> np.array:
start, end = self.find_anomaly_index()
noise = np.random.normal(self.params["mean"], self.params["std"], self.length)
self.data[self.idx, start:end] += noise
return self.data
......@@ -3,6 +3,8 @@ This module provides the main class needed to generate time series
"""
import numpy as np
from generator.dimension import DIMENSION_CLASSES
class DatasetGenerator():
"""
This class is in charge of the generation of a full dataset. It only requires the configuration of the
......@@ -18,9 +20,13 @@ class DatasetGenerator():
Start generation of data according to the configuration.
"""
dataset = np.zeros(len(self.dimensions), self.length)
training_dataset = np.zeros(len(self.dimensions), self.length * 3)
for dimension in self.dimensions:
pass
for idx, dimension in enumerate(self.dimensions):
dataset, training_dataset, new_labels = (
DIMENSION_CLASSES[dimension["kind"]](dimension, dataset, training_dataset, idx).generate()
)
labels = np.bitwise_or.reduce((labels, new_labels), axis=0)
def __str__(self) -> str:
return f"Dataset(dimensions={len(self.dimensions)}, length={self.length}, training={self.training})"
"""
This module provides classes needed to generate dimensions. A set of dimensions will be used
to create a full dataset.
"""
from .affine import AffineDimension
from .correlation import CorrelationDimension
from .inertia import InertiaDimension
from .oscillating import OscillatingDimension
DIMENSION_CLASSES = {
"AFFINE": AffineDimension,
"OSC": OscillatingDimension,
"CORRELATION": CorrelationDimension,
"INERTIA": InertiaDimension,
}
......@@ -3,7 +3,7 @@ This module defines different dimension generator.
"""
import numpy as np
from generator.base_dimension import BaseDimension
from .base import BaseDimension
class AffineDimension(BaseDimension):
......@@ -16,9 +16,15 @@ class AffineDimension(BaseDimension):
"""
This function generates data according to the given configuration
"""
# Add anomalies
self.inject_anomalies()
def inject_anomalies(self) -> np.array:
"""
This method is in charge of injecting anomalies into the data. It can either be called before
or after the data generation depending on the needs of the data generation.
"""
# Compute values for test data
x = np.linspace(0, self.length, self.length)
self.data[self.idx] += x * self.terms["a"] + self.terms["b"]
# Compute values for test data
x = np.linspace(0, self.length, self.train_length)
self.train_data[self.idx] += x * self.terms["a"] + self.terms["b"]
return self.data, self.train_data, self.labels
"""
This module defines different dimension generator.
"""
from typing import Tuple
import numpy as np
from generator.anomaly import ANOMALY_CLASSES
class BaseDimension():
"""
......@@ -10,7 +14,7 @@ class BaseDimension():
generator is to generate data according to a given function or behavior such as oscillating
functions, correlation functions, etc.
"""
def __init__(self, configuration: dict, data: np.array, idx: int) -> "BaseDimension":
def __init__(self, configuration: dict, data: np.array, train_data: np.array, idx: int) -> "BaseDimension":
"""
:params configuration: (dict) the configuration of the dimension.
:params data: (np.array) The whole dataset. It is needed for some kind of dimensions when they
......@@ -22,11 +26,19 @@ class BaseDimension():
self.anomalies = configuration["anomalies"]
self.length = data.shape[1]
self.data = data
self.train_data = train_data
self.train_length = train_data.shape[1]
self.labels = np.zeros(self.length)
self.idx = idx
def generate(self) -> np.array:
def generate(self) -> Tuple[np.array, np.array, np.array]:
"""
This function generates data according to the given configuration
:return: This function will return a Tuple of arrays. The first one should be used for training purposes
whereas the second should be used for testing purposes i.e. The first array will not contain
any anomalies and the second array will contain anomalies. The third array will be used to
return the anomaly labels in the form of an array containing either zeros or ones.
"""
raise NotImplementedError("Please implement the 'generate' method for this custom dimension generator")
......@@ -42,4 +54,9 @@ class BaseDimension():
This method is in charge of injecting anomalies into the data. It can either be called before
or after the data generation depending on the needs of the data generation.
"""
raise NotImplementedError("Please implement the 'inject_anomalies' method for this dimension generator")
for anomaly in self.anomalies:
data, labels = ANOMALY_CLASSES[anomaly["kind"]](anomaly, self.data, self.idx).inject()
self.data += data
self.labels += labels
return self.data
......@@ -3,7 +3,7 @@ This module defines different dimension generator.
"""
import numpy as np
from generator.base_dimension import BaseDimension
from .base import BaseDimension
class CorrelationDimension(BaseDimension):
......@@ -16,9 +16,3 @@ class CorrelationDimension(BaseDimension):
"""
This function generates data according to the given configuration
"""
def inject_anomalies(self) -> np.array:
"""
This method is in charge of injecting anomalies into the data. It can either be called before
or after the data generation depending on the needs of the data generation.
"""
......@@ -3,7 +3,7 @@ This module defines different dimension generator.
"""
import numpy as np
from generator.base_dimension import BaseDimension
from .base import BaseDimension
class InertiaDimension(BaseDimension):
......@@ -16,9 +16,3 @@ class InertiaDimension(BaseDimension):
"""
This function generates data according to the given configuration
"""
def inject_anomalies(self) -> np.array:
"""
This method is in charge of injecting anomalies into the data. It can either be called before
or after the data generation depending on the needs of the data generation.
"""
"""
This module defines different dimension generator.
"""
from typing import Tuple
import numpy as np
from generator.base_dimension import BaseDimension
from .base import BaseDimension
class OscillatingDimension(BaseDimension):
......@@ -12,13 +14,29 @@ class OscillatingDimension(BaseDimension):
generator is to generate data according to a given function or behavior such as oscillating
functions, correlation functions, etc.
"""
def generate(self) -> np.array:
OSCILLATING_FUNCTIONS = {
"sin": np.sin,
"cos": np.cos,
"versine": lambda x: 1 - np.cos(x),
"vercosine": lambda x: 1 + np.cos(x),
"coversine": lambda x: 1 - np.sin(x),
"covercosine": lambda x: 1 + np.sin(x),
"haversine": lambda x: (1 - np.cos(x)) / 2,
"havercosine": lambda x: (1 + np.cos(x)) / 2,
"hacoversine": lambda x: (1 - np.sin(x)) / 2,
"hacovercosine": lambda x: (1 + np.sin(x)) / 2,
}
def generate(self) -> Tuple[np.array, np.array, np.array]:
"""
This function generates data according to the given configuration
"""
offset = np.pi * np.random.random_sample()
dt = .01
func = self.OSCILLATING_FUNCTIONS[self.terms["function"]]
steps = np.zeros(self.length)
def inject_anomalies(self) -> np.array:
"""
This method is in charge of injecting anomalies into the data. It can either be called before
or after the data generation depending on the needs of the data generation.
"""
steps += 2 * np.pi * self.terms["frequency"] * dt
self.data[self.idx] = self.terms["amplitude"] * func(np.cumsum(steps) + offset)
return self.data, self.train_data, self.labels
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment