Skip to main content

Implementation of Optimal Sparse Survival Trees

Project description

OSST Documentation

Implementation of Optimal Sparse Survival Trees (OSST), an optimal decision tree algorithm for survival analysis. This is implemented based on Generalized Optimal Sparse Decision Tree framework (GOSDT). If you need classification trees, please use GOSDT. If you need regression trees, please use Optimal Sparse Regression Trees (OSRT).


Installation

You may use the following commands to install OSST along with its dependencies on macOS, Ubuntu and Windows.
You need Python 3.9 or later to use the module osst in your project.

pip3 install attrs packaging editables pandas scikit-learn sortedcontainers gmpy2 matplotlib scikit-survival
pip3 install osst

You need to install gmpy2==2.0.a1 if You are using Python 3.12

Configuration

The configuration is a JSON object and has the following structure and default values:

{ 
  "regularization": 0.01,
  "depth_budget": 5,
  "minimum_captured_points": 7,
  "bucketize": false,
  "number_of_buckets": 0,
  "warm_LB": false,
  "path_to_labels": "",
  
  "uncertainty_tolerance": 0.0,
  "upperbound": 0.0,
  "worker_limit": 1,
  "precision_limit": 0,
  "model_limit": 1,
  "time_limit": 0,

  "verbose": false,
  "diagnostics": false,
  "look_ahead": true,

  "model": "",
  "timing": "",
  "trace": "",
  "tree": "",
  "profile": ""
}

Key parameters

regularization

  • Values: Decimal within range [0,1]
  • Description: Used to penalize complexity. A complexity penalty is added to the risk in the following way.
    ComplexityPenalty = # Leaves x regularization
    
  • Default: 0.01
  • Note: We highly recommend setting the regularization to a value larger than 1/num_samples. A small regularization could lead to a longer training time and possible overfitting.

depth_budget

  • Values: Integers >= 1
  • Description: Used to set the maximum tree depth for solutions, counting a tree with just the root node as depth 1. 0 means unlimited.
  • Default: 5

minimum_captured_points

  • Values: Integers >= 1
  • Description: Minimum number of sample points each leaf node must capture
  • Default: 7

bucketize

  • Values: true or false
  • Description: Enables bucketization of time threshold for training
  • Default: false

number_of_buckets

  • Values: Integers
  • Description: The number of time thresholds to which origin data mapping to if bucktize flag is set to True
  • Default: 0

warm_LB

  • Values: true or false
  • Description: Enables the reference lower bound
  • Default: false

path_to_labels

  • Values: string representing a path to a directory.
  • Description: IBS loss of reference model
  • Special Case: When set to empty string, no reference IBS loss are stored.
  • Default: Empty string

time_limit

  • Values: Decimal greater than or equal to 0
  • Description: A time limit upon which the algorithm will terminate. If the time limit is reached, the algorithm will terminate with an error.
  • Special Cases: When set to 0, no time limit is imposed.
  • Default: 0

More parameters

Flag

look_ahead

  • Values: true or false
  • Description: Enables the one-step look-ahead bound implemented via scopes
  • Default: true

diagnostics

  • Values: true or false
  • Description: Enables printing of diagnostic trace when an error is encountered to standard output
  • Default: false

verbose

  • Values: true or false
  • Description: Enables printing of configuration, progress, and results to standard output
  • Default: false

Tuners

uncertainty_tolerance

  • Values: Decimal within range [0,1]
  • Description: Used to allow early termination of the algorithm. Any models produced as a result are guaranteed to score within the lowerbound and upperbound at the time of termination. However, the algorithm does not guarantee that the optimal model is within the produced model unless the uncertainty value has reached 0.
  • Default: 0.0

upperbound

  • Values: Decimal within range [0,1]
  • Description: Used to limit the risk of model search space. This can be used to ensure that no models are produced if even the optimal model exceeds a desired maximum risk. This also accelerates learning if the upperbound is taken from the risk of a nearly optimal model.
  • Special Cases: When set to 0, the bound is not activated.
  • Default: 0.0

