Example usage

To use probounds in a project:

import probounds.probounds as pb
import pandas as pd
import numpy as np
df_observed = pd.DataFrame(
    {
        "trt": np.concatenate([np.repeat(1, 1400), np.repeat(0, 600)] * 2),
        "outcome": [1] * 378
        + [0] * 1022
        + [1] * 420
        + [0] * 180
        + [1] * 980
        + [0] * 420
        + [1] * 420
        + [0] * 180,
        "sex": ["Female"] * 2000 + ["Male"] * 2000,
    }
)

df_experimental = pd.DataFrame(
    {
        "trt": np.concatenate([np.repeat(1, 1000), np.repeat(0, 1000)] * 2),
        "outcome": [1] * 489
        + [0] * 511
        + [1] * 210
        + [0] * 790
        + [1] * 490
        + [0] * 510
        + [1] * 210
        + [0] * 790,
        "sex": ["Female"] * 2000 + ["Male"] * 2000,
    }
)

probounds_crosstab_observed = pb.create_probounds_crosstab(
    df_observed, datatype="observational"
)
probounds_crosstab_experimental = pb.create_probounds_crosstab(
    df_experimental, datatype="experimental"
)
probounds_crosstab_observed = pb.create_probounds_crosstab(
    df_observed, datatype="observational"
)
probounds_crosstab_experimental = pb.create_probounds_crosstab(
    df_experimental, datatype="experimental"
)


probounds_crosstab_observed_by_sex = pb.probounds_crosstab_feature(
    df_observed, "observational", "sex"
)
probounds_crosstab_experimental_by_sex = pb.probounds_crosstab_feature(
    df_experimental, "experimental", "sex"
)
pb.calculate_bounds_observed_from_probounds_data(probounds_crosstab_observed)
pb.calculate_bounds_observed_from_probounds_data(
    probounds_crosstab_observed_by_sex["Female"]
)
pb.calculate_bounds_observed_from_probounds_data(
    probounds_crosstab_observed_by_sex["Male"]
)

pb.calculate_bounds_experimental_from_probounds_data(probounds_crosstab_experimental)
pb.calculate_bounds_experimental_from_probounds_data(
    probounds_crosstab_experimental_by_sex["Female"]
)
pb.calculate_bounds_experimental_from_probounds_data(
    probounds_crosstab_experimental_by_sex["Male"]
)
Benefit Bounds: 0 <= Benefit <= 0.4295
Benefit Bounds: 0 <= Benefit <= 0.279
Benefit Bounds: 0 <= Benefit <= 0.58
Benefit Bounds: 0.27949999999999997 <= Benefit <= 0.4895
Benefit Bounds: 0.279 <= Benefit <= 0.489
Benefit Bounds: 0.28 <= Benefit <= 0.49
{'lower_bound': np.float64(0.28), 'upper_bound': np.float64(0.49)}

1 Calculate Bounds Directly from Data

1.1 Observational Data

pb.calculate_bounds_observed(df_observed)
pb.calculate_bounds_observed_by_feature(df_observed, "sex")
Benefit Bounds: 0 <= Benefit <= 0.4295
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[18], line 2
      1 pb.calculate_bounds_observed(df_observed)
----> 2 pb.calculate_bounds_observed_by_feature(df_observed, 'sex')

AttributeError: module 'probounds.probounds' has no attribute 'calculate_bounds_observed_by_feature'

1.2 Experimental Data

pb.calculate_bounds_experimental(df_experimental)
pb.calculate_bounds_experimental(df_experimental[df_experimental["sex"] == "Female"])
pb.calculate_bounds_experimental(df_experimental[df_experimental["sex"] == "Male"])
Benefit Bounds: 0 <= Benefit <= 1.2795
Benefit Bounds: 0 <= Benefit <= 1.279
Benefit Bounds: 0 <= Benefit <= 1.28
{'lower_bound': 0, 'upper_bound': np.float64(1.28)}

1.3 Combined Data

pb.calculate_bounds_combined(df_observed, df_experimental)
pb.calculate_bounds_combined(
    df_observed[df_observed["sex"] == "Female"],
    df_experimental[df_experimental["sex"] == "Female"],
)
pb.calculate_bounds_combined(
    df_observed[df_observed["sex"] == "Male"],
    df_experimental[df_experimental["sex"] == "Male"],
)
{'lower_bound': np.float64(0.49), 'upper_bound': np.float64(0.49)}

2 Calculate Bounds by Feature

pb.calculate_bounds_combined_by_feature(df_observed, df_experimental, "sex")
Benefit Bounds: 0.279 <= Benefit|Female <= 0.279
Benefit Bounds: 0.49 <= Benefit|Male <= 0.49
{'Female': {'lower_bound': np.float64(0.279),
  'upper_bound': np.float64(0.279)},
 'Male': {'lower_bound': np.float64(0.49), 'upper_bound': np.float64(0.49)}}