Elevator Predictive Maintenance

⚠️ Synthetic data. This model was trained and tested on a seeded synthetic month of elevator sensor readings, not on data from a real elevator. The public Kaggle set usually linked to this task (shivamb/elevator-predictive-maintenance-dataset) has no failure label, so the training code generates a month that matches the brief. The numbers below say how well the model learns that generator's degradation pattern. They say nothing about real elevators.

From the last 60 minutes of 11 elevator sensors (one reading per minute), the model predicts whether the elevator will be in a degradation/failure state 10 minutes later. It is a RandomForest (300 trees) on 63 features computed from the window. On the held-out test days of the synthetic month it scores F1 = 0.988 (168 of 170 failure windows caught, 2 false alarms among 1,156 healthy windows) at its tuned threshold of 0.38 (run of 2026-09-25, metrics.json). It beat a Keras 1D-CNN and a Keras LSTM trained on the raw windows.

Model

  • Input: at least 60 rows (one per minute) with the columns temperature, humidity, vibration_rms, vibration_peak, motor_current, motor_rpm, door_cycles, load_kg, acoustic_db, oil_level, power_kw, as a CSV path, CSV text, a DataFrame or a list of row dicts. The last 60 rows are used. An optional timestamp column gives the time of the window end; without it a weekday noon is assumed.
  • Features (model.window_features, 63 in total): mean, std, min, max and least-squares slope of each sensor over the window (55), the top-5 FFT magnitudes of vibration_rms (DC dropped) and its dominant frequency bin (6), and the hour and day of week of the window end (2).
  • Classifier (rf.joblib): scikit-learn RandomForestClassifier, 300 trees, class_weight="balanced", default depth, 10,408 tree nodes in total. P(failure) is the trees' vote share.
  • Decision: flag the elevator for maintenance when P(failure) >= 0.377, the threshold that maximised F1 on the validation days (config.json β†’ threshold).
  • Output of predict(data): {"failure": p, "healthy": 1 - p}.
  • config.json holds the sensors, window length, label lag, feature names, threshold and library versions. model.py reads it all. No scaler is needed: trees are insensitive to feature scale.

Usage

from huggingface_hub import hf_hub_download, snapshot_download
import sys
path = snapshot_download("shalev396/elevator-maintenance")
sys.path.insert(0, path)
import model
predictor = model.load(path, device="cpu")          # CPU only (scikit-learn)
csv = hf_hub_download("shalev396/elevator-maintenance", "examples/degrading.csv", repo_type="space")
p = predictor.predict(csv)                          # {"failure": 0.92, "healthy": 0.08}
print(p, "maintenance" if p["failure"] >= predictor.threshold else "healthy")

Or call the hosted API: see the Space (POST /gradio_api/call/predict with the CSV file).

Inference Endpoint: handler.py makes this repo deployable from its page (Deploy β†’ Inference Endpoints). Send {"inputs": "<CSV text with >= 60 rows>"} (or a list of row dicts, or {column: [values]}); the response is {"failure": p, "healthy": 1 - p}.

Training

  • Data: a seeded synthetic month (training/src/data_setup.py, seed 42): 31 days x 1,440 minutes = 44,640 rows. A daily usage profile (morning, lunch and evening peaks, quiet nights, weekends at 35 %) drives all sensors, plus noise. Five degradation episodes add 6-14 h of linear drift (vibration +1.8, peak vibration +4.5, motor current +5 A, temperature +7 Β°C, noise +9 dB, power +2 kW, rpm -90, faster oil loss), then a 45-120 min failure, then a maintenance reset. Status = 1 during degradation + failure: 8.5 % of minutes. The anchors put three episodes in train and one each in validation and test.
  • Split: by time, 70/15/15 of the rows (train to 22 Jan 16:48, validation to 27 Jan 08:24, test to the end). Windows: 60 min, label = Status 10 min after the window, stride 5 min. A window and its label must lie in the same segment, so nothing crosses a boundary. This gives 6,236 / 1,326 / 1,326 windows with 413 / 178 / 170 failure windows.
  • Experiments: the RandomForest on the 63 features, and two Keras nets on the raw windows (standardised with a scaler fit on train rows): a 1D-CNN (Conv1D 64 β†’ MaxPool β†’ Conv1D 128 β†’ GlobalMaxPool β†’ Dense 64 β†’ Dropout 0.3 β†’ sigmoid) and an LSTM (64 units β†’ Dense 64 β†’ Dropout 0.3 β†’ sigmoid). The nets use Adam (lr 1e-3), batch 128, class weights (neg/pos), up to 8 epochs and early stopping on validation PR-AUC.
  • Selection: each model's threshold is tuned for max F1 on validation (searched in [0.05, 0.95]). The model with the highest validation F1 is deployed. The test segment is scored once, afterwards.
  • Hardware: local desktop CPU; the whole notebook ran in 248 s (forest fit 2.9 s). Code: training/ Β· Colab

Evaluation

Deployed RandomForest on the 1,326 test windows (the last 4.65 days, one unseen episode), threshold 0.377:

metric (test) value
f1 0.9882
precision 0.9882
recall 0.9882
accuracy 0.9970
pr_auc 0.9890
roc_auc 0.9927

Confusion (test): 168 true alarms, 2 missed failure windows, 2 false alarms, 1,154 correct "healthy".

Experiments

Every variant, ranked in training order; bold = deployed. Size is weights for the Keras nets and tree nodes for the forest.

experiment size val F1 threshold test F1 test precision test recall test PR-AUC train time
RandomForest (deployed) 10,408 tree nodes 0.9888 0.377 0.9882 0.9882 0.9882 0.9890 2.9 s
CNN-1D 52,993 weights 0.9117 0.189 0.9581 0.9756 0.9412 0.9380 64.5 s
LSTM 23,681 weights 0.9375 0.166 0.9329 0.9684 0.9000 0.9200 146.1 s
  • The forest wins on validation (F1 0.989 vs 0.938 for the LSTM and 0.912 for the CNN) and on test. Rolling means, slopes and maxima capture a slow drift almost directly, which suits the synthetic generator's linear degradation ramps.
  • Both nets reached their best validation PR-AUC in epoch 1 and then overfit; early stopping restored the epoch-1 weights.
  • The Keras nets are not exported: serving the forest keeps the Space free of TensorFlow.
  • The same metrics came out of the earlier version of this project (F1 0.988 / 0.958 / 0.933), which used the same seed and data.

Test metrics of every experiment Keras training curves Precision-recall curves on the test segment Confusion matrix of the deployed model Predicted failure probability over the whole month RandomForest feature importance

The timeline shows the train episodes at a flat 1.0: those windows were in the training set, so the forest fits them perfectly. Only the orange (validation) and green (test) parts are out of sample.

Limitations

  • Synthetic data. The generator, not a real elevator, defines what "degradation" looks like: smooth linear drifts in several sensors at once. Real failures are noisier, rarer and more varied. Do not use this model to make maintenance decisions.
  • One episode per evaluation split. Validation and test each hold a single degradation episode, so the scores rest on 178 and 170 overlapping failure windows (stride 5 on a 60-min window). One different episode could move them by several points.
  • The label covers the whole 6-14 h drift, so "failure in 10 minutes" in practice means "inside a degradation episode"; the model sees the drift itself, not an early warning hours ahead.
  • Hour and day-of-week features encode the generator's usage schedule. Uploads without a timestamp column are scored as weekday noon.
  • The window must be sampled once per minute, in the same units as the training data.
Downloads last month
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Space using shalev396/elevator-maintenance 1

Evaluation results