Limits

model_limit

  • Values: Decimal greater than or equal to 0
  • Description: The maximum number of models that will be extracted into the output.
  • Special Cases: When set to 0, no output is produced.
  • Default: 1

precision_limit

  • Values: Decimal greater than or equal to 0
  • Description: The maximum number of significant figures considered when converting ordinal features into binary features.
  • Special Cases: When set to 0, no limit is imposed.
  • Default: 0

worker_limit

  • Values: Decimal greater than or equal to 1
  • Description: The maximum number of threads allocated to executing th algorithm.
  • Special Cases: When set to 0, a single thread is created for each core detected on the machine.
  • Default: 1

Files

model

  • Values: string representing a path to a file.
  • Description: The output models will be written to this file.
  • Special Case: When set to empty string, no model will be stored.
  • Default: Empty string

profile

  • Values: string representing a path to a file.
  • Description: Various analytics will be logged to this file.
  • Special Case: When set to empty string, no analytics will be stored.
  • Default: Empty string

timing

  • Values: string representing a path to a file.
  • Description: The training time will be appended to this file.
  • Special Case: When set to empty string, no training time will be stored.
  • Default: Empty string

trace

  • Values: string representing a path to a directory.
  • Description: snapshots used for trace visualization will be stored in this directory
  • Special Case: When set to empty string, no snapshots are stored.
  • Default: Empty string

tree

  • Values: string representing a path to a directory.
  • Description: snapshots used for trace-tree visualization will be stored in this directory
  • Special Case: When set to empty string, no snapshots are stored.
  • Default: Empty string

Example

Example code to run OSST with lower bound guessing, and depth limit. The example python file is available in osst/example.py.

import pandas as pd
import numpy as np
from osst.model.osst import OSST
from osst.model.metrics import harrell_c_index, uno_c_index, integrated_brier_score, cumulative_dynamic_auc, compute_ibs_per_sample
from sklearn.model_selection import train_test_split
from sksurv.ensemble import RandomSurvivalForest
from sksurv.datasets import get_x_y
import pathlib


dataset_path = "experiments/datasets/churn/churn.csv"

# read the dataset
# preprocess your data otherwise OSST will binarize continuous feature using all threshold values.
df = pd.read_csv(dataset_path)
X, event, y = df.iloc[:,:-2].values, df.iloc[:,-2].values.astype(int), df.iloc[:,-1].values
h = df.columns[:-2]
X = pd.DataFrame(X, columns=h)
event = pd.DataFrame(event)
y = pd.DataFrame(y)
_, y_sksurv = get_x_y(df, df.columns[-2:], 1)
print("X shape: ", X.shape)
# split train and test set
X_train, X_test, event_train, event_test, y_train, y_test, y_sksurv_train, y_sksurv_test \
      = train_test_split(X, event, y, y_sksurv, test_size=0.2, random_state=2024)

times_train = np.unique(y_train.values.reshape(-1))
times_test = np.unique(y_test.values.reshape(-1))
print("Train time thresholds range: ({:.1f}, {:.1f}),  Test time thresholds range: ({:.1f}, {:.1f})".format(\
    times_train[0], times_train[-1], times_test[0], times_test[-1]))

# compute reference lower bounds
ref_model = RandomSurvivalForest(n_estimators=100, max_depth=3, random_state=2024)
ref_model.fit(X_train, y_sksurv_train)
ref_S_hat = ref_model.predict_survival_function(X_train)
ref_estimates = np.array([f(times_train) for f in ref_S_hat])
ibs_loss_per_sample = compute_ibs_per_sample(event_train, y_train, event_train, y_train, ref_estimates, times_train)

labelsdir = pathlib.Path('/tmp/warm_lb_labels')
labelsdir.mkdir(exist_ok=True, parents=True)

