cesar 2 weeks ago
parent
commit
c502f04fde
2 changed files with 493 additions and 8 deletions
  1. 65
    8
      v4_class.py
  2. 428
    0
      v5_class.py

+ 65
- 8
v4_class.py View File

@@ -66,7 +66,17 @@ datafiles[4]=['2024-12-28_5_','2024-12-29_5_','2024-12-30_5_','2024-12-31_5_','2
66 66
 
67 67
 features=['r1 s1','r1 s4','r1 s5','pa1 apiii']
68 68
 features=['r1 s1','r1 s4','r1 s5']
69
+features=['r1 s5']
70
+# Feature combination suggested by AKO
71
+features=['r1 s1','r1 s4','r1 s5','pa1 apiii']
72
+features=['r1 s1','r1 s4','r1 s5']
73
+features=['r1 s1','r1 s5','pa1 apiii']
74
+features=['r1 s5','pa1 apiii']
69 75
 features=['r1 s1','r1 s5']
76
+features=['r1 s5']
77
+
78
+
79
+
70 80
 featureNames={}
71 81
 featureNames['r1 s1']='$T_{evap}$'
72 82
 featureNames['r1 s4']='$T_{cond}$'
@@ -310,7 +320,10 @@ def plotData4():
310 320
         init=0
311 321
         end=testRanges[0][1]
312 322
         for j in range(NumberOfFailures+1):
313
-            axes[i].plot(range(init,end),x_test[testRanges[j][0]:testRanges[j][1],0,indexesToPlot[i]]*stdevs[i]+means[i],label="Class "+str(j), color=colorline[j],linewidth=1)
323
+            if NumFeaturesToPlot==1:
324
+                axes.plot(range(init,end),x_test[testRanges[j][0]:testRanges[j][1],0,indexesToPlot[i]]*stdevs[i]+means[i],label="Class "+str(j), color=colorline[j],linewidth=1)
325
+            else:
326
+                axes[i].plot(range(init,end),x_test[testRanges[j][0]:testRanges[j][1],0,indexesToPlot[i]]*stdevs[i]+means[i],label="Class "+str(j), color=colorline[j],linewidth=1)
314 327
             if j<NumberOfFailures:
315 328
                 init=end
316 329
                 end+=(testRanges[j+1][1]-testRanges[j+1][0])
@@ -323,17 +336,34 @@ def plotData4():
323 336
         s=''
324 337
         s+=featureNames[features[indexesToPlot[i]]]
325 338
         s+=' '+unitNames[features[indexesToPlot[i]]]
326
-        axes[i].set_ylabel(s)
327
-        axes[i].grid()
339
+        if NumFeaturesToPlot==1:
340
+            axes.set_ylabel(s)
341
+            axes.grid()
342
+        else:
343
+            axes[i].set_ylabel(s)
344
+            axes[i].grid()
345
+
328 346
     for j in range(NumberOfFailures+1):
329
-        axes[0].plot(x[j],y[j] ,color=colordot[j],marker='.',markersize=10,linewidth=0,label="Fail detect  type "+str(j) )
330
-    axes[0].legend(ncol=4,loc=(0.1,0.98))
347
+        if NumFeaturesToPlot==1:
348
+            axes.plot(x[j],y[j] ,color=colordot[j],marker='.',markersize=10,linewidth=0,label="Fail detect  type "+str(j) )
349
+        else:
350
+            axes[0].plot(x[j],y[j] ,color=colordot[j],marker='.',markersize=10,linewidth=0,label="Fail detect  type "+str(j) )
351
+            
352
+    if NumFeaturesToPlot==1:
353
+        axes.legend(ncol=4,loc=(0.1,0.98))
354
+    else:
355
+        axes[0].legend(ncol=4,loc=(0.1,0.98))
331 356
 
332 357
         
333
-    axes[NumFeaturesToPlot-1].set_xlabel("Sample number")
358
+    #axes[NumFeaturesToPlot-1].set_xlabel("Sample number")
334 359
     plt.show()
335 360
 
336
-
361
+def whichClass(k,ranges):
362
+    for i in range(NumberOfFailures+1):
363
+        if k in range(ranges[i][0],ranges[i][1]):
364
+            return(i)
365
+    print("Error:  Class not exists")
366
+    exit(0)        
337 367
 
338 368
 ##   It remains to implemenent anomaly metrics for each failure type
339 369
 def anomalyMetric(classes,testranges,testclasses):  
@@ -342,8 +372,35 @@ def anomalyMetric(classes,testranges,testclasses):
342 372
     # Sensitivity (recall): probab failure detection if data is fail: TP/(TP+FN)
343 373
     # Precision: Rate of positive results:  TP/(TP+FP)  
344 374
     # F1-score: predictive performance measure: 2*Precision*Sensitity/(Precision+Sensitity)
375
+    TP=np.zeros(NumberOfFailures+1)
376
+    FP=np.zeros(NumberOfFailures+1)
377
+    FN=np.zeros(NumberOfFailures+1)
378
+    Sensitivity=np.zeros(NumberOfFailures+1)
379
+    Precision=np.zeros(NumberOfFailures+1)
380
+    for i in range(len(testranges)):
381
+        for k in range(testranges[i][0],testranges[i][1]):
382
+            if classes[k]==testclasses[i]:
383
+                TP[i]+=1
384
+            else:
385
+                FP[i]+=1
386
+    for k in range(testranges[NumberOfFailures][1]):
387
+        for i in range(len(testranges)):
388
+            classK=whichClass(k,testranges)
389
+            if not classK==testClasses[i]:
390
+                if not classes[k]==classK:
391
+                    FN[classes[k]]+=1
345 392
 
346
-    print(classes)
393
+    for i in range(NumberOfFailures+1):
394
+        Sensitivity[i]=TP[i]/(TP[i]+FN[i])
395
+        Precision[i]=TP[i]/(TP[i]+FP[i])
396
+    S=Sensitivity.mean()
397
+    P=Precision.mean()
398
+    F1=2*S*P/(S+P)
399
+    print("Sensitivity: ",Sensitivity) 
400
+    print("S: ",S) 
401
+    print("Precision: ",Precision) 
402
+    print("P: ",P) 
403
+    print("F1-Score: ",F1)
347 404
 
348 405
 anomalyMetric(classes,testRanges,testClasses)
349 406
 plotData4()

+ 428
- 0
v5_class.py View File

@@ -0,0 +1,428 @@
1
+# Csar Fdez, UdL, 2025
2
+# Changes from v1:   Normalization 
3
+# IN v1, each failure type has its own normalization pars (mean and stdevs)
4
+# In v2, mean and stdev is the same for all data
5
+# v3.py trains the models looping in TIME_STEPS (4,8,12,16,20,24,....) finding the optimal Threshold factor
6
+
7
+#  Derived from v3_class, derived from v3.py with code from v1_multifailure.py
8
+#  This code don't train for multiple time steps !!
9
+
10
+#  partial and total blocked condenser merged in one class.
11
+#  Construction of train and test sets changed. Now is done by days
12
+
13
+import pandas as pd
14
+import matplotlib.pyplot as plt
15
+import datetime
16
+import numpy as np
17
+import keras
18
+import os.path
19
+from keras import layers
20
+from optparse import OptionParser
21
+import copy
22
+import pickle
23
+
24
+
25
+parser = OptionParser()
26
+parser.add_option("-t", "--train", dest="train", help="Trains the models (false)", default=False, action="store_true")
27
+parser.add_option("-n", "--timesteps", dest="timesteps", help="TIME STEPS ", default=12)
28
+#parser.add_option("-f", "--thresholdfactor", dest="TF", help="Threshold Factor ", default=1.4)
29
+# threshold makes no sense when classifying, becaues we apply many models and decide class for the less MSE
30
+
31
+(options, args) = parser.parse_args()
32
+
33
+
34
+# data files arrays. Index:
35
+# 0.  No failure
36
+# 1.  Blocked evaporator
37
+# 2.   Full Blocked condenser
38
+# 3.   Partial Blocked condenser
39
+# 4   Fan condenser not working
40
+# 5.  Open door
41
+
42
+
43
+NumberOfFailures=3  # So far, we have only data for the first 4 types of failures
44
+datafiles=[[],[]]   # 0 for train,  1 for test
45
+for i in range(NumberOfFailures+1):
46
+    datafiles[0].append([])
47
+    datafiles[1].append([])
48
+
49
+# Next set of ddata corresponds to Freezer, SP=-26
50
+datafiles[0][0]=['2024-08-07_5_','2024-08-08_5_','2025-01-25_5_','2025-01-26_5_'] 
51
+datafiles[1][0]=['2025-01-27_5_','2025-01-28_5_'] 
52
+
53
+datafiles[0][1]=['2024-12-11_5_', '2024-12-12_5_','2024-12-13_5_'] 
54
+datafiles[1][1]=['2024-12-14_5_','2024-12-15_5_'] 
55
+
56
+datafiles[0][2]=['2024-12-18_5_','2024-12-21_5_','2024-12-22_5_','2024-12-23_5_','2024-12-24_5_'] 
57
+datafiles[1][2]=['2024-12-19_5_','2024-12-25_5_','2024-12-26_5_'] 
58
+
59
+
60
+datafiles[0][3]=['2024-12-28_5_','2024-12-29_5_','2024-12-30_5_'] 
61
+datafiles[1][3]=['2024-12-31_5_','2025-01-01_5_'] 
62
+
63
+#r1s5 supply air flow temperature
64
+#r1s1 inlet evaporator temperature
65
+#r1s4 condenser outlet
66
+
67
+# VAriables r1s4 and pa1 apiii  may not exists in cloud controlers
68
+
69
+
70
+features=['r1 s1','r1 s4','r1 s5','pa1 apiii']
71
+features=['r1 s1','r1 s4','r1 s5']
72
+features=['r1 s5']
73
+# Feature combination suggested by AKO
74
+#features=['r1 s1','r1 s4','r1 s5','pa1 apiii']
75
+#features=['r1 s1','r1 s4','r1 s5']
76
+#features=['r1 s1','r1 s5','pa1 apiii']
77
+#features=['r1 s5','pa1 apiii']
78
+features=['r1 s1','r1 s5']
79
+#features=['r1 s5']
80
+
81
+
82
+
83
+featureNames={}
84
+featureNames['r1 s1']='$T_{evap}$'
85
+featureNames['r1 s4']='$T_{cond}$'
86
+featureNames['r1 s5']='$T_{air}$'
87
+featureNames['pa1 apiii']='$P_{elec}$'
88
+
89
+unitNames={}
90
+unitNames['r1 s1']='$(^{o}C)$'
91
+unitNames['r1 s4']='$(^{o}C)$'
92
+unitNames['r1 s5']='$(^{o}C)$'
93
+unitNames['pa1 apiii']='$(W)$'
94
+
95
+
96
+#features=['r1 s1','r1 s2','r1 s3','r1 s4','r1 s5','r1 s6','r1 s7','r1 s8','r1 s9','r1 s10','r2 s1','r2 s2','r2 s3','r2 s4','r2 s5','r2 s6','r2 s7','r2 s8','r2 s9','pa1 apiii','tc s1','tc s2']
97
+
98
+#features=['r2 s2', 'tc s1','r1 s10','r1 s6','r2 s8']
99
+
100
+NumFeatures=len(features)
101
+
102
+df_list=[[],[]]
103
+for i in range(NumberOfFailures+1):
104
+    df_list[0].append([])
105
+    df_list[1].append([])
106
+
107
+for i in range(NumberOfFailures+1):
108
+    dftemp=[]
109
+    for f in datafiles[0][i]:
110
+        print("                 ", f)
111
+        df1 = pd.read_csv('./data/'+f+'.csv')
112
+        dftemp.append(df1)
113
+    df_list[0][i]=pd.concat(dftemp)
114
+
115
+for i in range(NumberOfFailures+1):
116
+    dftemp=[]
117
+    for f in datafiles[1][i]:
118
+        print("                 ", f)
119
+        #df1 = pd.read_csv('./data/'+f+'.csv', parse_dates=['datetime'], dayfirst=True, index_col='datetime')
120
+        df1 = pd.read_csv('./data/'+f+'.csv')
121
+        dftemp.append(df1)
122
+    df_list[1][i]=pd.concat(dftemp)
123
+
124
+
125
+
126
+# subsampled to 5'  =  30 * 10"
127
+# We consider smaples every 5' because in production, we will only have data at this frequency
128
+subsamplingrate=30
129
+
130
+dataframe=[[],[]]
131
+for i in range(NumberOfFailures+1):
132
+    dataframe[0].append([])
133
+    dataframe[1].append([])
134
+
135
+for i in range(NumberOfFailures+1):
136
+    datalength=df_list[0][i].shape[0]
137
+    dataframe[0][i]=df_list[0][i].iloc[range(0,datalength,subsamplingrate)][features]
138
+    dataframe[0][i].reset_index(inplace=True,drop=True)
139
+    dataframe[0][i].dropna(inplace=True)
140
+for i in range(NumberOfFailures+1):
141
+    datalength=df_list[1][i].shape[0]
142
+    dataframe[1][i]=df_list[1][i].iloc[range(0,datalength,subsamplingrate)][features]
143
+    dataframe[1][i].reset_index(inplace=True,drop=True)
144
+    dataframe[1][i].dropna(inplace=True)
145
+
146
+
147
+# Train data is first 2/3 of data
148
+# Test data is: last 1/3 of data 
149
+dataTrain=[]
150
+dataTest=[]
151
+for i in range(NumberOfFailures+1):
152
+    dataTrain.append(dataframe[0][i].values)
153
+    dataTest.append(dataframe[0][i])
154
+
155
+# Calculate means and stdev
156
+a=dataTrain[0]
157
+for i in range(1,NumberOfFailures+1):
158
+    a=np.vstack((a,dataTrain[i]))
159
+
160
+means=a.mean(axis=0) 
161
+stdevs=a.std(axis=0)
162
+def normalize2(train,test):
163
+    return( (train-means)/stdevs, (test-means)/stdevs )
164
+
165
+dataTrainNorm=[]
166
+dataTestNorm=[]
167
+for i in range(NumberOfFailures+1):
168
+    dataTrainNorm.append([])
169
+    dataTestNorm.append([])
170
+
171
+for i in range(NumberOfFailures+1):
172
+    (dataTrainNorm[i],dataTestNorm[i])=normalize2(dataTrain[i],dataTest[i])
173
+
174
+def plotData():    
175
+    fig, axes = plt.subplots(
176
+        nrows=NumberOfFailures+1, ncols=2, figsize=(15, 20), dpi=80, facecolor="w", edgecolor="k",sharex=True
177
+    )
178
+    for i in range(NumberOfFailures+1):
179
+        axes[i][0].plot(np.concatenate((dataTrainNorm[i][:,0],dataTestNorm[i][:,0])),label="Fail "+str(i)+",  feature 0")
180
+        axes[i][1].plot(np.concatenate((dataTrainNorm[i][:,1],dataTestNorm[i][:,1])),label="Fail "+str(i)+",  feature 1")
181
+    #axes[1].legend()
182
+    #axes[0].set_ylabel(features[0])
183
+    #axes[1].set_ylabel(features[1])
184
+    plt.show()
185
+
186
+#plotData()
187
+#exit(0)
188
+
189
+
190
+NumFilters=64
191
+KernelSize=7
192
+DropOut=0.2
193
+ThresholdFactor=1.4
194
+def create_sequences(values, time_steps):
195
+    output = []
196
+    for i in range(len(values) - time_steps + 1):
197
+        output.append(values[i : (i + time_steps)])
198
+    return np.stack(output)
199
+
200
+
201
+
202
+def listToString(l):
203
+    r=''
204
+    for i in l:
205
+        r+=str(i)
206
+    return(r.replace(' ',''))
207
+
208
+
209
+model=[]
210
+modelckpt_callback =[]
211
+es_callback =[]
212
+path_checkpoint=[]
213
+
214
+timesteps=int(options.timesteps)
215
+x_train=[]
216
+for i in range(NumberOfFailures+1):
217
+    x_train.append(create_sequences(dataTrainNorm[i],timesteps))
218
+    model.append([])
219
+    model[i] = keras.Sequential(
220
+        [
221
+            layers.Input(shape=(x_train[i].shape[1], x_train[i].shape[2])),
222
+            layers.Conv1D(
223
+                filters=NumFilters,
224
+                kernel_size=KernelSize,
225
+                padding="same",
226
+                strides=2,
227
+                activation="relu",
228
+            ),
229
+            layers.Dropout(rate=DropOut),
230
+            layers.Conv1D(
231
+                filters=int(NumFilters/2),
232
+                kernel_size=KernelSize,
233
+                padding="same",
234
+                strides=2,
235
+                activation="relu",
236
+            ),
237
+            layers.Conv1DTranspose(
238
+                filters=int(NumFilters/2),
239
+                kernel_size=KernelSize,
240
+                padding="same",
241
+                strides=2,
242
+                activation="relu",
243
+            ),
244
+            layers.Dropout(rate=DropOut),
245
+            layers.Conv1DTranspose(
246
+                filters=NumFilters,
247
+                kernel_size=KernelSize,
248
+                padding="same",
249
+                strides=2,
250
+                activation="relu",
251
+            ),
252
+            layers.Conv1DTranspose(filters=x_train[i].shape[2], kernel_size=KernelSize, padding="same"),
253
+        ]
254
+    )
255
+    model[i].compile(optimizer=keras.optimizers.Adam(learning_rate=0.001), loss="mse")
256
+    model[i].summary()
257
+    path_checkpoint.append("model_class_v5_"+str(i)+"_"+str(timesteps)+listToString(features)+"_checkpoint.weights.h5")
258
+    es_callback.append(keras.callbacks.EarlyStopping(monitor="val_loss", min_delta=0, patience=15))
259
+    modelckpt_callback.append(keras.callbacks.ModelCheckpoint( monitor="val_loss", filepath=path_checkpoint[i], verbose=1, save_weights_only=True, save_best_only=True,))
260
+
261
+
262
+if options.train:
263
+    history=[]    
264
+    for i in range(NumberOfFailures+1):
265
+        history.append(model[i].fit( x_train[i], x_train[i], epochs=400, batch_size=128, validation_split=0.3, callbacks=[  es_callback[i], modelckpt_callback[i]      ],))
266
+
267
+        x_train_pred=model[i].predict(x_train[i])
268
+else:
269
+    for i in range(NumberOfFailures+1):
270
+        model[i].load_weights(path_checkpoint[i])
271
+
272
+
273
+
274
+# Let's plot some features
275
+
276
+colorline=['black','violet','lightcoral','cyan','lime','grey']
277
+colordot=['grey','darkviolet','red','blue','green','black']
278
+
279
+#featuresToPlot=['r1 s1','r1 s2','r1 s3','pa1 apiii']
280
+featuresToPlot=features
281
+
282
+indexesToPlot=[]
283
+for i in featuresToPlot:
284
+    indexesToPlot.append(features.index(i))
285
+
286
+
287
+
288
+#   2nd scenario. Go over anomalies and classify it by less error
289
+datalist=[dataTestNorm[0],dataTestNorm[1],dataTestNorm[2],dataTestNorm[3]]
290
+x_test=create_sequences(datalist[0],int(options.timesteps))
291
+for i in range(1,len(datalist)):
292
+    x_test=np.vstack((x_test,create_sequences(datalist[i],int(options.timesteps))))
293
+
294
+# Define ranges for plotting in different colors
295
+testRanges=[]
296
+r=0
297
+for i in range(len(datalist)):
298
+    testRanges.append([r,r+datalist[i].shape[0]-int(options.timesteps)])
299
+    r+=datalist[i].shape[0]-int(options.timesteps)
300
+
301
+testClasses=[0,1,2,3]
302
+
303
+if not len(testClasses)==len(testRanges):
304
+    print("ERROR:  testClasses and testRanges must have same length")
305
+    exit(0)
306
+
307
+x_test_predict=[]
308
+for m in range(NumberOfFailures+1):
309
+    x_test_predict.append(model[m].predict(x_test))
310
+
311
+x_test_predict=np.array((x_test_predict))
312
+test_mae_loss =[]
313
+for m in range(NumberOfFailures+1):
314
+    test_mae_loss.append(np.mean(np.abs(x_test_predict[m,:,:,:] - x_test), axis=1))
315
+
316
+test_mae_loss=np.array((test_mae_loss))
317
+test_mae_loss_average=np.mean(test_mae_loss,axis=2)  # average over features
318
+classes=np.argmin(test_mae_loss_average,axis=0)
319
+
320
+x=[]
321
+y=[]
322
+for j in range(NumberOfFailures+1):
323
+    x.append([])
324
+    y.append([])
325
+for j in range(NumberOfFailures+1):
326
+    for k in range(testRanges[j][0],testRanges[j][1]):
327
+        if not  classes[k]==testClasses[j]:
328
+            x[classes[k]].append(k)
329
+            y[classes[k]].append(x_test[k,0,indexesToPlot[0]]*stdevs[0]+means[0])
330
+
331
+
332
+def plotData4():
333
+    NumFeaturesToPlot=len(indexesToPlot)
334
+    plt.rcParams.update({'font.size': 16})
335
+    fig, axes = plt.subplots(
336
+        nrows=NumFeaturesToPlot, ncols=1, figsize=(15, 10), dpi=80, facecolor="w", edgecolor="k",sharex=True
337
+    )
338
+    for i in range(NumFeaturesToPlot):
339
+        init=0
340
+        end=testRanges[0][1]
341
+        for j in range(NumberOfFailures+1):
342
+            if NumFeaturesToPlot==1:
343
+                axes.plot(range(init,end),x_test[testRanges[j][0]:testRanges[j][1],0,indexesToPlot[i]]*stdevs[i]+means[i],label="Class "+str(j), color=colorline[j],linewidth=1)
344
+            else:
345
+                axes[i].plot(range(init,end),x_test[testRanges[j][0]:testRanges[j][1],0,indexesToPlot[i]]*stdevs[i]+means[i],label="Class "+str(j), color=colorline[j],linewidth=1)
346
+            if j<NumberOfFailures:
347
+                init=end
348
+                end+=(testRanges[j+1][1]-testRanges[j+1][0])
349
+
350
+            #if i==0:
351
+            #    axes[0].plot(x[j],y[j] ,color=colordot[j],marker='.',markersize=10,linewidth=0,label="Fail detect  type "+str(j) )
352
+
353
+
354
+
355
+        s=''
356
+        s+=featureNames[features[indexesToPlot[i]]]
357
+        s+=' '+unitNames[features[indexesToPlot[i]]]
358
+        if NumFeaturesToPlot==1:
359
+            axes.set_ylabel(s)
360
+            axes.grid()
361
+        else:
362
+            axes[i].set_ylabel(s)
363
+            axes[i].grid()
364
+
365
+    for j in range(NumberOfFailures+1):
366
+        if NumFeaturesToPlot==1:
367
+            axes.plot(x[j],y[j] ,color=colordot[j],marker='.',markersize=10,linewidth=0,label="Fail detect  type "+str(j) )
368
+        else:
369
+            axes[0].plot(x[j],y[j] ,color=colordot[j],marker='.',markersize=10,linewidth=0,label="Fail detect  type "+str(j) )
370
+            
371
+    if NumFeaturesToPlot==1:
372
+        axes.legend(ncol=4,loc=(0.1,0.98))
373
+    else:
374
+        axes[0].legend(ncol=4,loc=(0.1,0.98))
375
+
376
+        
377
+    #axes[NumFeaturesToPlot-1].set_xlabel("Sample number")
378
+    plt.show()
379
+
380
+def whichClass(k,ranges):
381
+    for i in range(NumberOfFailures+1):
382
+        if k in range(ranges[i][0],ranges[i][1]):
383
+            return(i)
384
+    print("Error:  Class not exists")
385
+    exit(0)        
386
+
387
+##   It remains to implemenent anomaly metrics for each failure type
388
+def anomalyMetric(classes,testranges,testclasses):  
389
+    # FP, TP: false/true positive
390
+    # TN, FN: true/false negative
391
+    # Sensitivity (recall): probab failure detection if data is fail: TP/(TP+FN)
392
+    # Precision: Rate of positive results:  TP/(TP+FP)  
393
+    # F1-score: predictive performance measure: 2*Precision*Sensitity/(Precision+Sensitity)
394
+    TP=np.zeros(NumberOfFailures+1)
395
+    FP=np.zeros(NumberOfFailures+1)
396
+    FN=np.zeros(NumberOfFailures+1)
397
+    Sensitivity=np.zeros(NumberOfFailures+1)
398
+    Precision=np.zeros(NumberOfFailures+1)
399
+    for i in range(len(testranges)):
400
+        for k in range(testranges[i][0],testranges[i][1]):
401
+            if classes[k]==testclasses[i]:
402
+                TP[i]+=1
403
+            else:
404
+                FP[i]+=1
405
+    for k in range(testranges[NumberOfFailures][1]):
406
+        for i in range(len(testranges)):
407
+            classK=whichClass(k,testranges)
408
+            if not classK==testClasses[i]:
409
+                if not classes[k]==classK:
410
+                    FN[classes[k]]+=1
411
+
412
+    for i in range(NumberOfFailures+1):
413
+        Sensitivity[i]=TP[i]/(TP[i]+FN[i])
414
+        Precision[i]=TP[i]/(TP[i]+FP[i])
415
+    S=Sensitivity.mean()
416
+    P=Precision.mean()
417
+    F1=2*S*P/(S+P)
418
+    print("Sensitivity: ",Sensitivity) 
419
+    print("S: ",S) 
420
+    print("Precision: ",Precision) 
421
+    print("P: ",P) 
422
+    print("F1-Score: ",F1)
423
+
424
+anomalyMetric(classes,testRanges,testClasses)
425
+plotData4()
426
+exit(0)
427
+
428
+

Powered by TurnKey Linux.