Source code for acore.kaplan_meier_analysis

import pandas as pd

try:
    from lifelines import KaplanMeierFitter, NelsonAalenFitter
    from lifelines.statistics import multivariate_logrank_test
except ImportError as e:
    raise ImportError(
        "Error importing lifelines module. Make sure lifelines is installed. "
        "Install it with: pip install 'acore[all]'"
        f"\n\nError: {e}"
    ) from e


[docs] def get_data_ready_for_km(dfs_dict, args): kmdf = None for df_key in dfs_dict: if df_key == "clinical": kmdf = dfs_dict[df_key] else: df = dfs_dict[df_key] if "marker" in args and "index_col" in args: how = "half" value = None if "how" in args: how = args["how"] if "value" in args: value = args["value"] mdf = group_data_based_on_marker( df, args["marker"], args["index_col"], how, value ) if kmdf is not None: if "index_col" in args and args["index_col"] in kmdf: index_col = args["index_col"] kmdf = kmdf.set_index(index_col).join(mdf.set_index(index_col), how="inner") return kmdf
[docs] def group_data_based_on_marker(df, marker, index_col, how, value): mdf = pd.DataFrame() if index_col is not None and marker is not None: if index_col in df and marker in df: mdf = df[[marker, index_col]] if how == "cutoff": mdf["new_grouping"] = mdf.apply( lambda row: ( str(marker) + "+" if row[marker] >= value else str(marker) + "-" ) ) elif how == "top" or how == "top%": mdf = mdf.sort_values(by=marker, ascending=False) num_values = len(mdf[marker].values.tolist()) if how == "top%": value = int(num_values * value / 100) if value < num_values: labels = [str(marker) + "+"] * value labels.extend([str(marker) + "-"] * (num_values - value)) else: print( "Invalid value provided. Exceeded maximum number of samples {}".format( num_values ) ) mdf["new_grouping"] = labels else: print( "Grouping method {} not implemented. Try with 'cutoff' or 'top'".format( how ) ) return mdf
[docs] def run_km(data, time_col, event_col, group_col, args={}): kmdf = None kmf = pd.DataFrame() summary = None if isinstance(data, dict): kmdf = get_data_ready_for_km(data, args) group_col = "new_grouping" elif isinstance(data, pd.DataFrame): kmdf = data if kmdf is not None: kmf, summary = get_km_results(kmdf, group_col, time_col, event_col) return kmf, summary
[docs] def get_km_results(df, group_col, time_col, event_col): models = [] summary_ = None summary_result = None df = df[[event_col, time_col, group_col]].dropna() df[event_col] = df[event_col].astype("category") df[event_col] = df[event_col].cat.codes df[time_col] = df[time_col].astype("float") if not df.empty: for name, grouped_df in df.groupby(group_col): kmf = KaplanMeierFitter() t = grouped_df[time_col] e = grouped_df[event_col] kmf.fit( t, event_observed=e, label=name + " (N=" + str(len(t.tolist())) + ")" ) models.append(kmf) summary_ = multivariate_logrank_test( df[time_col].tolist(), df[group_col].tolist(), df[event_col].tolist(), alpha=99, ) if summary_ is not None: summary_result = "Multivariate logrank test: pval={}, t_statistic={}".format( summary_.p_value, summary_._test_statistic ) return models, summary_result
[docs] def get_hazard_ratio_results(df, group_col, time_col, event_col): models = [] df = df[[event_col, time_col, group_col]].dropna() df[event_col] = df[event_col].astype("category") df[event_col] = df[event_col].cat.codes df[time_col] = df[time_col].astype("float") if not df.empty: for name, grouped_df in df.groupby(group_col): hr = NelsonAalenFitter() t = grouped_df[time_col] e = grouped_df[event_col] hr.fit( t, event_observed=e, label=name + " (N=" + str(len(t.tolist())) + ")" ) models.append(hr) return models