labelpath = labelsdir / 'warm_label.tmp'
labelpath = str(labelpath)

pd.DataFrame(ibs_loss_per_sample, columns=['class_labels']).to_csv(labelpath, header='class_labels', index=None)

# fit model

config = {
    "look_ahead": True,
    "diagnostics": True,
    "verbose": False,

    "regularization": 0.01,
    "uncertainty_tolerance": 0.0,
    "upperbound": 0.0,
    "depth_budget": 5,
    "minimum_captured_points": 7,

    "model_limit": 100,
    
    "warm_LB": True,
    "path_to_labels": labelpath,
  }


model = OSST(config)
model.fit(X_train, event_train, y_train)
print("evaluate the model, extracting tree and scores", flush=True)

# evaluation
n_leaves = model.leaves()
n_nodes = model.nodes()
time = model.time
print("Model training time: {}".format(time))
print("# of leaves: {}".format(n_leaves))

print("Train IBS score: {:.6f} , Test IBS score: {:.6f}".format(\
    model.score(X_train, event_train, y_train), model.score(X_test, event_test, y_test)))

S_hat_train = model.predict_survival_function(X_train)
estimates_train = np.array([f(times_train) for f in S_hat_train])

S_hat_test = model.predict_survival_function(X_test)
estimates_test = np.array([f(times_test) for f in S_hat_test])

print("Train Harrell's c-index: {:.6f}, Test Harrell's c-index: {:.6f}".format(\
    harrell_c_index(event_train, y_train, estimates_train, times_train)[0], \
    harrell_c_index(event_test, y_test, estimates_test, times_test)[0]))

print("Train Uno's c-index: {:.6f}, Test Uno's c-index: {:.6f}".format(\
    uno_c_index(event_train, y_train, event_train, y_train, estimates_train, times_train)[0],\
    uno_c_index(event_train, y_train, event_test, y_test, estimates_test, times_test)[0]))

print("Train AUC: {:.6f}, Test AUC: {:.6f}".format(\
    cumulative_dynamic_auc(event_train, y_train, event_train, y_train, estimates_train, times_train)[0],\
    cumulative_dynamic_auc(event_train, y_train, event_test, y_test, estimates_test, times_test)[0]))

print(model.tree)

Output

X shape:  (2000, 42)
Train time thresholds range: (0.0, 12.0),  Test time thresholds range: (0.0, 12.0)
osst reported successful execution
training completed. 4.968 seconds.
bounds: [0.168379..0.168379] (0.000000) IBS loss = 0.118379, iterations=16920
evaluate the model, extracting tree and scores
Model training time: 4.9679999351501465
# of leaves: 5
Train IBS score: 0.118379 , Test IBS score: 0.124289
Train Harrell's c-index: 0.737871, Test Harrell's c-index: 0.734727
Train Uno's c-index: 0.689405, Test Uno's c-index: 0.706680
Train AUC: 0.800940, Test AUC: 0.806016
if product_accounting_No = 1 then:
    predicted time: 4
    normalized loss penalty: 0.0
    complexity penalty: 0.01

else if csat_score_7 = 1 and product_accounting_No != 1 then:
    predicted time: 3
    normalized loss penalty: 0.0
    complexity penalty: 0.01

else if csat_score_7 != 1 and product_accounting_No != 1 and product_payroll_No = 1 then:
    predicted time: 2
    normalized loss penalty: 0.0
    complexity penalty: 0.01

else if csat_score_7 != 1 and csat_score_8 = 1 and product_accounting_No != 1 and product_payroll_No != 1 then:
    predicted time: 1
    normalized loss penalty: 0.0
    complexity penalty: 0.01

else if csat_score_7 != 1 and csat_score_8 != 1 and product_accounting_No != 1 and product_payroll_No != 1 then:
    predicted time: 0
    normalized loss penalty: 0.0
    complexity penalty: 0.01

License

