Predictive maintenance covers variety of areas, including but not limited to:
To avoid downtimes caused by malfunction of technical equipment, companies follow maintenance schedule to discover and fix potential issues. Nevertheless, with more data (from sensors installed) available there are new possibilities how to make maintenance process better. With AI/ML it is possible to further optimize maintenance schedule.
This has tangible financial implications, imagine two extreme situations:
There is zero tolerance for failure of aircraft engines and so they are checked rather sooner than later. This is a very good example for our sample Use case.
In this Use case we will solve following problem: How much useful life (time) remains for given engine (until it fails)?. This kind of problem is also known as predicting Remaining Useful Life (RUL). From ML perspective this can be framed as forecasting problem.
|Business objective:||Financial: Maximize value of capital, minimize operational costs|
|Business value:||Lower cost, capital utilization|
|Business objective:||Operations: Increase aircraft’s safety|
|Business value:||Enhanced personnel/passengers safety|
import logging import pandas as pd import plotly as plt import plotly.express as px import plotly.graph_objects as go import numpy as np import json import datetime from sklearn.metrics import mean_squared_error, mean_absolute_error import math import tim_client
Credentials and logging
(Do not forget to fill in your credentials in the credentials.json file)
with open('credentials.json') as f: credentials_json = json.load(f) # loading the credentials from credentials.json TIM_URL = 'https://timws.tangent.works/v4/api' # URL to which the requests are sent SAVE_JSON = False # if True - JSON requests and responses are saved to JSON_SAVING_FOLDER JSON_SAVING_FOLDER = 'logs/' # folder where the requests and responses are stored LOGGING_LEVEL = 'INFO'
level = logging.getLevelName(LOGGING_LEVEL) logging.basicConfig(level=level, format='[%(levelname)s] %(asctime)s - %(name)s:%(funcName)s:%(lineno)s - %(message)s') logger = logging.getLogger(__name__)
credentials = tim_client.Credentials(credentials_json['license_key'], credentials_json['email'], credentials_json['password'], tim_url=TIM_URL) api_client = tim_client.ApiClient(credentials) api_client.save_json = SAVE_JSON api_client.json_saving_folder_path = JSON_SAVING_FOLDER
[INFO] 2021-02-08 17:30:27,019 - tim_client.api_client:save_json:66 - Saving JSONs functionality has been disabled [INFO] 2021-02-08 17:30:27,020 - tim_client.api_client:json_saving_folder_path:75 - JSON destination folder changed to logs
Data contain operational information about 100 aircraft engines consolidated into single table with columns about:
Train part of dataset contained information about when (at which cycle) engine failed, based on which RUL variable was created.
Data are sampled on a daily basis.
Original raw data files were consolidated into a single time series file - train file is used for in-sample interval only, test file is use for out-of-sample interval.
Structure of CSV file:
|rul||Remaning useful life (in days)||Target||t-1|
|cycle||Operations cycle no.||Predictor||t+1|
|setting1 ... setting3||Operational settings||Predictor||t+1|
|s1 ... s21||Sensor measurements||Predictor||t+1|
Due to consolidation into a single file timestamps were re-generated to avoid duplicates and be continous (they are not real timestamps from operations records).
Please note that engine_id column is not present in file because it is identifier, and not real measurement/setting.
If we want TIM to do classification the very last record of target must be kept empty (NaN/None). TIM will use all available predictors to classify given record. Furthermore, this situation will be replicated to calculate results for all out-of-sample records during back-testing.
CSV files used in experiments can be downloaded here.
Raw data files were acquired from Microsoft's server:
fpath = 'data_rul.csv' data = tim_client.load_dataset_from_csv_file( fpath , sep=',') data.tail()
5 rows × 27 columns
Visualization of data.
fig = go.Figure() fig.add_trace(go.Scatter( x = data.index, y = data['RUL'] )) fig.update_layout( height = 700, width = 1200, title = 'RUL' ) fig.show()