[RICAPP-181] Update Prediction message (from QP to TS) with serving cell prediciton
[ric-app/qp.git] / qp / qptrain.py
1 # ==================================================================================
2 #  Copyright (c) 2020 HCL Technologies Limited.
3 #
4 #  Licensed under the Apache License, Version 2.0 (the "License");
5 #  you may not use this file except in compliance with the License.
6 #  You may obtain a copy of the License at
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 #  Unless required by applicable law or agreed to in writing, software
11 #  distributed under the License is distributed on an "AS IS" BASIS,
12 #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 #  See the License for the specific language governing permissions and
14 #  limitations under the License.
15 # ==================================================================================
16
17 from statsmodels.tsa.api import VAR
18 from statsmodels.tsa.stattools import adfuller
19 import joblib
20
21
22 class DataNotMatchError(Exception):
23     pass
24
25
26 class PROCESS(object):
27
28     def __init__(self, data):
29         self.diff = 0
30         self.data = data
31
32     def adfuller_test(self, series, thresh=0.05, verbose=False):
33         """ADFuller test for Stationarity of given series and return True or False"""
34         r = adfuller(series, autolag='AIC')
35         output = {'test_statistic': round(r[0], 4), 'pvalue': round(r[1], 4), 'n_lags': round(r[2], 4), 'n_obs': r[3]}
36         p_value = output['pvalue']
37         if p_value <= thresh:
38             return True
39         else:
40             return False
41
42     def make_stationary(self):
43         """ call adfuller_test() to check for stationary
44             If the column is stationary, perform 1st differencing and return data"""
45         df = self.data.copy()
46         res_adf = []
47         for name, column in df.iteritems():
48             res_adf.append(self.adfuller_test(column))  # Perform ADF test
49         if not all(res_adf):
50             self.data = df.diff().dropna()
51             self.diff += 1
52
53     def invert_transformation(self, inp, forecast):
54         """Revert back the differencing to get the forecast to original scale."""
55         if self.diff == 0:
56             return forecast
57         df = forecast.copy()
58         columns = inp.columns
59         for col in columns:
60             df[col] = inp[col].iloc[-1] + df[col].cumsum()
61         self.diff = 0
62         return df
63
64     def process(self):
65         """ Filter throughput parameters, call make_stationary() to check for Stationarity time series
66         """
67         df = self.data.copy()
68         try:
69             df = df[['pdcpBytesDl', 'pdcpBytesUl']]
70         except DataNotMatchError:
71             print('Parameters pdcpBytesDl, pdcpBytesUl does not exist in provided data')
72             self.data = None
73         self.data = df.loc[:, (df != 0).any(axis=0)]
74         self.make_stationary()  # check for Stationarity and make the Time Series Stationary
75
76     def valid(self):
77         val = False
78         if self.data is not None:
79             df = self.data.copy()
80             df = df.loc[:, (df != 0).any(axis=0)]
81             if len(df) != 0 and df.shape[1] == 2:
82                 val = True
83         return val
84
85
86 def train(db, cid):
87     """
88      Read the input file(based on cell id received from the main program)
89      call process() to forecast the downlink and uplink of the input cell id
90      Make a VAR model, call the fit method with the desired lag order.
91     """
92     db.read_data(meas='liveCell', cellid=cid)
93     md = PROCESS(db.data)
94     md.process()
95     if md.valid():
96         model = VAR(md.data)          # Make a VAR model
97         model_fit = model.fit(10)            # call fit method with lag order
98         file_name = 'qp/'+cid.replace('/', '')
99         with open(file_name, 'wb') as f:
100             joblib.dump(model_fit, f)     # Save the model with the cell id name