This software is licensed under a 3-clause BSD license (see the LICENSE file for details).


Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

osst-0.1.5.tar.gz (6.0 MB view details)

Uploaded Source

Built Distributions

osst-0.1.5-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (536.2 kB view details)

Uploaded CPython 3.12+ manylinux: glibc 2.17+ x86-64

osst-0.1.5-cp312-abi3-macosx_14_0_arm64.whl (577.2 kB view details)

Uploaded CPython 3.12+ macOS 14.0+ ARM64

osst-0.1.5-cp312-abi3-macosx_13_0_x86_64.whl (672.3 kB view details)

Uploaded CPython 3.12+ macOS 13.0+ x86-64

osst-0.1.5-cp312-abi3-macosx_12_0_x86_64.whl (660.7 kB view details)

Uploaded CPython 3.12+ macOS 12.0+ x86-64

osst-0.1.5-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (536.2 kB view details)

Uploaded CPython 3.11+ manylinux: glibc 2.17+ x86-64

osst-0.1.5-cp311-abi3-macosx_14_0_arm64.whl (577.2 kB view details)

Uploaded CPython 3.11+ macOS 14.0+ ARM64

osst-0.1.5-cp311-abi3-macosx_13_0_x86_64.whl (672.3 kB view details)

Uploaded CPython 3.11+ macOS 13.0+ x86-64

osst-0.1.5-cp311-abi3-macosx_12_0_x86_64.whl (660.7 kB view details)

Uploaded CPython 3.11+ macOS 12.0+ x86-64

osst-0.1.5-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (536.2 kB view details)

Uploaded CPython 3.10+ manylinux: glibc 2.17+ x86-64

osst-0.1.5-cp310-abi3-macosx_14_0_arm64.whl (577.2 kB view details)

Uploaded CPython 3.10+ macOS 14.0+ ARM64

osst-0.1.5-cp310-abi3-macosx_13_0_x86_64.whl (672.3 kB view details)

Uploaded CPython 3.10+ macOS 13.0+ x86-64

osst-0.1.5-cp310-abi3-macosx_12_0_x86_64.whl (660.7 kB view details)

Uploaded CPython 3.10+ macOS 12.0+ x86-64

osst-0.1.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (536.2 kB view details)

Uploaded CPython 3.9+ manylinux: glibc 2.17+ x86-64

osst-0.1.5-cp39-abi3-macosx_14_0_arm64.whl (577.2 kB view details)

Uploaded CPython 3.9+ macOS 14.0+ ARM64

osst-0.1.5-cp39-abi3-macosx_13_0_x86_64.whl (672.3 kB view details)

Uploaded CPython 3.9+ macOS 13.0+ x86-64

osst-0.1.5-cp39-abi3-macosx_12_0_x86_64.whl (660.8 kB view details)

Uploaded CPython 3.9+ macOS 12.0+ x86-64

File details

Details for the file osst-0.1.5.tar.gz.

File metadata

  • Download URL: osst-0.1.5.tar.gz
  • Upload date:
  • Size: 6.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.9.19

File hashes

Hashes for osst-0.1.5.tar.gz
Algorithm Hash digest
SHA256 b4af2f1e3a57d4a7e91df9cc61ef330e8cd472795fe3192c381309f8553eedb4
MD5 e0f3875125662b969bad72c78b4c9943
BLAKE2b-256 6d1630c4cf51d8537efb8297c78d067275f0bfb38da4e7e21a8cc08e329d8c0c

See more details on using hashes here.

File details

Details for the file osst-0.1.5-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.5-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9c79f5de2405afbca44c3f5c05f6ffcdc2e0a8ce3de516f4d0dba9d9cec6cc3e
MD5 f51979f2af7193bfb1c926ca8026af1f
BLAKE2b-256 239674679153f1bd91c97b350aa389d7bd1087b26cfea625cd07c95ac24e6331

See more details on using hashes here.

File details

