Название может показаться слишком длинным, но проект - это реальный вариант использования, с которым я столкнулся во время своего опыта. Большинство производственных компаний изменили свою стратегию получения прибыли. Они продают свою продукцию по себестоимости в обмен на то, что хотели получать доход и прибыль, продавая свои услуги и техническое обслуживание, с которыми машины сталкиваются в течение своей жизни.
Чтобы выполнить финансовый план после выхода на рынок после выхода на рынок, всем этим компаниям необходимо предсказать, когда именно оборудование выйдет из строя. До появления достижений в области машинного обучения большинство производственных компаний используют для обзвона своих клиентов через определенные месяцы. с даты покупки машины или по фиксированной шкале времени с даты последнего технического обслуживания. В этом случае клиент может подумать о вариантах или местных точках обслуживания (которые считаются поддельными).
Чтобы удовлетворить вышеперечисленные требования, аналитические группы, работающие над созданием систем раннего оповещения, для прогнозирования условий простоя до того, как он действительно произойдет в оборудовании. Применяя подход, основанный на анализе данных, компании-производители могут обращаться к своим клиентам за месяц до того, как оборудование достигает срока обслуживания, и таким образом превращать их в своих послепродажных клиентов, не теряя доли рынка в бизнесе.
Это была одна из самых сложных проблем, с которыми я имел дело. Нам были предоставлены данные 45 датчиков, которые собирают различные показатели оборудования, такие как температура, значения давления, состояние аварийного напряжения, реактивная мощность в агрегате, угловое расположение валов, ротор и статор, максимальный крутящий момент и т. Д. Зависимой переменной является количество дней Оставшееся до того, как оборудование вышло из строя из-за «регресса», а количество дней, оставшихся на техническое обслуживание, меньше и больше 30 дней для классификации.
Теперь теория готова, давайте перейдем к решению проблем с использованием традиционных алгоритмов машинного обучения и LSTM для классификации.
Загрузка всех необходимых пакетов
import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns import keras from sklearn.preprocessing import MinMaxScaler from sklearn.metrics import confusion_matrix,accuracy_score from keras.models import Sequential from keras.layers import Dense, Dropout, LSTM, Activation from keras.callbacks import EarlyStopping import matplotlib.pyplot as plt plt.style.use(‘ggplot’) %matplotlib inline
Загрузка данных в предпочтительную среду в примере, который я показываю, загружается в python3.6.
train=pd.read_csv(‘../train.txt’,sep=’ ‘,header=None),axis=1) col_names = [‘UnitNumber’, ‘Cycle’, ‘Op_Setting_1’, ‘Op_Setting_2’, ‘Op_Setting_3’, ‘Sensor_1’, ‘Sensor_2’, ‘Sensor_3’, ‘Sensor_4’, ‘Sensor_5’, ‘Sensor_6’, ‘Sensor_7’, ‘Sensor_8’, ‘Sensor_9’, ‘Sensor_10’, ‘Sensor_11’, ‘Sensor_12’, ‘Sensor_13’, ‘Sensor_14’, ‘Sensor_15’, ‘Sensor_16’, ‘Sensor_17’, ‘Sensor_18’, ‘Sensor_19’, ‘Sensor_20’, ‘Sensor_21’] train.columns=col_names print(‘Shape of Train dataset: ‘,dataset_train.shape) train.head()
Код возвращает заголовок фрейма данных с 5 строками и назначенными столбцами.
Shape of Train data set: (20631, 26)
test=pd.read_csv(‘../test.txt’,sep=’‘,header=None).drop([26,27],axis=1) test.columns=col_names print(‘Shape of Test dataset: ‘,dataset_train.shape) test.head()
Код возвращает заголовок фрейма данных с 5 строками и назначенными столбцами.
Shape of Test dataset: (20631, 26)
df=pd.concat([train,test]) max_cycle = df.groupby(‘UnitNumber’)[‘Cycle’].max().reset_index() max_cycle.columns = [‘UnitNumber’, ‘MaxOfCycle’] df_merged = df.merge(max_cycle, left_on=’UnitNumber’, right_on=’UnitNumber’, how=’inner’) Target_Remaining_Useful_Life = df_merged[“MaxOfCycle”] — df_merged[“Cycle”] df_with_target = df_merged[“Target_Remaining_Useful_Life”] = Target_Remaining_Useful_Life df_with_target = df_merged.drop(“MaxOfCycle”, axis=1) df_with_target[df_with_target[‘UnitNumber’] == 1].head(5) target_var = [‘Target_Remaining_Useful_Life’] index_columns_names = [“UnitNumber”,”Cycle”] op_settings_columns = [“Op_Setting_”+str(i) for i in range(1,4)] sensor_columns =[“Sensor_”+str(i) for i in range(1,22)] print(df_with_target.shape) leakage_to_drop = ['UnitNumber', 'Cycle', 'Op_Setting_1', 'Op_Setting_2', 'Op_Setting_3','Sensor_18','Sensor_19'] df_no_leakage = df_with_target.drop(leakage_to_drop, axis = 1) print(df_no_leakage.shape) # set up features and target variable y = df_no_leakage['Target_Remaining_Useful_Life'] X = df_no_leakage.drop(['Target_Remaining_Useful_Life'], axis = 1) df=df_no_leakage corr=df.corr() plt.rcParams[“font.size”] = 12 plt.rcParams[“figure.figsize”] = (len(corr),len(corr)) plt.subplot(1, 1, 1) sns.heatmap(corr, square=True, vmax=1, vmin=-1, center=0,annot=True,fmt=”1.1f”) plt.show
Использование техники ранжирования характеристик для определения лучших характеристик
from sklearn import ensemble rf = ensemble.RandomForestRegressor() single_rf = ensemble.RandomForestRegressor(n_estimators = 200, max_depth = 15) single_rf.fit(X, y) y_pred = single_rf.predict(X) print(“complete”) import matplotlib.pyplot as plt importances = single_rf.feature_importances_ indices = np.argsort(importances)[::-1] feature_names = X.columns f, ax = plt.subplots(figsize=(11, 9)) plt.title(“Feature ranking”, fontsize = 20) plt.bar(range(X.shape[1]), importances[indices], color=”b”, align=”center”) plt.xticks(range(X.shape[1]), indices) #feature_names, rotation=’vertical’) plt.xlim([-1, X.shape[1]]) plt.ylabel(“importance”, fontsize = 18) plt.xlabel(“index of the feature”, fontsize = 18) plt.show() # list feature importance important_features = pd.Series(data=single_rf.feature_importances_,index=X.columns) important_features.sort_values(ascending=False,inplace=True) print(important_features.head(10))
print(train_no_leakage.shape) vars_to_drop = [“Sensor_”+str(i) for i in [5, 15, 9, 17, 4]] df_final = df_no_leakage.drop(vars_to_drop, axis = 1) print(df_final.shape) from sklearn import preprocessing categorical = df_final.select_dtypes(include=['object']) numeric = df_final.select_dtypes(exclude=['object']) print(categorical.columns.values) for name, values in categorical.items(): print(name) dummies = pd.get_dummies(values.str.strip(), prefix = name, dummy_na=True) numeric = pd.concat([numeric, dummies], axis=1) for name in numeric: print(name) if pd.isnull(numeric[name]).sum() > 0: numeric["%s_mi" % (name)] = pd.isnull(numeric[name]) median = numeric[name].median() numeric[name] = numeric[name].apply(lambda x: median if pd.isnull(x) else x) y = numeric['Target_Remaining_Useful_Life'] X = numeric.drop(['Target_Remaining_Useful_Life'], axis = 1)
Применение регрессии случайного леса для прогнозирования оставшегося срока полезного использования до технического обслуживания
import numpy as np from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1234) # choose the model from sklearn.ensemble import RandomForestRegressor rf = ensemble.RandomForestRegressor() # set up 5-fold cross-validation from sklearn import model_selection cv = model_selection.KFold(5) # pipeline standardization and model from sklearn.pipeline import Pipeline pipeline = Pipeline(steps=[(‘standardize’, preprocessing.StandardScaler()) , (‘model’, rf) ]) # tune the model my_min_samples_leaf = [2, 10, 25, 50, 100] my_max_depth = [7, 8, 9, 10, 11, 12] # run the model using gridsearch, select the model with best search from sklearn.model_selection import GridSearchCV optimized_rf = GridSearchCV(estimator=pipeline , cv=cv , param_grid =dict(model__min_samples_leaf = my_min_samples_leaf, model__max_depth = my_max_depth) , scoring = ‘neg_mean_squared_error’ , verbose = 1 , n_jobs = -1 ) optimized_rf.fit(X_train, y_train) # show the best model estimators print(optimized_rf.best_estimator_) # evaluate metrics on holdout from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score y_pred = optimized_rf.predict(X_test) print(“Random Forest Mean Squared Error: “, mean_squared_error(y_test, y_pred)) print(“Random Forest Mean Absolute Error: “, mean_absolute_error(y_test, y_pred)) print(“Random Forest r-squared: “, r2_score(y_test, y_pred))
Применение ElasticNet, которое учитывает регрессию Лассо и Ридж при уменьшении параметров
import numpy as np from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1234) # choose the model from sklearn.linear_model import ElasticNet glm_net = ElasticNet() # set up 5-fold cross-validation from sklearn import model_selection cv = model_selection.KFold(5) # pipeline standardization and model from sklearn.pipeline import Pipeline pipeline = Pipeline(steps=[(‘standardize’, preprocessing.StandardScaler()) , (‘model’, glm_net) ]) # tune the model my_alpha = np.linspace(.01, 1, num=5) my_l1_ratio = np.linspace(.01, 1, num=3) # run the model using gridsearch, select the model with best search from sklearn.model_selection import GridSearchCV optimized_glm_net = GridSearchCV(estimator=pipeline , cv=cv , param_grid =dict(model__l1_ratio = my_l1_ratio, model__alpha = my_alpha) , scoring = ‘neg_mean_squared_error’ , verbose = 1 , n_jobs = -1 ) optimized_glm_net.fit(X_train, y_train) # show the best model estimators print(optimized_glm_net.best_estimator_) # evaluate metrics on holdout from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score y_pred = optimized_glm_net.predict(X_test) print(“GLM Elastic Net Mean Squared Error: “, mean_squared_error(y_test, y_pred)) print(“GLM Elastic Net Mean Absolute Error: “, mean_absolute_error(y_test, y_pred)) print(“GLM Elastic Net r-squared: “, r2_score(y_test, y_pred))
Применение регрессора опорных векторов
import numpy as np from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1234) # choose the model from sklearn import svm from sklearn.svm import SVR svm = svm.SVR() # set up 5-fold cross-validation from sklearn import model_selection cv = model_selection.KFold(5) # pipeline standardization and model from sklearn.pipeline import Pipeline pipeline = Pipeline(steps=[(‘standardize’, preprocessing.StandardScaler()) , (‘model’, svm) ]) # tune the model my_C = [1] my_epsilon = [.05, .1, .15] # run the model using gridsearch, select the model with best search from sklearn.model_selection import GridSearchCV optimized_svm = GridSearchCV(estimator=pipeline , cv=cv , param_grid =dict(model__C = my_C, model__epsilon = my_epsilon) , scoring = ‘neg_mean_squared_error’ , verbose = 1 , n_jobs = -1 ) optimized_svm.fit(X_train, y_train) # show the best model estimators print(optimized_svm.best_estimator_) # evaluate metrics on holdout from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score y_pred = optimized_svm.predict(X_test) print(“SVM Mean Squared Error: “, mean_squared_error(y_test, y_pred)) print(“SVM Mean Absolute Error: “, mean_absolute_error(y_test, y_pred)) print(“SVM r-squared: “, r2_score(y_test, y_pred))
Применение алгоритма повышения градиента
import numpy as np from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1234) # choose the model from sklearn.ensemble import GradientBoostingRegressor gb = ensemble.GradientBoostingRegressor() # set up 5-fold cross-validation from sklearn import model_selection cv = model_selection.KFold(5) # pipeline standardization and model from sklearn.pipeline import Pipeline pipeline = Pipeline(steps=[(‘standardize’, preprocessing.StandardScaler()) , (‘model’, gb) ]) # tune the model my_alpha = [.5, .75, .9] my_n_estimators= [500] my_learning_rate = [0.005, .01] my_max_depth = [4, 5, 6] # run the model using gridsearch, select the model with best search from sklearn.model_selection import GridSearchCV optimized_gb = GridSearchCV(estimator=pipeline , cv=cv , param_grid =dict(model__max_depth = my_max_depth, model__n_estimators = my_n_estimators, model__learning_rate = my_learning_rate, model__alpha = my_alpha) , scoring = ‘neg_mean_squared_error’ , verbose = 1 , n_jobs = -1 ) optimized_gb.fit(X_train, y_train) # show the best model estimators print(optimized_gb.best_estimator_) # evaluate metrics on holdout from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score y_pred = optimized_gb.predict(X_test) print(“Gradient Boosting Mean Squared Error: “, mean_squared_error(y_test, y_pred)) print(“Gradient Boosting Mean Absolute Error: “, mean_absolute_error(y_test, y_pred)) print(“Gradient Boosting r-squared: “, r2_score(y_test, y_pred))
fig, ax = plt.subplots() ax.scatter(y_test, y_pred, edgecolors=(0, 0, 0)) ax.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], ‘k — ‘, lw=4) ax.set_xlabel(‘Actual RUL’) ax.set_ylabel(‘Predicted RUL’) ax.set_title(‘Remaining Useful Life Actual vs. Predicted’) plt.show()
cycles = 15 df_no_leakage[‘Target_15_Cycles’] = np.where(df_no_leakage[‘Target_Remaining_Useful_Life’] <= cycles, 1, 0 ) df_no_leakage.tail(5)
print(train_no_leakage.shape) vars_to_drop = [“Sensor_”+str(i) for i in [5, 15, 9, 17, 4]] target_to_drop = [‘Target_Remaining_Useful_Life’] train_final = train_no_leakage.drop(vars_to_drop, axis = 1) train_final = train_no_leakage.drop(target_to_drop, axis = 1) train_final.tail()
from sklearn import preprocessing categorical = train_final.select_dtypes(include=[‘object’]) numeric = train_final.select_dtypes(exclude=[‘object’]) print(categorical.columns.values) # create dummy variables (if any categorical fields) for name, values in categorical.items(): print(name) dummies = pd.get_dummies(values.str.strip(), prefix = name, dummy_na=True) numeric = pd.concat([numeric, dummies], axis=1) # imputation (if any NULL values) for name in numeric: print(name) if pd.isnull(numeric[name]).sum() > 0: numeric[“%s_mi” % (name)] = pd.isnull(numeric[name]) median = numeric[name].median() numeric[name] = numeric[name].apply(lambda x: median if pd.isnull(x) else x) y = numeric[‘Target_15_Cycles’] X = numeric.drop([‘Target_15_Cycles’], axis = 1)
import numpy as np from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1234) # choose the model from sklearn import ensemble from sklearn.ensemble import RandomForestClassifier rf = ensemble.RandomForestClassifier() # set up 5-fold cross-validation from sklearn import model_selection cv = model_selection.KFold(5) # pipeline standardization and model from sklearn.pipeline import Pipeline pipeline = Pipeline(steps=[(‘standardize’, preprocessing.StandardScaler()) , (‘model’, rf) ]) # tune the model my_min_samples_leaf = [2, 25, 50] my_max_depth = [8, 9, 10, 12] # run the model using gridsearch, select the model with best search from sklearn.model_selection import GridSearchCV optimized_rf = GridSearchCV(estimator=pipeline , cv=cv , param_grid =dict(model__min_samples_leaf = my_min_samples_leaf, model__max_depth = my_max_depth) , scoring = ‘roc_auc’ , verbose = 1 , n_jobs = -1 ) optimized_rf.fit(X_train, y_train) # show the best model estimators y_pred_proba = optimized_rf.predict_proba(X_test)[:, 1] y_pred = optimized_rf.predict(X_test) print(optimized_rf.best_estimator_)
from sklearn.metrics import roc_auc_score, accuracy_score, precision_score, recall_score, confusion_matrix print(“Confusion Matrix:”) print(confusion_matrix(y_test, y_pred)) from sklearn.metrics import classification_report print(“Random Forest Accuracy: “+”{:.1%}”.format(accuracy_score(y_test, y_pred))); print(“Random Forest Precision: “+”{:.1%}”.format(precision_score(y_test, y_pred))); print(“Random Forest Recall: “+”{:.1%}”.format(recall_score(y_test, y_pred))); print(“Classification Report:”) print(classification_report(y_test, y_pred)) from sklearn import metrics fpr, tpr, threshold = metrics.roc_curve(y_test, y_pred_proba) roc_auc = metrics.auc(fpr, tpr) import matplotlib.pyplot as plt plt.title(‘Receiver Operating Characteristic’) plt.plot(fpr, tpr, ‘b’, label = ‘AUC = %0.2f’ % roc_auc) plt.legend(loc = ‘lower right’) plt.plot([0, 1], [0, 1],’r — ‘) plt.xlim([0, 1]) plt.ylim([0, 1]) plt.ylabel(‘True Positive Rate’) plt.xlabel(‘False Positive Rate’) plt.show()
def gen_sequence(id_df, seq_length, seq_cols): df_zeros=pd.DataFrame(np.zeros((seq_length-1,id_df.shape[1])),columns=id_df.columns) id_df=df_zeros.append(id_df,ignore_index=True) data_array = id_df[seq_cols].values num_elements = data_array.shape[0] lstm_array=[] for start, stop in zip(range(0, num_elements-seq_length), range(seq_length, num_elements)): lstm_array.append(data_array[start:stop, :]) return np.array(lstm_array) # function to generate labels def gen_label(id_df, seq_length, seq_cols,label): df_zeros=pd.DataFrame(np.zeros((seq_length-1,id_df.shape[1])),columns=id_df.columns) id_df=df_zeros.append(id_df,ignore_index=True) data_array = id_df[seq_cols].values num_elements = data_array.shape[0] y_label=[] for start, stop in zip(range(0, num_elements-seq_length), range(seq_length, num_elements)): y_label.append(id_df[label][stop]) return np.array(y_label) seq_length=50 seq_cols=numeric.columns.values cycles = 15 df_with_target['Target_15_Cycles'] = np.where(df_with_target['Target_Remaining_Useful_Life'] <= cycles, 1, 0 ) df_with_target.tail(5)
sc=MinMaxScaler() df_with_target[seq_cols]=sc.fit_transform(df_with_target[seq_cols]) X=np.concatenate(list(list(gen_sequence(df_with_target[df_with_target['UnitNumber']==id], seq_length, seq_cols)) for id in df_with_target['UnitNumber'].unique())) print(X.shape) # generate y_train y=np.concatenate(list(list(gen_label(df_with_target[df_with_target['UnitNumber']==id], 50, seq_cols,'Target_15_Cycles')) for id in df_with_target['UnitNumber'].unique())) print(y.shape) X_train, X_test, y_train, y_test = train_test_split(X, y , test_size=0.3, random_state=0)
Применение LSTM с помощью Kera’s
nb_features =X_train.shape[2] timestamp=seq_length model = Sequential() model.add(LSTM( input_shape=(timestamp, nb_features), units=100, return_sequences=True)) model.add(Dropout(0.2)) model.add(LSTM( units=50, return_sequences=False)) model.add(Dropout(0.2)) model.add(Dense(units=1, activation=’sigmoid’)) model.compile(loss=’binary_crossentropy’, optimizer=’adam’, metrics=[‘accuracy’]) model.summary()
model.fit(X_train, y_train, epochs=10, batch_size=200, validation_split=0.05, verbose=1, callbacks = [EarlyStopping(monitor=’val_loss’, min_delta=0, patience=0, verbose=0, mode=’auto’)])
scores = model.evaluate(X_train, y_train, verbose=1, batch_size=200) print(‘Accurracy: {}’.format(scores[1]))
y_pred=model.predict_classes(X_test) y_pred_proba = model.predict_proba(X_test) print(‘Accuracy of model on test data: ‘,accuracy_score(y_test,y_pred)) print(‘Confusion Matrix: \n’,confusion_matrix(y_test,y_pred))
from sklearn.metrics import roc_auc_score, accuracy_score, precision_score, recall_score, confusion_matrix print(“Confusion Matrix:”) print(confusion_matrix(y_test, y_pred)) from sklearn.metrics import classification_report print(“LSTM Accuracy: “+”{:.1%}”.format(accuracy_score(y_test, y_pred))); print(“LSTM Precision: “+”{:.1%}”.format(precision_score(y_test, y_pred))); print(“LSTM Recall: “+”{:.1%}”.format(recall_score(y_test, y_pred))); print(“Classification Report:”) print(classification_report(y_test, y_pred)) from sklearn import metrics fpr, tpr, threshold = metrics.roc_curve(y_test, y_pred_proba) roc_auc = metrics.auc(fpr, tpr) import matplotlib.pyplot as plt plt.title(‘Receiver Operating Characteristic’) plt.plot(fpr, tpr, ‘b’, label = ‘AUC = %0.2f’ % roc_auc) plt.legend(loc = ‘lower right’) plt.plot([0, 1], [0, 1],’r — ‘) plt.xlim([0, 1]) plt.ylim([0, 1]) plt.ylabel(‘True Positive Rate’) plt.xlabel(‘False Positive Rate’) plt.show()
С помощью подхода, которого мы придерживались, мы смогли продемонстрировать, что ранние сигналы могут быть обнаружены, поэтому компании могут поддерживать достаточный запас запасов и выделять нужных специалистов по обслуживанию для удовлетворения и удовлетворения потребностей в обслуживании и техническом обслуживании.
Я надеюсь, что эта статья поможет большинству команд по всему миру справиться с профилактическим обслуживанием.