]> AND Private Git Repository - predictops.git/blob - predictops/learn/preprocessing.py
Logo AND Algorithmique Numérique Distribuée

Private GIT Repository
833e48316bffa1c51affc6885210b71f61b2c1d1
[predictops.git] / predictops / learn / preprocessing.py
1 from itertools import chain
2 from logging import getLogger
3 from logging.config import fileConfig
4 from pathlib import Path
5
6 import numpy as np
7 import pandas as pd
8
9 fileConfig((Path.cwd() / 'config') / 'logging.cfg')
10 logger = getLogger()
11
12 class Preprocessing:
13     '''
14     Generate a pandas dataframe from a dictionary of features per datetime, which
15     respects the starting and ending dates of the study, and its precision (the
16     time step) as passed to the constructor. Missing feature values are completed.
17
18      - Missing datetimes are added first with np.NaN feature values,
19      - The dataframe is then constructed based on the filled feature dictionary,
20      - NaN values are then filled with last known values.
21
22     '''
23     def __init__(self, dict_features,
24                  start, end, timestep,
25                  features = None):
26         '''
27         Constructor that defines all needed attributes and collects features.
28         '''
29         logger.info("Entering  NaN values in the feature dataframe")
30         self._dict_features = dict_features
31         self._start = start
32         self._end = end
33         self._timestep = timestep
34         self._full_dict = None
35         self._dataframe = None
36         self._datetimes = []
37         # If features are not provided to the constructor, then we collect
38         # any existing feature in the dictionary
39         if features != None:
40             self._features = features
41         else:
42             self._features = set(chain.from_iterable([tuple(u.keys())
43                                                       for u in [*dict_features.values()]]))
44
45
46     def _fill_dict(self):
47         '''
48         Add datetime keys in the dated feature dictionary that are missing. The
49         features are then set to np.NaN. Add missing features in existing datetimes
50         too.
51         '''
52         logger.info("Adding missing dates and filling missing features with NaN values")
53         current = self._start
54         while current <= self._end:
55             self._datetimes.append(current)
56             if current not in self._dict_features:
57                 self._dict_features[current] = {feature:np.NaN
58                                                 for feature in self._features}
59             else:
60                 null_dict = {feature:np.NaN
61                              for feature in self._features}
62                 null_dict.update(self._dict_features[current])
63                 self._dict_features[current] = null_dict
64             current += self._timestep
65         for k in self._dict_features:
66             null_dict = {feature:np.NaN
67                          for feature in self._features}
68             null_dict.update(self._dict_features[k])
69             self._dict_features[k] = null_dict
70
71         self._full_dict = {k: self._dict_features[k]
72                            for k in sorted(self._dict_features.keys())}
73
74
75
76     @property
77     def full_dict(self):
78         '''
79         Returns the fully filled dated feature dictionary, ordered by datetimes
80         '''
81         if self._full_dict is None:
82             self._fill_dict()
83         return self._full_dict
84
85
86
87     @property
88     def dataframe(self):
89         '''
90         Returns the feature dataframe, after creating it if needed.
91         '''
92         if self._dataframe is None:
93             logger.info("Creating feature dataframe from feature dictionary")
94             self._dataframe = pd.DataFrame.from_dict(self.full_dict,
95                                                      orient='index')
96             logger.info("Filling NaN values in the feature dataframe")
97             #TODO: add other filling methods like linear interpolation
98             self._dataframe = self._dataframe.fillna(method='ffill')
99             self._dataframe = self._dataframe.fillna(method='bfill')
100             self._dataframe = self._dataframe.drop([k.to_pydatetime()
101                                                    for k in self._dataframe.T
102                                                    if k not in self._datetimes])
103         return self._dataframe
104
105     @dataframe.setter
106     def dataframe(self, df):
107         self._dataframe = df
108
109