Details for the file osst-0.1.5-cp312-abi3-macosx_14_0_arm64.whl.

File metadata

File hashes

Hashes for osst-0.1.5-cp312-abi3-macosx_14_0_arm64.whl
Algorithm Hash digest
SHA256 dc4931df454fcb42c8ec7e7f526136e095c3c87b953beb4e3fa4bf1b98ad2c93
MD5 85f7fb9ea6deb8fff4c3a8e01e341a32
BLAKE2b-256 4a003a2d08e869233345be72596e18f7bc2d2a6a50da2f8f41238d49d3663f52

See more details on using hashes here.

File details

Details for the file osst-0.1.5-cp312-abi3-macosx_13_0_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.5-cp312-abi3-macosx_13_0_x86_64.whl
Algorithm Hash digest
SHA256 6706b9267e67a0c4cb4d4ab08ca6ac21029f080372cc6752a7892070f468f48d
MD5 e8f7adca8b62b46e9f9efeaaeaf5b154
BLAKE2b-256 1a825845f2bff1a148c79e822698226adb767afef73417da1c6665e431d1413a

See more details on using hashes here.

File details

Details for the file osst-0.1.5-cp312-abi3-macosx_12_0_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.5-cp312-abi3-macosx_12_0_x86_64.whl
Algorithm Hash digest
SHA256 d79568ae3cc466398f22ec3d7e25d9669f8bdee1ad9510a3c5149262d6898929
MD5 9bb2ac1a14dd7faf017b46fa185d200a
BLAKE2b-256 1c4b36757234abfc93044a01bc447865d4298fbef42be57ba06c3c4a8beefb20

See more details on using hashes here.

File details

Details for the file osst-0.1.5-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.5-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 4a832c5ca73156cf84762185cc3804ca1269c4eb8e0b237a4d6222d63090fb4a
MD5 bd29863132880a511a4f8ee216f25470
BLAKE2b-256 9e95504bd093a8ca93f5d3c1bad900134f625866751c8a75474ea5cb403031e4

See more details on using hashes here.

File details

Details for the file osst-0.1.5-cp311-abi3-macosx_14_0_arm64.whl.

File metadata

File hashes

Hashes for osst-0.1.5-cp311-abi3-macosx_14_0_arm64.whl
Algorithm Hash digest
SHA256 4aacb6f02a292f3ca334c34bb2b71c48ad9e9f4eeeeeae90a46645ca6c0d4c61
MD5 4fc8611f9edd5315221ea5f598fd60e6
BLAKE2b-256 71659f5e7203cfc1411f3abda75229ff41058444519b0e2487a3c5dc66a11acf

See more details on using hashes here.

File details

Details for the file osst-0.1.5-cp311-abi3-macosx_13_0_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.5-cp311-abi3-macosx_13_0_x86_64.whl
Algorithm Hash digest
SHA256 a9c609428c39ce766311d27363fc04e3a10e947631f442cce84f2bd157a76084
MD5 f8ff941122d500eccfd00a4d9e598aa2
BLAKE2b-256 fed98c755a57b17a61e845f70f8bfa168dedfb3ee754e2118e136896b99877a6

See more details on using hashes here.

File details

Details for the file osst-0.1.5-cp311-abi3-macosx_12_0_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.5-cp311-abi3-macosx_12_0_x86_64.whl
Algorithm Hash digest
SHA256 3e9c35e4fea7c382327a2222b60f2d091b4d636b3a859b3ed113d88c6391bee8
MD5 f0fbd1cb02fcdff08cb71d2425851e7f
BLAKE2b-256 9900b4c2fa31e2ad3d7c107a1af35aef02f08111a53eb9e58e03305a31793821

See more details on using hashes here.

File details

Details for the file osst-0.1.5-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.5-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 cdc5f7bb45183530142f8da8d7d908aaa72fdc732a2ae24d2dccf9f8f7529c6a
MD5 ce3fdd864bc293c79dc88e5f40f34a0e
BLAKE2b-256 3e91a6cad37c488604c4c1b5c9d317ab779cc4bafbc4a46d871fc614131b87f4

