Converting a Probability to Fail Into a Time to Failure Metric
By: Shad Griffin
Tags: Probability To Fail, Survival Analysis, Equipment Failure, Time To Failure, Predictive Maintenance

Converting a Probability to Fail Into a Time to Failure Metric

Getting the most out of your Probability to Fail Models

With predictive maintenance problems, there are two common metrics that represent the health of your asset.

The first is a probability to fail. That is, at a given moment in time, what is the probability that your machine will fail. Sometimes, this is represented by a health score. Typically, the health score is one minus the probability to fail times 100.

The second metric is the time until failure. That is, how many days, weeks, months, hours, minutes or seconds do you have until the asset in question stops working.

There are many different ways to calculate these metrics. Probably the most common way to gauge the probability to fail is a machine learning algorithm like logistic regression, random forest or gradient boosted tree (Note, there are many more).

Time to failure models typically rely on some type of survival model. A survival model is a family of techniques based on measuring and predicting expected lifetimes, given certain attributes of an individual or population. For example, will a drug treatment increase or decrease the life of a cancer patient? Or, how much longer will a machine operate if we service it every three months instead of every six months?

What if you have a probability to fail and want to convert it into a time to failure? Is this possible?

Of course it is possible. In fact, there are many ways to do it. In this article, I focus on my favorite technique. Not saying it is the best, just my favorite.

You probably won’t see this in a textbook, but my approach has served me well over the years. My technique is pretty easy and guarantees that your time to failure and probability to fail metrics are perfectly in-synch.

I should also mention that, although this is an equipment failure problem, this technique has many other applications. For example, the probability to churn and expected customer lifetime. Anytime you need to convert a probability of death to a prediction of lifespan, this should work.

1.0 Getting Set-Up

Install all of the relevant Python Libraries

!pip install --upgrade numpy

!pip install imblearn --upgrade

!pip install plotly --upgrade

!pip install chart-studio --upgrade

Import required libraries

import chart_studio.plotly as py

import plotly.graph_objs as go

import numpy as np

import numpy.dual as dual import types

import pandas as pd

import statsmodels.api as sm

import plotly as plotly def __iter__(self): return 0

Import the data from GitHub



!rm P_HAT_DATA.csv

#import from github

!wget #Remove the data if you run this notebook more than once!rm P_HAT_DATA.csv#import from github!wget https://raw.githubusercontent.com/shadgriffin/phat_to_ttf/master/P_HAT_DATA.csv # Convert csv to pandas dataframe

pd_data = pd.read_csv("P_HAT_DATA.csv", sep=",", header=0)

2.0 Data Exporation

pd_data.head()

Our data set is pretty simple. Note that we have panel data. This means we have multiple entities (machines in this case) measured each day for a period of time.

Here is a description of the fields.

ID — ID field that represents a specific machine.

DATE — The date of the observation.

FAILURE_DATE — Day the machine in question failed.

P_FAIL — The probability a machine will fail on a given day. The result of Gradient Boosted Tree Model.

We also need to create another field that indicates the number of days between the day of record and the failure date of the machine. This is the actual time to failure from the historical record.

#convert dates to date format

pd_data['DATE'] = pd.to_datetime(pd_data['DATE'])

pd_data['FAILURE_DATE'] = pd.to_datetime(pd_data['FAILURE_DATE']) pd_data['C'] = pd_data['FAILURE_DATE'] - pd_data['DATE']

pd_data['TIME_TO_FAILURE'] = pd_data['C'] / np.timedelta64(1, 'D')

pd_data=pd_data[['ID','DATE','FAILURE_DATE','P_FAIL','TIME_TO_FAILURE']]

pd_data.head()

Examine the number of rows and columns. The data has 171,094 rows and 5 columns

pd_data.shape

There are 421 machines in the data set

xxxx = pd.DataFrame(pd_data.groupby(['ID']).agg(['count']))

xxxx.shape

Check for dups. There are none

df_failure_thingy=pd_data

df_failure_thingy=df_failure_thingy.drop_duplicates(subset=['ID','DATE'])

df_failure_thingy.shape

Look for null values in the fields — There are none

pd_data.isnull().sum(axis = 0)

3.0 Data transformations and Feature Engineering

Our data is currently at a daily level. We really don’t need that level of detail for this exercise. In fact, if the data has any non-normal properties (it does and this is almost always the case) aggregating a bit usually yields better results.

Next, we will convert the daily data to monthly data.

#create fields that represent the month and year

pd_data['MONTH'] = pd.DatetimeIndex(pd_data['DATE']).month

pd_data['YEAR'] = pd.DatetimeIndex(pd_data['DATE']).year pd_data=pd_data[['ID','MONTH','DATE','YEAR','FAILURE_DATE','P_FAIL','TIME_TO_FAILURE']]

pd_data=pd_data.copy() # aggregate by machine, month and year

YY=pd_data

tips_summed = pd.DataFrame(YY.groupby(['ID','YEAR','MONTH'])[['P_FAIL', 'TIME_TO_FAILURE']].mean()) tips_summed=tips_summed.sort_values(by=['ID','YEAR','MONTH'], ascending=[True,True,True])

plotter=tips_summed

plotter.reset_index(level=0, inplace=True)

plotter.reset_index(level=0, inplace=True)

plotter.reset_index(level=0, inplace=True) pd_data=plotter

pd_data.shape

We now have 5,844 records after aggregating.

In case you haven’t guessed already, we are about to build a model that uses the probability to fail to predict the time to failure. Before we do that, however, let’s examine the relationship betwwen the two variables graphically.

A scatter plot with 5,844 records will probably not be that meaningful, so first we will aggreate the data by using P_FAIL to create groupings. This should give us the essence of the relationship between P_FAIL and the TIME_TO_FAILURE without a bunch of clutter.

#Create percentiles based on P_FAIL

pd_data['P'] = pd.qcut(pd_data['P_FAIL'], 100, labels=np.arange(100, 0,-1))

pd_data.head()

#aggregate the variables by grouping

YY=pd_data

tips_summed = pd.DataFrame(YY.groupby(['P'])[['P_FAIL', 'TIME_TO_FAILURE']].mean()) tips_summed=tips_summed.sort_values(by=['P'], ascending=[True])

plotter=tips_summed

plotter.head(10)

Create a plot with Plotly