Feature Engineering | Thresholding Setting | Condition Quantification
This one day project was an emergency response to the spate of motor burns on the BPLRT. The objective was to find an engineering-based scoring metric that could be used to filter out the motors that were at higher risk of burning so that they could be removed from the network and serviced. Since there was no time for validation, the model's effectiveness was based on backtest results.
Aside from the rapid identification and direct application of engineering insights based on research which correlated motor resistance, temperature and life to carbon brush-rotor interfaces (Shin, WG., Song, YS. & Seo, YK. Correlation analysis of brush temperature in brush-type DC motor for predicting motor life. J Mech Sci Technol 26, 2151–2154 (2012). https://doi.org/10.1007/s12206-012-0534-0), this project relied on direct feedback on visualizations of the data over time from the maintenance team to determine their preferred mode of quantifying a motor's risk of burning. The ideation process based on visualized data allowed for different ideas to be tested and the backtesting of the methods from the ideas eventually quantitatively determined the best idea.
# Combine all data into one dataframe
import os
import pandas as pd
import xlrd
pd.options.mode.chained_assignment = None # default='warn'
path = os.getcwd()
df1 = pd.DataFrame()
df2 = pd.DataFrame()
xls = xlrd.open_workbook(path + '\\' + 'BURNS.xls')
for sheet_name in xls.sheet_names():
print('INCLUDED TRAIN: ' + str(sheet_name))
df1 = df1.append(pd.read_excel(xls, sheet_name=sheet_name, skiprows=2,usecols=[i for i in range(16)]), ignore_index=True)
df2 = df2.append(pd.read_excel(xls, sheet_name=sheet_name, skiprows=2,usecols=[i for i in range(16,32)]), ignore_index=True)
col_name_remap = {}
for col_1_name,col_2_name in zip(df1.columns,df2.columns):
col_name_remap[col_2_name] = col_1_name
df2.rename(columns=col_name_remap, inplace=True)
df = df1.append(df2)
df.reset_index(inplace=True)
df.to_excel("combined_files.xlsx") #assign name of the excel file you want to output the combined files as
df.columns
INCLUDED TRAIN: V101
INCLUDED TRAIN: V102
INCLUDED TRAIN: V103
INCLUDED TRAIN: V104
INCLUDED TRAIN: V105
INCLUDED TRAIN: V106
INCLUDED TRAIN: V107
INCLUDED TRAIN: V108
INCLUDED TRAIN: V109
INCLUDED TRAIN: V110
INCLUDED TRAIN: V111
INCLUDED TRAIN: V112
INCLUDED TRAIN: V113
INCLUDED TRAIN: V114
INCLUDED TRAIN: V115
INCLUDED TRAIN: V116
INCLUDED TRAIN: V117
INCLUDED TRAIN: V118
INCLUDED TRAIN: V119
INCLUDED TRAIN: V120
INCLUDED TRAIN: V121
INCLUDED TRAIN: V122
INCLUDED TRAIN: V123
INCLUDED TRAIN: V124
INCLUDED TRAIN: V125
INCLUDED TRAIN: V126
INCLUDED TRAIN: V127
INCLUDED TRAIN: V128
INCLUDED TRAIN: V129
INCLUDED TRAIN: V130
INCLUDED TRAIN: V131
INCLUDED TRAIN: V132
Index(['index', 'Team', 'Date', 'Odometer', 'Motor\nS/N',
'Spring\ntab\ncolour\n(Y/R)', 'Track\n(A/B)',
'Carbon Brush Length (mm)', 'Unnamed: 7', 'Unnamed: 8', 'Unnamed: 9',
'Undercut\n> 0.5 mm', 'Wear rate per 10,000 km', 'Unnamed: 12',
'Unnamed: 13', 'Unnamed: 14', 'Motor\nwear\nrate'],
dtype='object')
df
| index | Team | Date | Odometer | Motor\nS/N | Spring\ntab\ncolour\n(Y/R) | Track\n(A/B) | Carbon Brush Length (mm) | Unnamed: 7 | Unnamed: 8 | Unnamed: 9 | Undercut\n> 0.5 mm | Wear rate per 10,000 km | Unnamed: 12 | Unnamed: 13 | Unnamed: 14 | Motor\nwear\nrate | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | NaN | NaT | NaN | NaN | NaN | NaN | Position 1 | Position 2 | Position 3 | Position 4 | NaN | Position 1 | Position 2 | Position 3 | Position 4 | NaN |
| 1 | 1 | NaN | NaT | NaN | NaN | NaN | NaN | NaN | Track A | Track A | Track A | NaN | NaN | Track A | Track A | Track A | NaN |
| 2 | 2 | D | 2019-11-05 00:00:00 | 180637.0 | SLMA 006 | Y | A | 36.55 | 41.48 | 40.16 | 39.03 | NaN | N.A. | N.A. | N.A. | N.A. | NaN |
| 3 | 3 | NaN | 2019-11-13 00:00:00 | 182700.0 | NaN | Y | A | 38.8 | 41 | 39 | 37.06 | NaN | -10.906447 | 2.326709 | 5.622879 | 9.5492 | 5.832929 |
| 4 | 4 | C | 2019-11-21 00:00:00 | 185853.0 | NaN | Y | A | 36.59 | 38.44 | 36.43 | 35.14 | NaN | -0.076687 | 5.828221 | 7.151074 | 7.457822 | 6.812372 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 28637 | 14316 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.000000 |
| 28638 | 14317 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.000000 |
| 28639 | 14318 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.000000 |
| 28640 | 14319 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.000000 |
| 28641 | 14320 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.000000 |
28642 rows × 17 columns
temp_df = pd.read_excel('combined_files.xlsx')
cols = ['Motor\nS/N']
temp_df.loc[:,cols] = df.loc[:,cols].ffill()
temp_df['Motor\nS/N'] = temp_df['Motor\nS/N'].str.replace('-',"")
temp_df['Motor\nS/N'] = temp_df['Motor\nS/N'].str.replace(' ',"")
#temp_df['Motor\nS/N'] = temp_df['Motor\nS/N'].str.replace('25462002',"254620020")
temp_df['Motor\nS/N'] = temp_df['Motor\nS/N'].str.replace('AO11603',"A011603")
motor_set = sorted([str(motor_sn) for motor_sn in set(temp_df['Motor\nS/N'])])
motor_set
len(motor_set)
69
motor_set
['0AIF003',
'254620010',
'254620011',
'254620012',
'254620013',
'254620014',
'254620015',
'254620017',
'254620019',
'25462002',
'254620020',
'254620021',
'254620022',
'254620023',
'254620024',
'254620025',
'254620026',
'25462003',
'25462004',
'25462006',
'25462007',
'25462008',
'25462009',
'25462025',
'25882001',
'A011603',
'A021602',
'B011604',
'B021601',
'HOAA002',
'HOAA003',
'ISCAA531001',
'OAIF001',
'OAIF002',
'Othermotor',
'ROAA002',
'ROAA003',
'SCAA003008',
'SCAA903007',
'SLCP4328001',
'SLCP43288002',
'SLMA002',
'SLMA003',
'SLMA006',
'SLMA007',
'SLMA008',
'SLMA009',
'SLMA010',
'SLMA013',
'SLMA016',
'SLMA018',
'SLMA019',
'SLMA020',
'SLMA021',
'SLMA022',
'SLMA023',
'SLMA024',
'SLMA025',
'SLMA026',
'SLMA027',
'SLMA028',
'SLMA030',
'SLMA031',
'SLMA032',
'SLMA033',
'SLMA034',
'SLMA036',
'SLMA037',
'nan']
temp_df.columns
temp_df.rename(columns={'Carbon Brush Length (mm)':'Pos1_Len',
'Unnamed: 7':'Pos2_Len',
'Unnamed: 8':'Pos3_Len',
'Unnamed: 9':'Pos4_Len',
'Wear rate per 10,000 km':'Pos1_Wear_Rate',
'Unnamed: 12':'Pos2_Wear_Rate',
'Unnamed: 13':'Pos3_Wear_Rate',
'Unnamed: 14':'Pos4_Wear_Rate',
}, inplace=True)
temp_df=temp_df[['Date','Motor\nS/N','Pos1_Len','Pos2_Len','Pos3_Len','Pos4_Len','Pos1_Wear_Rate','Pos2_Wear_Rate','Pos3_Wear_Rate','Pos4_Wear_Rate','Motor\nwear\nrate']]
temp_df.dropna(subset=['Motor\nwear\nrate','Date','Motor\nS/N'], inplace=True)
temp_df.reset_index(inplace=True, drop=True)
len(temp_df)
6091
# Clean Data
import time
from datetime import datetime
from time import mktime
for df_entry in range(len(temp_df)-1,-1,-1):
try:
if type(temp_df['Date'][df_entry]) == str:
print(temp_df['Date'][df_entry])
temp_df.drop(df_entry, inplace=True)
except:
print(temp_df['Date'][df_entry])
temp_df.reset_index(inplace=True, drop=True)
len(temp_df)
02/27/21
29/09/20q
02/27/21
05/04/21`
27/04/021
02/27/21
29/09/20q
02/27/21
6083
temp_df['Pos_Wear_Variance'] = 0
temp_df['Pos_Len_Variance'] = 0
for df_entry in range(len(temp_df)-1,-1,-1):
#print(temp_df['Pos1_Wear_Rate'][df_entry], temp_df['Pos2_Wear_Rate'][df_entry], temp_df['Pos3_Wear_Rate'][df_entry], temp_df['Pos4_Wear_Rate'][df_entry])
try:
row_wear_mean = (temp_df['Pos1_Wear_Rate'][df_entry] + temp_df['Pos2_Wear_Rate'][df_entry] + temp_df['Pos3_Wear_Rate'][df_entry] + temp_df['Pos4_Wear_Rate'][df_entry])/4
temp_df['Pos_Wear_Variance'][df_entry] = (temp_df['Pos1_Wear_Rate'][df_entry] - row_wear_mean)**2 + (temp_df['Pos2_Wear_Rate'][df_entry] - row_wear_mean)**2 + (temp_df['Pos3_Wear_Rate'][df_entry] - row_wear_mean)**2 + (temp_df['Pos4_Wear_Rate'][df_entry] - row_wear_mean)**2
row_len_mean = (temp_df['Pos1_Len'][df_entry] + temp_df['Pos2_Len'][df_entry] + temp_df['Pos3_Len'][df_entry] + temp_df['Pos4_Len'][df_entry])/4
temp_df['Pos_Len_Variance'][df_entry] = (temp_df['Pos1_Len'][df_entry] - row_len_mean)**2 + (temp_df['Pos2_Len'][df_entry] - row_len_mean)**2 + (temp_df['Pos3_Len'][df_entry] - row_len_mean)**2 + (temp_df['Pos4_Len'][df_entry] - row_len_mean)**2
except:
pass
temp_df['Pos_Wear_Variance'].describe()
count 6.064000e+03
mean 3.917391e+04
std 2.824995e+06
min 0.000000e+00
25% 5.724688e-01
50% 2.997480e+00
75% 1.491303e+01
max 2.196675e+08
Name: Pos_Wear_Variance, dtype: float64
temp_df['Pos_Len_Variance'].describe()
count 6068.000000
mean 15.575714
std 50.673626
min 0.000000
25% 0.786494
50% 3.888075
75% 13.252250
max 2090.210000
Name: Pos_Len_Variance, dtype: float64
temp_df['Pos_Wear_Variance'].quantile([0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.95,0.99,0.999])
0.100 0.000000
0.200 0.292992
0.300 0.928441
0.400 1.730724
0.500 2.997480
0.600 5.375859
0.700 10.003303
0.800 24.440275
0.900 93.469240
0.950 287.044386
0.990 2449.510376
0.999 250552.200000
Name: Pos_Wear_Variance, dtype: float64
temp_df['Pos_Len_Variance'].quantile([0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.95,0.99,0.999])
0.100 0.045800
0.200 0.499445
0.300 1.117035
0.400 2.143980
0.500 3.888075
0.600 6.388555
0.700 10.471615
0.800 16.760570
0.900 30.304700
0.950 49.685735
0.990 257.147840
0.999 495.562548
Name: Pos_Len_Variance, dtype: float64
start = datetime(2020, 1, 1)
end = datetime(2022, 3, 30)
filtered_df = temp_df.loc[(temp_df['Date'] >= start)
& (temp_df['Date'] < end)]
filtered_df.sort_values(by=['Motor\nwear\nrate'],ascending=[False],inplace=True)
filtered_df['Motor\nwear\nrate'].describe()
count 5718.000000
mean 20.143974
std 455.472261
min 0.000000
25% 3.351039
50% 4.866994
75% 8.781261
max 25925.000000
Name: Motor\nwear\nrate, dtype: float64
filtered_df['Motor\nwear\nrate'].quantile([0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.95,0.99,0.999])
0.100 0.000000
0.200 3.054668
0.300 3.626772
0.400 4.179889
0.500 4.866994
0.600 5.919157
0.700 7.647813
0.800 10.357053
0.900 15.322252
0.950 24.112265
0.990 98.585213
0.999 990.785714
Name: Motor\nwear\nrate, dtype: float64
print(filtered_df.loc[filtered_df['Motor\nwear\nrate']>filtered_df['Motor\nwear\nrate'].quantile(0.5)][:50])
Date Motor\nS/N Pos1_Len Pos2_Len Pos3_Len Pos4_Len \
2931 2020-04-03 00:00:00 25462006 49.14 49.72 49.11 50.94
1836 2022-01-24 00:00:00 OAIF002 0 0 0 0
4954 2022-01-24 00:00:00 SLMA023 0 0 0 0
4167 2021-06-20 00:00:00 OAIF001 NaN NaN NaN NaN
1800 2021-04-11 00:00:00 ROAA002 51.55 51.3 51.32 51.36
4922 2021-04-11 00:00:00 SLMA023 51.95 52.02 50.5 51.51
1835 2022-01-08 00:00:00 OAIF002 52.16 52.91 52.06 52.19
4953 2022-01-08 00:00:00 SLMA023 52.2 52.09 52.11 52.2
4065 2020-05-30 00:00:00 SLMA019 51.38 52 52.3 51.27
3588 2020-02-03 00:00:00 SLMA022 52.01 52.18 51.95 52.2
1404 2022-01-28 00:00:00 SLMA010 NaN NaN NaN NaN
1405 2022-02-05 00:00:00 SLMA010 NaN NaN NaN NaN
5285 2020-08-06 00:00:00 25462009 51.99 52.3 52.29 51.31
2195 2020-08-06 00:00:00 25462002 52.3 51.61 52.29 51.8
120 2020-09-24 00:00:00 HOAA003 NaN NaN NaN NaN
121 2020-10-02 00:00:00 HOAA003 NaN NaN NaN NaN
4871 2020-03-31 00:00:00 SLMA023 51.06 50.15 51.44 51.54
3755 2020-12-11 00:00:00 SLMA024 46.83 43.98 43.08 44.88
119 2020-09-16 00:00:00 HOAA003 NaN NaN NaN NaN
1401 2021-01-04 00:00:00 SLMA036 37.23 39.12 37.78 39.54
3756 2020-12-19 00:00:00 SLMA024 46.23 43.98 43.1 45.18
1396 2021-12-11 00:00:00 SLMA036 44.94 46.09 45.25 45.71
4872 2020-04-08 00:00:00 SLMA023 50.5 49.55 51.08 51.04
4529 2022-02-05 00:00:00 SLCP43288002 NaN NaN NaN NaN
3546 2021-07-11 00:00:00 SLMA006 52.26 52.15 52.2 52.25
5458 2022-01-05 00:00:00 25462008 52.1 52.21 52.21 52.22
3517 2021-10-31 00:00:00 SLMA016 45.75 46.37 43.3 46.22
1157 2021-08-23 00:00:00 SLMA036 46.87 46.83 45.97 47.73
1399 2021-12-27 00:00:00 SLMA036 28.48 31.2 27.3 31
84 2020-01-28 00:00:00 SLMA037 40.15 44 40.35 42.5
1368 2020-12-22 00:00:00 SLCP4328001 46.03 46.76 45.74 45.94
1158 2021-08-31 00:00:00 SLMA036 42.38 42.21 41.5 43.67
3768 2021-03-18 00:00:00 SLMA024 47.39 47.59 47.8 46.07
1369 2020-12-24 00:00:00 SLCP4328001 46.03 46.63 45.72 45.9
3746 2020-11-17 00:00:00 SLMA036 48.85 49.52 49.44 49.05
536 2021-03-13 00:00:00 HOAA002 40.41 41.75 40.75 41.72
3757 2020-12-27 00:00:00 SLMA024 45.88 43.87 42.84 44.38
3752 2020-12-03 00:00:00 SLMA036 35.67 37.48 40.11 41.33
1159 2021-09-08 00:00:00 SLMA036 41.46 43.25 40.27 42.84
3750 2020-11-25 00:00:00 SLMA036 43.11 43.79 45.5 47.24
3751 2020-12-01 00:00:00 SLMA036 38.81 40.59 42.29 43.92
3744 2020-11-09 00:00:00 SLMA036 38.1 39.76 38.74 39.29
3540 2021-03-05 00:00:00 SLMA037 27.08 30.73 27.9 28.08
1397 2021-12-19 00:00:00 SLMA036 26 28.8 25.4 28.6
3542 2021-03-13 00:00:00 SLMA037 40.06 44.4 39.99 43.37
3747 2020-11-19 00:00:00 SLMA036 48.64 49.1 49.36 48.68
3332 2020-05-19 00:00:00 SLMA007 31.24 36.16 33.85 33.86
1160 2021-09-16 00:00:00 SLMA036 37.7 39.8 36.2 39.4
3748 2020-11-21 00:00:00 SLMA036 47.47 48.23 48.58 48.59
540 2021-07-11 00:00:00 SLMA034 52.3 52.26 52.2 52.22
Pos1_Wear_Rate Pos2_Wear_Rate Pos3_Wear_Rate Pos4_Wear_Rate \
2931 31800 26000.0 32100.0 13800.0
1836 15854.545455 15854.545455 15854.545455 15854.545455
4954 15854.545455 15854.545455 15854.545455 15854.545455
4167 2399.39759 2348.795181 2471.686747 2398.795181
1800 1100.0 1457.142857 1428.571429 1371.428571
4922 528.571429 428.571429 2600 1157.142857
1835 800.0 -2950.0 1300.0 650.0
4953 600.0 1150.0 1050.0 600.0
4065 854.545455 290.909091 18.181818 954.545455
3588 620.0 280.0 740.0 240.0
1404 447.562019 447.562019 447.562019 447.562019
1405 446.797609 446.797609 446.797609 446.797609
5285 412.5 25.0 37.5 1262.5
2195 25.0 887.5 37.5 650.0
120 287.13575 304.761905 240.085288 258.208955
121 270.954357 287.344398 217.91148 237.206086
4871 237.735849 409.433962 166.037736 147.169811
3755 168.923077 256.615385 284.307692 228.923077
119 240.534521 250.612472 213.808463 222.048998
1401 215.263909 188.302425 207.417974 182.310984
3756 133.846154 183.296703 202.637363 156.923077
1396 179.126214 151.213592 171.601942 160.436893
4872 168.518519 256.481481 114.814815 118.518519
4529 156.025213 153.058954 157.693734 166.366333
3546 85.714286 242.857143 171.428571 100.0
5458 244.444444 122.222222 122.222222 111.111111
3517 167.667238 109.005146 145.368782 169.210978
1157 145.333333 146.4 169.333333 122.4
1399 151.943913 134.608031 159.464627 135.882728
84 152.506266 104.260652 150 123.057644
1368 134.115139 118.550107 140.298507 136.034115
1158 129.258778 131.469441 140.702211 112.483745
3768 122.029703 117.079208 111.881188 154.70297
1369 125.8 113.8 132 128.4
3746 135.019455 108.949416 112.062257 127.237354
536 127.7897 113.412017 124.141631 113.733906
3757 92.929293 121.933622 136.796537 114.574315
3752 142.168675 129.518072 102.048193 87.46988
1159 120.80089 100.889878 134.03782 105.450501
3750 151.851852 151.587302 104.232804 47.883598
3751 146.279762 126.636905 105.208333 70.833333
3744 119.444444 105.701754 117.397661 104.824561
3540 117.84213 100.794021 114.012144 113.171415
1397 116.614976 104.209127 119.273372 105.095259
3542 131.545064 84.978541 132.296137 96.030043
3747 119.869707 104.885993 96.416938 118.566775
3332 123.563892 94.724502 108.264947 108.206331
1160 112.288786 96.159754 123.809524 99.231951
3748 126.963351 107.068063 97.905759 97.643979
540 28.571429 85.714286 171.428571 142.857143
Motor\nwear\nrate Pos_Wear_Variance Pos_Len_Variance
2931 25925.000000 2.196675e+08 2.196675
1836 15854.545455 0.000000e+00 0.000000
4954 15854.545455 0.000000e+00 0.000000
4167 2404.668675 7.675552e+03 NaN
1800 1339.285714 8.015306e+04 0.039275
4922 1178.571429 3.005918e+06 1.472900
1835 916.666667 1.144500e+07 0.457800
4953 850.000000 2.550000e+05 0.010200
4065 529.545455 6.046901e+05 0.731675
3588 470.000000 1.844000e+05 0.046100
1404 447.562019 0.000000e+00 NaN
1405 446.797609 0.000000e+00 NaN
5285 434.375000 1.011367e+06 0.647275
2195 400.000000 5.721875e+05 0.366200
120 272.547974 2.509974e+03 NaN
121 253.354080 2.982047e+03 NaN
4871 240.094340 4.280082e+04 1.202275
3755 234.692308 7.301183e+03 7.711875
119 231.751114 8.489688e+02 NaN
1401 198.323823 7.265095e+02 3.570075
3756 169.175824 2.717389e+03 5.625675
1396 165.594660 4.526080e+02 0.768275
4872 164.583333 1.305963e+04 1.523275
4529 158.286059 9.807572e+01 NaN
3546 150.000000 1.571429e+04 0.007700
5458 150.000000 1.197500e+04 0.009700
3517 147.813036 2.364088e+03 6.145400
1157 145.866667 1.101938e+03 1.549600
1399 145.474825 4.476592e+02 11.020300
84 132.456140 1.593112e+03 10.145000
1368 132.249467 2.702638e+02 0.594475
1158 128.478544 4.148058e+02 2.453000
3768 126.423267 1.117829e+03 1.824475
1369 125.000000 1.866400e+02 0.466600
3746 120.817121 4.604158e+02 0.304100
536 119.769313 1.602851e+02 1.392275
3757 116.558442 1.000746e+03 4.806075
3752 115.301205 1.874205e+03 19.563275
1159 115.294772 6.860298e+02 5.544500
3750 113.888889 7.312295e+03 10.271400
3751 112.239583 3.129933e+03 14.506675
3744 111.842105 1.756096e+02 1.536275
3540 111.454928 1.639370e+02 7.514675
1397 111.298183 1.806029e+02 9.200000
3542 111.212446 1.776661e+03 15.432500
3747 109.934853 3.814364e+02 0.359500
3332 108.689918 4.166824e+02 12.127275
1160 107.872504 4.853398e+02 8.227500
3748 107.395288 5.681553e+02 0.829075
540 107.142857 1.204082e+04 0.005900
columns = ['Date', 'Motor\nwear\nrate']
for motor_x_sn in motor_set:
motor_x_data = temp_df[columns].loc[temp_df['Motor\nS/N'] == motor_x_sn].sort_values(by=['Date'],ascending=[True])
motor_x_data.set_index('Date',inplace=True)
motor_x_data["2018-05-20":"2022-05-21"].plot(kind='line',title=motor_x_sn, figsize=(16,12))
columns = ['Date', 'Motor\nwear\nrate']
burn_motor_set = ['SLMA036','SLMA022','SLMA021','SLMA032']
for motor_x_sn in burn_motor_set:
motor_x_data = temp_df[columns].loc[temp_df['Motor\nS/N'] == motor_x_sn].sort_values(by=['Date'],ascending=[True])
motor_x_data.set_index('Date',inplace=True)
motor_x_data["2018-05-20":"2022-05-21"].plot(kind='line',title=motor_x_sn, figsize=(16,12))
columns = ['Date', 'Motor\nwear\nrate']
burn_motor_set = ['SLMA036','SLMA022','SLMA021','SLMA032']
start = datetime(2020, 1, 1)
end = datetime(2022, 3, 30)
#based on how many motors can be attended to at any point in time, derived from percentile
threshold = 10.0
for motor_x_sn in burn_motor_set:
exceed_threshold = 0
motor_x_data = temp_df[columns].loc[(temp_df['Motor\nS/N'] == motor_x_sn) & (temp_df['Date'] >= start) & (temp_df['Date'] <= end)].sort_values(by=['Date'],ascending=[True])
motor_x_data.reset_index(inplace=True,drop=True)
motor_x_data['Days_From_Prev_Measurement'] = 0
for df_entry in range(1,len(motor_x_data)-1):
motor_x_data['Days_From_Prev_Measurement'][df_entry] = motor_x_data['Date'][df_entry] - motor_x_data['Date'][df_entry-1]
motor_x_data.set_index('Date',inplace=True, drop=True)
motor_x_data["2018-05-20":"2022-05-21"].plot(kind='line',title=motor_x_sn, figsize=(16,8))
motor_x_data['Days_From_Prev_Measurement'] = motor_x_data['Days_From_Prev_Measurement'].astype('timedelta64[D]')
motor_x_data['Days_From_Prev_Measurement'] = motor_x_data['Days_From_Prev_Measurement'].dt.days
for df_entry in range(1,len(motor_x_data)-1):
if motor_x_data['Motor\nwear\nrate'][df_entry] > threshold:
exceed_threshold += motor_x_data['Days_From_Prev_Measurement'][df_entry]
print('Percentage threshold exceedance: ', exceed_threshold/sum(motor_x_data['Days_From_Prev_Measurement']))
Percentage threshold exceedance: 0.5725490196078431
Percentage threshold exceedance: 0.42359249329758714
Percentage threshold exceedance: 0.46
Percentage threshold exceedance: 0.23940149625935161
import matplotlib.pyplot as plt
columns = ['Date', 'Motor\nwear\nrate']
burning_motor_set = []
start = datetime(2021, 11, 1)
end = datetime(2022, 2, 28)
#based on how many motors can be attended to at any point in time, derived from percentile
threshold = 15.3
exceedance_percentage_threshold = 0.20
for motor_x_sn in motor_set:
exceed_threshold = 0
motor_x_data = temp_df[columns].loc[(temp_df['Motor\nS/N'] == motor_x_sn) & (temp_df['Date'] >= start) & (temp_df['Date'] <= end)].sort_values(by=['Date'],ascending=[True])
motor_x_data.reset_index(inplace=True,drop=True)
motor_x_data['Days_From_Prev_Measurement'] = 0
motor_x_data['Days_From_Latest_Measurement'] = 0
for df_entry in range(1,len(motor_x_data)-1):
motor_x_data['Days_From_Prev_Measurement'][df_entry] = motor_x_data['Date'][df_entry] - motor_x_data['Date'][df_entry-1]
motor_x_data['Days_From_Latest_Measurement'][df_entry] = motor_x_data['Date'][df_entry] - motor_x_data['Date'][0]
for df_entry in range(len(motor_x_data)-1,1,-1):
if (motor_x_data['Motor\nwear\nrate'][df_entry] == 0) and (motor_x_data['Motor\nwear\nrate'][df_entry-1] == 0):
motor_x_data.drop(df_entry, inplace=True)
motor_x_data.reset_index(inplace=True,drop=True)
motor_x_data.set_index('Date',inplace=True, drop=True)
motor_x_data['Days_From_Prev_Measurement'] = motor_x_data['Days_From_Prev_Measurement'].astype('timedelta64[D]')
motor_x_data['Days_From_Prev_Measurement'] = motor_x_data['Days_From_Prev_Measurement'].dt.days
motor_x_data['Days_From_Latest_Measurement'] = motor_x_data['Days_From_Latest_Measurement'].astype('timedelta64[D]')
motor_x_data['Days_From_Latest_Measurement'] = motor_x_data['Days_From_Latest_Measurement'].dt.days
for df_entry in range(1,len(motor_x_data)-1):
if motor_x_data['Motor\nwear\nrate'][df_entry] > threshold:
exceed_threshold += motor_x_data['Days_From_Prev_Measurement'][df_entry]
# set hard limit for graph visibility
if motor_x_data['Motor\nwear\nrate'][df_entry] > 100:
motor_x_data['Motor\nwear\nrate'][df_entry] = 100
if exceed_threshold/max(1,sum(motor_x_data['Days_From_Prev_Measurement'])) > exceedance_percentage_threshold:
burning_motor_set.append((motor_x_sn,exceed_threshold/sum(motor_x_data['Days_From_Prev_Measurement'])))
#print(motor_x_sn, ' percentage threshold exceedance: ', exceed_threshold/sum(motor_x_data['Days_From_Prev_Measurement']))
plt.figure(motor_x_sn)
motor_x_data['Motor\nwear\nrate'].plot(kind='line',title=motor_x_sn, figsize=(16,8))
print('Burning Motors')
for motor,score in sorted(burning_motor_set, key=lambda x: x[1], reverse=True)[10:]:
print(motor,score)
print('Number of Burning Motors: ',len(burning_motor_set))
Burning Motors
OAIF001 0.3448275862068966
SLMA025 0.3402061855670103
ROAA002 0.3333333333333333
25462003 0.2962962962962963
25882001 0.2727272727272727
254620021 0.23684210526315788
SLMA030 0.23076923076923078
Number of Burning Motors: 17
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
import math
columns = ['Date', 'Motor\nwear\nrate']
burning_motor_set = []
highscore_motor_set = []
motor_data_set = {}
start = datetime(2021, 12, 16)
end = datetime(2022, 3, 16)
date_multiplier_table = decay([30,30,30,999],[0.1,0.05,0.01,0])
#based on how many motors can be attended to at any point in time, derived from percentile
threshold = 15.3
exceedance_percentage_threshold = 0.20
min_replacements = 5
for motor_x_sn in motor_set:
exceed_threshold = 0
number_replacements = 0
motor_x_data = temp_df[columns].loc[(temp_df['Motor\nS/N'] == motor_x_sn) & (temp_df['Date'] >= start) & (temp_df['Date'] <= end)].sort_values(by=['Date'],ascending=[True])
motor_x_data.reset_index(inplace=True,drop=True)
motor_x_data['Days_From_Prev_Measurement'] = 0
motor_x_data['Days_From_Latest_Measurement'] = timedelta(days=0)
for df_entry in range(1,len(motor_x_data)-1):
motor_x_data['Days_From_Prev_Measurement'][df_entry] = motor_x_data['Date'][df_entry] - motor_x_data['Date'][df_entry-1]
motor_x_data['Days_From_Latest_Measurement'][df_entry] = motor_x_data['Date'][df_entry] - motor_x_data['Date'][0]
for df_entry in range(len(motor_x_data)-1,1,-1):
if (motor_x_data['Motor\nwear\nrate'][df_entry] == 0) and (motor_x_data['Motor\nwear\nrate'][df_entry-1] == 0):
motor_x_data.drop(df_entry, inplace=True)
motor_x_data.reset_index(inplace=True,drop=True)
#get data for only last 3 motor replacements
for df_entry in range(len(motor_x_data)-1,1,-1):
if (motor_x_data['Motor\nwear\nrate'][df_entry] == 0):
number_replacements += 1
if number_replacements == min_replacements:
motor_x_data = motor_x_data[df_entry:]
break
motor_x_data.reset_index(inplace=True,drop=True)
#calculate score for wear-date measurements
motor_x_data['Score'] = 0
motor_x_data['Exceeded'] = 0
for df_entry in range(len(motor_x_data)-1):
#date score multiplier
date_multiplier = date_multiplier_table[motor_x_data['Days_From_Latest_Measurement'][df_entry].days]
#exceedance score
exceedance_score = max(motor_x_data['Motor\nwear\nrate'][df_entry]-threshold,0)
if exceedance_score:
motor_x_data['Exceeded'][df_entry] = 1
#combo multiplier
earlier_entry = df_entry-1
combo_x = 1.1
while earlier_entry >= 0 and motor_x_data['Exceeded'][earlier_entry]:
combo_x *= combo_x
earlier_entry -= 1
motor_x_data['Score'][df_entry] = min(combo_x * date_multiplier * exceedance_score,9999)
# print(combo_x,date_multiplier,exceedance_score)
# print(combo_x * date_multiplier * exceedance_score)
pass
motor_x_data.set_index('Date',inplace=True, drop=True)
motor_x_data['Days_From_Prev_Measurement'] = motor_x_data['Days_From_Prev_Measurement'].astype('timedelta64[D]')
motor_x_data['Days_From_Prev_Measurement'] = motor_x_data['Days_From_Prev_Measurement'].dt.days
# motor_x_data['Days_From_Latest_Measurement'] = motor_x_data['Days_From_Latest_Measurement'].astype('timedelta64[D]')
# motor_x_data['Days_From_Latest_Measurement'] = motor_x_data['Days_From_Latest_Measurement'].dt.days
for df_entry in range(1,len(motor_x_data)):
if motor_x_data['Motor\nwear\nrate'][df_entry] > threshold:
exceed_threshold += motor_x_data['Days_From_Prev_Measurement'][df_entry]
# set hard limit for graph visibility
if motor_x_data['Motor\nwear\nrate'][df_entry] > 50:
motor_x_data['Motor\nwear\nrate'][df_entry] = 50
if exceed_threshold/max(1,sum(motor_x_data['Days_From_Prev_Measurement'])) > exceedance_percentage_threshold:
burning_motor_set.append((motor_x_sn,exceed_threshold/sum(motor_x_data['Days_From_Prev_Measurement'])))
#print(motor_x_sn, ' percentage threshold exceedance: ', exceed_threshold/sum(motor_x_data['Days_From_Prev_Measurement']))
# plt.figure(motor_x_sn)
# motor_x_data['Motor\nwear\nrate'].plot(kind='line',title=motor_x_sn, figsize=(16,8))
motor_data_set[motor_x_sn] = motor_x_data
highscore_motor_set.append((motor_x_sn,sum(motor_x_data['Score'])))
print('------------------------------------------------REPORT TIME-----------------------------------------------')
print('**Burning Motors:**')
sorted_burning_motors = sorted(burning_motor_set, key=lambda x: x[1], reverse=True)
for burning_motor,score in sorted_burning_motors:
print(burning_motor,score)
print()
print('**Number of Burning Motors:** ',len(burning_motor_set))
print()
print('**Motor Scores:**')
sorted_motor_scores = sorted(highscore_motor_set, key=lambda x: x[1], reverse=True)
for motor,motor_score in sorted_motor_scores:
if motor_score > 0:
print(motor,motor_score)
------------------------------------------------REPORT TIME-----------------------------------------------
**Burning Motors:**
SLMA010 1.0
SLMA019 1.0
SLMA032 1.0
SLMA036 1.0
SCAA003008 0.9
SLMA018 0.875
SLMA022 0.8421052631578947
SLMA025 0.7
OAIF002 0.6666666666666666
SLMA021 0.6
254620023 0.5949367088607594
25882001 0.5
25462003 0.375
SLMA023 0.22727272727272727
**Number of Burning Motors:** 14
**Motor Scores:**
SLMA032 29527
SLMA023 14589
OAIF002 4560
SLMA018 2499
SLMA010 2363
SLMA036 1327
25462008 770
SLCP43288002 605
SCAA003008 403
25462007 214
SLMA022 156
254620023 109
25882001 104
SLMA025 92
25462003 88
SLMA019 51
SLMA021 44
25462006 13
254620010 6
254620021 3
Othermotor 3
for motor_x_sn, exeedance_percentage in sorted_burning_motors:
motor_x_data = motor_data_set[motor_x_sn]
plt.figure(motor_x_sn)
motor_x_data['Motor\nwear\nrate'].plot(kind='line',title=str(motor_x_sn) + ' | ' + str(exeedance_percentage), figsize=(16,8))
for motor_x_sn, score in sorted(highscore_motor_set, key=lambda x: x[1], reverse=True):
if score > 0:
motor_x_data = motor_data_set[motor_x_sn]
plt.figure(motor_x_sn)
motor_x_data['Motor\nwear\nrate'].plot(kind='line',title=str(motor_x_sn) + ' | ' + str(score), figsize=(16,8))
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
import math
columns = ['Date', 'Motor\nwear\nrate']
burning_motor_set = []
highscore_motor_set = []
motor_data_set = {}
start = datetime(2021, 10, 9)
end = datetime(2022, 1, 9)
date_multiplier_table = decay([30,30,30,999],[0.1,0.05,0.01,0])
#based on how many motors can be attended to at any point in time, derived from percentile
threshold = 15.3
exceedance_percentage_threshold = 0.20
min_replacements = 2
for motor_x_sn in motor_set:
exceed_threshold = 0
number_replacements = 0
motor_x_data = temp_df[columns].loc[(temp_df['Motor\nS/N'] == motor_x_sn) & (temp_df['Date'] >= start) & (temp_df['Date'] <= end)].sort_values(by=['Date'],ascending=[True])
motor_x_data.reset_index(inplace=True,drop=True)
motor_x_data['Days_From_Prev_Measurement'] = 0
motor_x_data['Days_From_Latest_Measurement'] = timedelta(days=0)
for df_entry in range(1,len(motor_x_data)-1):
motor_x_data['Days_From_Prev_Measurement'][df_entry] = motor_x_data['Date'][df_entry] - motor_x_data['Date'][df_entry-1]
motor_x_data['Days_From_Latest_Measurement'][df_entry] = motor_x_data['Date'][df_entry] - motor_x_data['Date'][0]
for df_entry in range(len(motor_x_data)-1,1,-1):
if (motor_x_data['Motor\nwear\nrate'][df_entry] == 0) and (motor_x_data['Motor\nwear\nrate'][df_entry-1] == 0):
motor_x_data.drop(df_entry, inplace=True)
motor_x_data.reset_index(inplace=True,drop=True)
#get data for only last 3 motor replacements
for df_entry in range(len(motor_x_data)-1,1,-1):
if (motor_x_data['Motor\nwear\nrate'][df_entry] == 0):
number_replacements += 1
motor_x_data.reset_index(inplace=True,drop=True)
#calculate score for wear-date measurements
motor_x_data['Score'] = 0
motor_x_data['Exceeded'] = 0
for df_entry in range(len(motor_x_data)-1):
#date score multiplier
date_multiplier = date_multiplier_table[motor_x_data['Days_From_Latest_Measurement'][df_entry].days]
#exceedance score
exceedance_score = max(motor_x_data['Motor\nwear\nrate'][df_entry]-threshold,0)
if exceedance_score:
motor_x_data['Exceeded'][df_entry] = 1
#combo multiplier
earlier_entry = df_entry-1
combo_x = 1.1
while earlier_entry >= 0 and motor_x_data['Exceeded'][earlier_entry]:
combo_x *= combo_x
earlier_entry -= 1
motor_x_data['Score'][df_entry] = min(combo_x * date_multiplier * exceedance_score,9999)
# print(combo_x,date_multiplier,exceedance_score)
# print(combo_x * date_multiplier * exceedance_score)
pass
motor_x_data.set_index('Date',inplace=True, drop=True)
motor_x_data['Days_From_Prev_Measurement'] = motor_x_data['Days_From_Prev_Measurement'].astype('timedelta64[D]')
motor_x_data['Days_From_Prev_Measurement'] = motor_x_data['Days_From_Prev_Measurement'].dt.days
# motor_x_data['Days_From_Latest_Measurement'] = motor_x_data['Days_From_Latest_Measurement'].astype('timedelta64[D]')
# motor_x_data['Days_From_Latest_Measurement'] = motor_x_data['Days_From_Latest_Measurement'].dt.days
for df_entry in range(1,len(motor_x_data)):
if motor_x_data['Motor\nwear\nrate'][df_entry] > threshold:
exceed_threshold += motor_x_data['Days_From_Prev_Measurement'][df_entry]
# set hard limit for graph visibility
if motor_x_data['Motor\nwear\nrate'][df_entry] > 50:
motor_x_data['Motor\nwear\nrate'][df_entry] = 50
if exceed_threshold/max(1,sum(motor_x_data['Days_From_Prev_Measurement'])) > exceedance_percentage_threshold:
burning_motor_set.append((motor_x_sn,exceed_threshold/sum(motor_x_data['Days_From_Prev_Measurement'])))
#print(motor_x_sn, ' percentage threshold exceedance: ', exceed_threshold/sum(motor_x_data['Days_From_Prev_Measurement']))
# plt.figure(motor_x_sn)
# motor_x_data['Motor\nwear\nrate'].plot(kind='line',title=motor_x_sn, figsize=(16,8))
motor_data_set[motor_x_sn] = motor_x_data
highscore_motor_set.append((motor_x_sn,sum(motor_x_data['Score']),number_replacements))
print('------------------------------------------------REPORT TIME-----------------------------------------------')
print('**Burning Motors:**')
sorted_burning_motors = sorted(burning_motor_set, key=lambda x: x[1], reverse=True)
for burning_motor,score in sorted_burning_motors:
print(burning_motor,score)
print()
print('**Number of Burning Motors:** ',len(burning_motor_set))
print()
print('**Motor Scores:**')
sorted_motor_scores = sorted(highscore_motor_set, key=lambda x: x[1], reverse=True)
for motor,motor_score,num_changes in sorted_motor_scores:
if motor_score > 0:
print(motor,motor_score,f'Replaced {num_changes} times.')
for motor_x_sn, exeedance_percentage in sorted(burning_motor_set, key=lambda x: x[1], reverse=True):
motor_x_data = motor_data_set[motor_x_sn]
plt.figure(motor_x_sn)
motor_x_data['Motor\nwear\nrate'].plot(kind='line',title=str(motor_x_sn) + ' | ' + str(exeedance_percentage), figsize=(16,8))
for motor_x_sn, score in sorted(highscore_motor_set, key=lambda x: x[1], reverse=True):
if score > 0:
motor_x_data = motor_data_set[motor_x_sn]
plt.figure(motor_x_sn)
motor_x_data['Motor\nwear\nrate'].plot(kind='line',title=str(motor_x_sn) + ' | ' + str(score), figsize=(16,8))
<ipython-input-53-c6d77653c97f>:4: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).
plt.figure(motor_x_sn)
#takes in the expected number of days (int), the interval (list) over which rate changes and the rates of decrease (list)
def decay(intervals,rates):
if len(intervals) != len(rates):
print('ERROR: INTERVAL AND RATES NOT EQUAL LENGTH')
return 0
decay_table = []
weight = 1
for interval,rate in zip(intervals,rates):
count = 0
while count < interval:
decay_table.append(weight)
weight -= rate
count += 1
min_weight = min(decay_table)
if min_weight < 0:
decay_table = [weight + -min_weight + 1 for weight in decay_table]
return decay_table
plt.plot([x for x in range(sum([30,30,30,30,30,30,999]))], decay([30,30,30,30,30,30,999],[0.001,0.003,0.005,0.008,0.012,0.018,0]))
[<matplotlib.lines.Line2D at 0x24d34754fd0>]
plt.plot([x for x in range(sum([30,30,30,999]))], decay([30,30,30,999],[0.1,0.05,0.01,0]))
[<matplotlib.lines.Line2D at 0x201aaf22370>]
#Cost function which polynomially sets the weight to half by 90 day mark (i.e. measurements beyond 90 days get less than 0.5 weightage)
[1-x*0.01+2.24 for x in range(1,30)]+[1-x*0.04+(0.03*30)+2.24 for x in range(30,60)]+[1-x*0.06+(0.035*60)+2.24 for x in range(60,90)]
[3.2300000000000004,
3.22,
3.21,
3.2,
3.1900000000000004,
3.18,
3.17,
3.16,
3.1500000000000004,
3.14,
3.1300000000000003,
3.12,
3.1100000000000003,
3.1,
3.0900000000000003,
3.08,
3.0700000000000003,
3.0600000000000005,
3.0500000000000003,
3.04,
3.0300000000000002,
3.0200000000000005,
3.0100000000000002,
3.0,
2.99,
2.9800000000000004,
2.97,
2.96,
2.95,
2.9400000000000004,
2.9000000000000004,
2.8600000000000003,
2.8200000000000003,
2.7800000000000002,
2.74,
2.7,
2.66,
2.62,
2.58,
2.54,
2.5,
2.46,
2.42,
2.38,
2.34,
2.3,
2.26,
2.22,
2.18,
2.14,
2.1,
2.06,
2.02,
1.98,
1.94,
1.9,
1.8599999999999999,
1.8200000000000003,
1.7800000000000002,
1.7400000000000007,
1.6800000000000006,
1.6200000000000006,
1.5600000000000005,
1.5000000000000004,
1.4400000000000004,
1.3800000000000003,
1.3200000000000007,
1.2600000000000002,
1.2000000000000006,
1.1400000000000001,
1.0800000000000005,
1.02,
0.9600000000000004,
0.9000000000000008,
0.8400000000000003,
0.7800000000000007,
0.7200000000000002,
0.6600000000000006,
0.6000000000000001,
0.5400000000000005,
0.48000000000000087,
0.4200000000000004,
0.36000000000000076,
0.30000000000000027,
0.24000000000000066,
0.18000000000000016,
0.12000000000000055,
0.06000000000000094,
4.440892098500626e-16]
For the detection of imbalanced wear of carbon brushes
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
import math
columns = ['Date', 'Motor\nwear\nrate', 'Pos_Len_Variance', 'Pos_Wear_Variance']
brush_len_set = []
brush_wear_set = []
motor_data_set = {}
start = datetime(2022, 1, 9)
end = datetime(2022, 4, 9)
#based on how many motors can be attended to at any point in time, derived from percentile
wear_variance_threshold = 287 #2450
len_variance_threshold = 50 #257
exceedance_percentage_threshold = 0.1
min_replacements = 2
for motor_x_sn in motor_set:
len_var_exceed_threshold = 0
wear_var_exceed_threshold = 0
number_replacements = 0
motor_x_data = temp_df[columns].loc[(temp_df['Motor\nS/N'] == motor_x_sn) & (temp_df['Date'] >= start) & (temp_df['Date'] <= end)].sort_values(by=['Date'],ascending=[True])
motor_x_data.reset_index(inplace=True,drop=True)
motor_x_data['Days_From_Prev_Measurement'] = 0
motor_x_data['Days_From_Latest_Measurement'] = timedelta(days=0)
for df_entry in range(1,len(motor_x_data)-1):
motor_x_data['Days_From_Prev_Measurement'][df_entry] = motor_x_data['Date'][df_entry] - motor_x_data['Date'][df_entry-1]
motor_x_data['Days_From_Latest_Measurement'][df_entry] = motor_x_data['Date'][df_entry] - motor_x_data['Date'][0]
for df_entry in range(len(motor_x_data)-1,1,-1):
if (motor_x_data['Motor\nwear\nrate'][df_entry] == 0) and (motor_x_data['Motor\nwear\nrate'][df_entry-1] == 0):
motor_x_data.drop(df_entry, inplace=True)
motor_x_data.reset_index(inplace=True,drop=True)
#get data for only last x motor replacements
for df_entry in range(len(motor_x_data)-1,1,-1):
if (motor_x_data['Motor\nwear\nrate'][df_entry] == 0):
number_replacements += 1
if number_replacements == min_replacements:
motor_x_data = motor_x_data[df_entry:]
break
motor_x_data.reset_index(inplace=True,drop=True)
#calculate variance exceedance
motor_x_data['Len_Var_Exceeded'] = 0
motor_x_data['Wear_Var_Exceeded'] = 0
motor_x_data.set_index('Date',inplace=True, drop=True)
motor_x_data['Days_From_Prev_Measurement'] = motor_x_data['Days_From_Prev_Measurement'].astype('timedelta64[D]')
motor_x_data['Days_From_Prev_Measurement'] = motor_x_data['Days_From_Prev_Measurement'].dt.days
for df_entry in range(1,len(motor_x_data)):
if motor_x_data['Pos_Len_Variance'][df_entry] > len_variance_threshold:
len_var_exceed_threshold += motor_x_data['Days_From_Prev_Measurement'][df_entry]
if motor_x_data['Pos_Wear_Variance'][df_entry] > wear_variance_threshold:
wear_var_exceed_threshold += motor_x_data['Days_From_Prev_Measurement'][df_entry]
if len_var_exceed_threshold/max(1,sum(motor_x_data['Days_From_Prev_Measurement'])) > exceedance_percentage_threshold:
brush_len_set.append((motor_x_sn,len_var_exceed_threshold/sum(motor_x_data['Days_From_Prev_Measurement'])))
if wear_var_exceed_threshold/max(1,sum(motor_x_data['Days_From_Prev_Measurement'])) > exceedance_percentage_threshold:
brush_wear_set.append((motor_x_sn,wear_var_exceed_threshold/sum(motor_x_data['Days_From_Prev_Measurement'])))
motor_data_set[motor_x_sn] = motor_x_data
print('------------------------------------------------REPORT TIME-----------------------------------------------')
print('**High Length Variance Motors:**')
sorted_brush_len_set = sorted(brush_len_set, key=lambda x: x[1], reverse=True)
for motor,score in sorted_brush_len_set:
print(motor,score)
print()
print('**Number of High Length Variance Motors:** ',len(sorted_brush_len_set))
print()
print('**High Wear Variance Motors::**')
sorted_brush_wear_set = sorted(brush_wear_set, key=lambda x: x[1], reverse=True)
for motor,motor_score in sorted_brush_wear_set:
print(motor,motor_score)
print()
print('**Number of High Wear Variance Motors:** ',len(sorted_brush_wear_set))