See more details on using hashes here.

File details

Details for the file osst-0.1.5-cp310-abi3-macosx_14_0_arm64.whl.

File metadata

File hashes

Hashes for osst-0.1.5-cp310-abi3-macosx_14_0_arm64.whl
Algorithm Hash digest
SHA256 9f8352d2b570a9fbbed057bd60a240291b03803a0b4e4c3dcd7e03dea7d291d4
MD5 199374361057d5d859a3591b27ed807c
BLAKE2b-256 0da12279cf17e23f78b7f2fe08eebf9f4add751ceef792241ba11f5d752f4f33

See more details on using hashes here.

File details

Details for the file osst-0.1.5-cp310-abi3-macosx_13_0_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.5-cp310-abi3-macosx_13_0_x86_64.whl
Algorithm Hash digest
SHA256 c3b54b4e6e606e624e97b6ce14ddcf9dc7981fe5ac4667f895a2562866e37a67
MD5 4915edb2a7aca8ef7f05beb4b6b296d9
BLAKE2b-256 c3042336a90795b0a2c2c12a3b48c6adc313bd879fad62379e4d45c53792ca01

See more details on using hashes here.

File details

Details for the file osst-0.1.5-cp310-abi3-macosx_12_0_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.5-cp310-abi3-macosx_12_0_x86_64.whl
Algorithm Hash digest
SHA256 f9d18f77b7a1d3dcefc33df5ec21a213173e77cc97b8c4f378dbc7e30ea40f37
MD5 1709b79724d0c6f3a688d82f5f7a580f
BLAKE2b-256 61964a738a4321ed96a15a965990d1308be1cc98987bbd3d844594b478e37a94

See more details on using hashes here.

File details

Details for the file osst-0.1.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 080104a959071f0eb0eaab01446381407006353d9e21732c4adeba7bcd614c98
MD5 cb6040da61b8491c29d1a7c9537dd066
BLAKE2b-256 8be33b1e6af8ab2deb2c2d6d1f0dd3e5fa9a4b257cc432e7e963bbf72b30d98e

See more details on using hashes here.

File details

Details for the file osst-0.1.5-cp39-abi3-macosx_14_0_arm64.whl.

File metadata

File hashes

Hashes for osst-0.1.5-cp39-abi3-macosx_14_0_arm64.whl
Algorithm Hash digest
SHA256 cbe4a9abfe6a625611dd929f8c02d61f0aeb38501984e4d2e453c1fe557ca8d7
MD5 175b993a2141bc3fa01b003a89e24ad0
BLAKE2b-256 b728d717bec08686e5b28b053a146e62cbfcac7d4ff3552bbff36d969c9c2957

See more details on using hashes here.

File details

Details for the file osst-0.1.5-cp39-abi3-macosx_13_0_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.5-cp39-abi3-macosx_13_0_x86_64.whl
Algorithm Hash digest
SHA256 7fd16e9804fd2f63c1f0ed46ddcc308a24c18da6cb81fd3fbc689ebe39146204
MD5 72923767acd61f8eb9786a772ef49aaf
BLAKE2b-256 d559120e07efea884637d5cbd6915c11e8de315aa4f21f313db7adae0cc6ac27

See more details on using hashes here.

File details

Details for the file osst-0.1.5-cp39-abi3-macosx_12_0_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.5-cp39-abi3-macosx_12_0_x86_64.whl
Algorithm Hash digest
SHA256 c417d358698d3a75fb0379e4f8ac87ebf6aa8638a19429c06c0a35347753a381
MD5 e1f1e848b75566eb02351f2e0df22441
BLAKE2b-256 2808145a1abf5901eaa036a5a969b52b68646f0fa4470ab9780edd52281dfa4f

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page