{"id":13665716,"url":"https://github.com/loft-br/xgboost-survival-embeddings","last_synced_at":"2025-04-26T08:33:06.505Z","repository":{"id":42431232,"uuid":"329317418","full_name":"loft-br/xgboost-survival-embeddings","owner":"loft-br","description":"Improving XGBoost survival analysis with embeddings and debiased estimators","archived":false,"fork":false,"pushed_at":"2024-10-03T17:02:12.000Z","size":13067,"stargazers_count":326,"open_issues_count":24,"forks_count":51,"subscribers_count":83,"default_branch":"main","last_synced_at":"2025-01-12T09:19:46.793Z","etag":null,"topics":["machine-learning","survival-analysis"],"latest_commit_sha":null,"homepage":"https://loft-br.github.io/xgboost-survival-embeddings/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/loft-br.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE-OF-CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-13T13:30:40.000Z","updated_at":"2025-01-11T20:44:13.000Z","dependencies_parsed_at":"2024-01-19T14:19:33.614Z","dependency_job_id":"b8a8c7ec-7fe9-4562-a781-3d989e779cea","html_url":"https://github.com/loft-br/xgboost-survival-embeddings","commit_stats":{"total_commits":46,"total_committers":6,"mean_commits":7.666666666666667,"dds":0.4347826086956522,"last_synced_commit":"6247a15dae2d75babd8cbe55d281ab117c92e3f5"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loft-br%2Fxgboost-survival-embeddings","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loft-br%2Fxgboost-survival-embeddings/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loft-br%2Fxgboost-survival-embeddings/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loft-br%2Fxgboost-survival-embeddings/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/loft-br","download_url":"https://codeload.github.com/loft-br/xgboost-survival-embeddings/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250960772,"owners_count":21514518,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["machine-learning","survival-analysis"],"created_at":"2024-08-02T06:00:48.334Z","updated_at":"2025-04-26T08:33:01.478Z","avatar_url":"https://github.com/loft-br.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.6326018.svg)](https://doi.org/10.5281/zenodo.6326018)\n\n## `xgbse`: XGBoost Survival Embeddings\n\n\u003e *\"There are two cultures in the use of statistical modeling to reach conclusions from data. One assumes that the data are generated by a given stochastic data model. The other uses algorithmic models and treats the data mechanism as unknown.\"* - Leo Breiman, [Statistical Modeling: The Two Cultures](https://projecteuclid.org/euclid.ss/1009213726)\n\nSurvival Analysis is a powerful statistical technique with a wide range of applications such as predictive maintenance, customer churn, credit risk, asset liquidity risk, and others.\n\nHowever, it has not yet seen widespread adoption in industry, with most implementations embracing one of two cultures:\n\n1. models with sound statistical properties, but lacking in expressivess and computational efficiency\n2. highly efficient and expressive models, but lacking in statistical rigor\n\n`xgbse` aims to unite the two cultures in a single package, adding a layer of statistical rigor to the highly expressive and computationally effcient `xgboost` survival analysis implementation.\n\nThe package offers:\n\n* calibrated and unbiased survival curves with confidence intervals (instead of point predictions)\n* great predictive power, competitive to vanilla `xgboost`\n* efficient, easy to use implementation\n* explainability through prototypes\n\nThis is a research project by [Loft Data Science Team](https://medium.com/loftbr/datascience/home), however we invite the community to contribute. Please help by trying it out, reporting bugs, and letting us know what you think!\n\n## Installation\n\n```\npip install xgbse\n```\n\n## Usage\n\n### *Basic usage*\n\nThe package follows `scikit-learn` API, with a minor adaptation to work with time and event data (`y` as a `numpy` structured array of times and events). `.predict()` returns a dataframe where each column is a time window and values represent the probability of survival before or exactly at the time window.\n\n```python\n# importing dataset from pycox package\nfrom pycox.datasets import metabric\n\n# importing model and utils from xgbse\nfrom xgbse import XGBSEKaplanNeighbors\nfrom xgbse.converters import convert_to_structured\n\n# getting data\ndf = metabric.read_df()\n\n# splitting to X, y format\nX = df.drop(['duration', 'event'], axis=1)\ny = convert_to_structured(df['duration'], df['event'])\n\n# fitting xgbse model\nxgbse_model = XGBSEKaplanNeighbors(n_neighbors=50)\nxgbse_model.fit(X, y)\n\n# predicting\nevent_probs = xgbse_model.predict(X)\nevent_probs.head()\n```\n\nindex | 15 | 30 | 45 | 60 | 75 | 90 | 105 | 120 | 135 | 150 | 165 | 180 | 195 | 210 | 225 | 240 | 255 | 270 | 285\n---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ----\n0 | 0.98 | 0.87 | 0.81 | 0.74 | 0.71 | 0.66 | 0.53 | 0.47 | 0.42 | 0.4 | 0.3 | 0.25 | 0.21 | 0.16 | 0.12 | 0.098 | 0.085 | 0.062 | 0.054\n1 | 0.99 | 0.89 | 0.79 | 0.7 | 0.64 | 0.58 | 0.53 | 0.46 | 0.42 | 0.39 | 0.33 | 0.31 | 0.3 | 0.24 | 0.21 | 0.18 | 0.16 | 0.11 | 0.095\n2 | 0.94 | 0.78 | 0.63 | 0.57 | 0.54 | 0.49 | 0.44 | 0.37 | 0.34 | 0.32 | 0.26 | 0.23 | 0.21 | 0.16 | 0.13 | 0.11 | 0.098 | 0.072 | 0.062\n3 | 0.99 | 0.95 | 0.93 | 0.88 | 0.84 | 0.81 | 0.73 | 0.67 | 0.57 | 0.52 | 0.45 | 0.37 | 0.33 | 0.28 | 0.23 | 0.19 | 0.16 | 0.12 | 0.1\n4 | 0.98 | 0.92 | 0.82 | 0.77 | 0.72 | 0.68 | 0.63 | 0.6 | 0.57 | 0.55 | 0.51 | 0.48 | 0.45 | 0.42 | 0.38 | 0.33 | 0.3 | 0.22 | 0.2\n\nYou can also get interval predictions (probability of failing exactly at each time window) using `return_interval_probs`:\n\n```python\n# point predictions\ninterval_probs = xgbse_model.predict(X_valid, return_interval_probs=True)\ninterval_probs.head()\n```\n\nindex | 15 | 30 | 45 | 60 | 75 | 90 | 105 | 120 | 135 | 150 | 165 | 180 | 195 | 210 | 225 | 240 | 255 | 270 | 285\n---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ----\n0 | 0.024 | 0.1 | 0.058 | 0.07 | 0.034 | 0.05 | 0.12 | 0.061 | 0.049 | 0.026 | 0.096 | 0.049 | 0.039 | 0.056 | 0.04 | 0.02 | 0.013 | 0.023 | 0.0078\n1 | 0.014 | 0.097 | 0.098 | 0.093 | 0.052 | 0.065 | 0.054 | 0.068 | 0.034 | 0.038 | 0.053 | 0.019 | 0.018 | 0.052 | 0.038 | 0.027 | 0.018 | 0.05 | 0.015\n2 | 0.06 | 0.16 | 0.15 | 0.054 | 0.033 | 0.053 | 0.046 | 0.073 | 0.032 | 0.014 | 0.06 | 0.03 | 0.017 | 0.055 | 0.031 | 0.016 | 0.014 | 0.027 | 0.0097\n3 | 0.011 | 0.034 | 0.021 | 0.053 | 0.038 | 0.038 | 0.08 | 0.052 | 0.1 | 0.049 | 0.075 | 0.079 | 0.037 | 0.052 | 0.053 | 0.041 | 0.026 | 0.04 | 0.017\n4 | 0.016 | 0.067 | 0.099 | 0.046 | 0.05 | 0.042 | 0.051 | 0.028 | 0.03 | 0.018 | 0.048 | 0.022 | 0.029 | 0.038 | 0.035 | 0.047 | 0.031 | 0.08 | 0.027\n\n\n### *Survival curves and confidence intervals*\n\n`XBGSEKaplanTree` and `XBGSEKaplanNeighbors` support estimation of survival curves and confidence intervals via the Exponential Greenwood formula out-of-the-box via the `return_ci` argument:\n\n```python\n# fitting xgbse model\nxgbse_model = XGBSEKaplanNeighbors(n_neighbors=50)\nxgbse_model.fit(X_train, y_train, time_bins=TIME_BINS)\n\n# predicting\nmean, upper_ci, lower_ci = xgbse_model.predict(X_valid, return_ci=True)\n\n# plotting CIs\nplot_ci(mean, upper_ci, lower_ci)\n```\n\n\u003cimg src=\"img/usage_ci_1.png\"\u003e\n\n`XGBSEDebiasedBCE` does not support estimation of confidence intervals out-of-the-box, but we provide the `XGBSEBootstrapEstimator` to get non-parametric confidence intervals. As the stacked logistic regressions are trained with more samples (in comparison to neighbor-sets in `XGBSEKaplanNeighbors`), confidence intervals are more concentrated:\n\n```python\n# base model as BCE\nbase_model = XGBSEDebiasedBCE(PARAMS_XGB_AFT, PARAMS_LR)\n\n# bootstrap meta estimator\nbootstrap_estimator = XGBSEBootstrapEstimator(base_model, n_estimators=20)\n\n# fitting the meta estimator\nbootstrap_estimator.fit(\n    X_train,\n    y_train,\n    validation_data=(X_valid, y_valid),\n    early_stopping_rounds=10,\n    time_bins=TIME_BINS,\n)\n\n# predicting\nmean, upper_ci, lower_ci = bootstrap_estimator.predict(X_valid, return_ci=True)\n\n# plotting CIs\nplot_ci(mean, upper_ci, lower_ci)\n```\n\n\u003cimg src=\"img/usage_ci_2.png\"\u003e\n\nThe bootstrap abstraction can be used for `XBGSEKaplanTree` and `XBGSEKaplanNeighbors` as well, however, the confidence interval will be estimated via bootstrap only (not Exponential Greenwood formula):\n\n```python\n# base model\nbase_model = XGBSEKaplanTree(PARAMS_TREE)\n\n# bootstrap meta estimator\nbootstrap_estimator = XGBSEBootstrapEstimator(base_model, n_estimators=100)\n\n# fitting the meta estimator\nbootstrap_estimator.fit(\n    X_train,\n    y_train,\n    time_bins=TIME_BINS,\n)\n\n# predicting\nmean, upper_ci, lower_ci = bootstrap_estimator.predict(X_valid, return_ci=True)\n\n# plotting CIs\nplot_ci(mean, upper_ci, lower_ci)\n```\n\n\u003cimg src=\"img/usage_ci_3.png\"\u003e\n\nWith a sufficiently large `n_estimators`, interval width shouldn't be much different, with the added benefit of model stability and improved accuracy. Addittionaly, `XGBSEBootstrapEstimator` allows building confidence intervals for interval probabilities (which is not supported for Exponential Greenwood):\n\n```python\n# predicting\nmean, upper_ci, lower_ci = bootstrap_estimator.predict(\n    X_valid,\n    return_ci=True,\n    return_interval_probs=True\n)\n\n# plotting CIs\nplot_ci(mean, upper_ci, lower_ci)\n```\n\n\u003cimg src=\"img/usage_ci_6.png\"\u003e\n\nThe parameter `ci_width` controls the width of the confidence interval. For `XGBSEKaplanTree` it should be passed at `.fit()`, as KM curves are pre-calculated for each leaf at fit time to avoid storing training data.\n\n```python\n# fitting xgbse model\nxgbse_model = XGBSEKaplanTree(PARAMS_TREE)\nxgbse_model.fit(X_train, y_train, time_bins=TIME_BINS, ci_width=0.99)\n\n# predicting\nmean, upper_ci, lower_ci = xgbse_model.predict(X_valid, return_ci=True)\n\n# plotting CIs\nplot_ci(mean, upper_ci, lower_ci)\n```\n\n\u003cimg src=\"img/usage_ci_4.png\"\u003e\n\nFor other models (`XGBSEKaplanNeighbors` and `XGBSEBootstrapEstimator`) it should be passed at `.predict()`.\n\n```python\n# base model\nmodel = XGBSEKaplanNeighbors(PARAMS_XGB_AFT, N_NEIGHBORS)\n\n# fitting the meta estimator\nmodel.fit(\n    X_train, y_train,\n    validation_data = (X_valid, y_valid),\n    early_stopping_rounds=10,\n    time_bins=TIME_BINS\n)\n\n# predicting\nmean, upper_ci, lower_ci = model.predict(X_valid, return_ci=True, ci_width=0.99)\n\n# plotting CIs\nplot_ci(mean, upper_ci, lower_ci)\n```\n\n\u003cimg src=\"img/usage_ci_5.png\"\u003e\n\n### *Extrapolation*\n\nWe provide an extrapolation interface, to deal with cases where the survival curve does not end at 0 due to censoring. Currently the implementation only supports extrapolation assuming constant risk.\n\n```python\nfrom xgbse.extrapolation import extrapolate_constant_risk\n\n# predicting\nsurvival = bootstrap_estimator.predict(X_valid)\n\n# extrapolating\nsurvival_ext = extrapolate_constant_risk(survival, 450, 15)\n```\n\n\u003cimg src=\"img/extrapolation.png\"\u003e\n\n\n### *Early stopping*\n\nA simple interface to `xgboost` early stopping is provided.\n\n```python\n# splitting between train, and validation\n(X_train, X_valid,\n y_train, y_valid) = \\\ntrain_test_split(X, y, test_size=0.2, random_state=42)\n\n# fitting with early stopping\nxgb_model = XGBSEDebiasedBCE()\nxgb_model.fit(\n    X_train,\n    y_train,\n    validation_data=(X_valid, y_valid),\n    early_stopping_rounds=10,\n    verbose_eval=50\n)\n```\n\n```\n[0]\tvalidation-aft-nloglik:16.86713\nWill train until validation-aft-nloglik hasn't improved in 10 rounds.\n[50]\tvalidation-aft-nloglik:3.64540\n[100]\tvalidation-aft-nloglik:3.53679\n[150]\tvalidation-aft-nloglik:3.53207\nStopping. Best iteration:\n[174]\tvalidation-aft-nloglik:3.53004\n```\n\n### *Explainability through prototypes*\n\n`xgbse` also provides explainability through prototypes, searching the embedding for neighbors. The idea is to explain model predictions with real samples, providing solid ground to justify them (see [8]). The method `.get_neighbors()` searches for the `n_neighbors` nearest neighbors in `index_data` for each sample in `query_data`:\n\n```python\nneighbors = xgb_model.get_neighbors(\n    query_data=X_valid,\n    index_data=X_train,\n    n_neighbors=10\n)\nneighbors.head(5)\n```\n\nindex | neighbor_1 | neighbor_2 | neighbor_3 | neighbor_4 | neighbor_5 | neighbor_6 | neighbor_7 | neighbor_8 | neighbor_9 | neighbor_10\n---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ----\n1225 | 1151 | 1513 | 1200 | 146 | 215 | 452 | 1284 | 1127 | 1895 | 257\n111 | 1897 | 1090 | 1743 | 1224 | 892 | 1695 | 1624 | 1546 | 1418 | 4\n554 | 9 | 627 | 1257 | 1460 | 1031 | 1575 | 1557 | 440 | 1236 | 858\n526 | 726 | 1042 | 177 | 1640 | 242 | 1529 | 234 | 1800 | 399 | 1431\n1313 | 205 | 1738 | 599 | 954 | 1694 | 1715 | 1651 | 828 | 541 | 992\n\nThis way, we can inspect neighbors of a given sample to try to explain predictions. For instance, we can choose a `reference` and check that its neighbors actually are very similar as a sanity check:\n\n```python\ni = 0\n\nreference = X_valid.iloc[i]\nreference.name = 'reference'\ntrain_neighs = X_train.loc[neighbors.iloc[i]]\n\npd.concat([reference.to_frame().T, train_neighs])\n```\n\nindex | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8\n---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ----\nreference | 5.7 | 5.7 | 11 | 5.6 | 1 | 1 | 0 | 1 | 86\n1151 | 5.8 | 5.9 | 11 | 5.5 | 1 | 1 | 0 | 1 | 82\n1513 | 5.5 | 5.5 | 11 | 5.6 | 1 | 1 | 0 | 1 | 79\n1200 | 5.7 | 6 | 11 | 5.6 | 1 | 1 | 0 | 1 | 76\n146 | 5.9 | 5.9 | 11 | 5.5 | 0 | 1 | 0 | 1 | 75\n215 | 5.8 | 5.5 | 11 | 5.4 | 1 | 1 | 0 | 1 | 78\n452 | 5.7 | 5.7 | 12 | 5.5 | 0 | 0 | 0 | 1 | 76\n1284 | 5.6 | 6.2 | 11 | 5.6 | 1 | 0 | 0 | 1 | 79\n1127 | 5.5 | 5.1 | 11 | 5.5 | 1 | 1 | 0 | 1 | 86\n1895 | 5.5 | 5.4 | 10 | 5.5 | 1 | 1 | 0 | 1 | 85\n257 | 5.7 | 6 | 9.6 | 5.6 | 1 | 1 | 0 | 1 | 76\n\nWe also can compare the Kaplan-Meier curve estimated from the neighbors to the actual model prediction, checking that it is inside the confidence interval:\n\n```python\nfrom xgbse.non_parametric import calculate_kaplan_vectorized\n\nmean, high, low = calculate_kaplan_vectorized(\n    np.array([y['c2'][neighbors.iloc[i]]]),\n    np.array([y['c1'][neighbors.iloc[i]]]),\n    TIME_BINS\n)\n\nmodel_surv = xgb_model.predict(X_valid)\n\nplt.figure(figsize=(12,4), dpi=120)\nplt.plot(model_surv.columns, model_surv.iloc[i])\nplt.plot(mean.columns, mean.iloc[0])\nplt.fill_between(mean.columns, low.iloc[0], high.iloc[0], alpha=0.1, color='red')\n```\n\n\u003cimg src=\"img/usage_prototype_kaplan.png\"\u003e\n\nSpecifically, for `XBGSEKaplanNeighbors` prototype predictions and model predictions should match exactly if `n_neighbors` is the same and `query_data` is equal to the training data.\n\n\n### **Metrics**\n\nWe made our own metrics submodule to make the lib self-contained. `xgbse.metrics` implements C-index, Brier Score and D-Calibration from [9], including adaptations to deal with censoring:\n\n```python\n# training model\nxgbse_model = XGBSEKaplanNeighbors(PARAMS_XGB_AFT, n_neighbors=30)\n\nxgbse_model.fit(\n    X_train, y_train,\n    validation_data = (X_valid, y_valid),\n    early_stopping_rounds=10,\n    time_bins=TIME_BINS\n)\n\n# predicting\npreds = xgbse_model.predict(X_valid)\n\n# importing metrics\nfrom xgbse.metrics import (\n    concordance_index,\n    approx_brier_score,\n    dist_calibration_score\n)\n\n# running metrics\nprint(f'C-index: {concordance_index(y_valid, preds)}')\nprint(f'Avg. Brier Score: {approx_brier_score(y_valid, preds)}')\nprint(f\"\"\"D-Calibration: {dist_calibration_score(y_valid, preds) \u003e 0.05}\"\"\")\n```\n\n```\nC-index: 0.6495863029409356\nAvg. Brier Score: 0.1704190044350422\nD-Calibration: True\n```\nAs metrics follow the `score_func(y, y_pred, **kwargs)` pattern, we can use the sklearn model selection module easily:\n\n```python\nfrom sklearn.model_selection import cross_val_score\nfrom sklearn.metrics import make_scorer\n\nxgbse_model = XGBSEKaplanTree(PARAMS_TREE)\nresults = cross_val_score(xgbse_model, X, y, scoring=make_scorer(approx_brier_score))\nresults\n```\n```\narray([0.17432953, 0.15907712, 0.13783666, 0.16770409, 0.16792016])\n```\n\nIf you want to dive deeper, please check our [docs](loft-br.github.io/xgboost-survival-embeddings/) and [examples](https://loft-br.github.io/xgboost-survival-embeddings/examples/how_xgbse_works.html)!\n\n\n## References\n\n[1] [Practical Lessons from Predicting Clicks on Ads at Facebook](https://research.fb.com/wp-content/uploads/2016/11/practical-lessons-from-predicting-clicks-on-ads-at-facebook.pdf): paper that shows how stacking boosting models with logistic regression improves performance and calibration\n\n[2] [Feature transformations with ensembles of trees](https://scikit-learn.org/stable/auto_examples/ensemble/plot_feature_transformation.html): scikit-learn post showing tree ensembles as feature transformers\n\n[3] [Calibration of probabilities for tree-based models](https://gdmarmerola.github.io/probability-calibration/): blog post showing a practical example of tree ensemble probability calibration with a logistic regression\n\n[4] [Supervised dimensionality reduction and clustering at scale with RFs with UMAP](https://gdmarmerola.github.io/umap-supervised-embeddings/): blog post showing how forests of decision trees act as noise filters, reducing intrinsic dimension of the dataset.\n\n[5] [Learning Patient-Specific Cancer Survival Distributions as a Sequence of Dependent Regressors](http://www.cs.cornell.edu/~cnyu/papers/nips11_survival.pdf): inspiration for the BCE method (multi-task logistic regression)\n\n[6] [The Brier Score under Administrative Censoring: Problems and Solutions](https://arxiv.org/pdf/1912.08581.pdf): reference to BCE (binary cross-entropy survival method).\n\n[7] [The Greenwood and Exponential Greenwood Confidence Intervals in Survival Analysis](https://www.math.wustl.edu/~sawyer/handouts/greenwood.pdf): reference we used for the Exponential Greenwood formula from KM confidence intervals\n\n[8] [Tree Space Prototypes: Another Look at Making Tree Ensembles Interpretable](https://arxiv.org/abs/1611.07115): paper showing a very similar method for extracting prototypes\n\n[9] [Effective Ways to Build and Evaluate Individual Survival Distributions](https://arxiv.org/pdf/1811.11347.pdf): paper showing how to validate survival analysis models with different metrics\n\n## Citing `xgbse`\n\nTo cite this repository:\n\n```\n@software{xgbse2020github,\n  author = {Davi Vieira and Gabriel Gimenez and Guilherme Marmerola and Vitor Estima},\n  title = {XGBoost Survival Embeddings: improving statistical properties of XGBoost survival analysis implementation},\n  url = {http://github.com/loft-br/xgboost-survival-embeddings},\n  version = {0.3.1},\n  year = {2021},\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floft-br%2Fxgboost-survival-embeddings","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Floft-br%2Fxgboost-survival-embeddings","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floft-br%2Fxgboost-survival-embeddings/lists"}