Tutorial (Hello World)๏ƒ

A minimal โ€œHello Worldโ€ using APLUS. Please see this folder in the repository for downloadable code.

1. Self-Contained Example๏ƒ

The code below shows the simplest way to run APLUS. It is entirely self-contained using Python for configuration and no file dependencies.

script.py๏ƒ
  1import aplusml
  2from aplusml.config import Config, ConfigMetadata, ConfigVariable, ConfigState, ConfigTransition, ConfigUtility
  3import numpy as np
  4import pandas as pd
  5from typing import List, Dict
  6import collections
  7
  8# Create config
  9config = Config(
 10    metadata = ConfigMetadata(
 11        name = 'Hello World Workflow',
 12        path_to_properties = None,
 13    ),
 14    variables = {
 15        'patient_property_1': ConfigVariable(
 16            type = 'property',
 17            value = None, # Note: Will get overwritten later
 18        ),
 19        'patient_property_2': ConfigVariable(
 20            type = 'property',
 21            value = None, # Note: Will get overwritten later
 22        ),
 23        'some_constant': ConfigVariable(
 24            type = 'scalar',
 25            value = 10,
 26        ),
 27    },
 28    states = {
 29        'start': ConfigState(
 30            type = 'start',
 31            label = 'Start',
 32            transitions = [
 33                ConfigTransition(
 34                    dest = 'state_2',
 35                ),
 36            ],
 37        ),
 38        'state_2': ConfigState(
 39            type = 'intermediate',
 40            label = 'Switch',
 41            transitions = [
 42                ConfigTransition(dest = 'state_3', if_ = 'patient_property_1 > patient_property_2'),
 43                ConfigTransition(dest = 'state_4', if_ = 'patient_property_1 <= patient_property_2'),
 44            ],
 45        ),
 46        'state_3': ConfigState(
 47            type = 'end',
 48            label = 'Good End',
 49            utilities = [
 50                ConfigUtility(
 51                    value = 100,
 52                    unit = 'USD',
 53                ),
 54            ],
 55        ),
 56        'state_4': ConfigState(
 57            type = 'end',
 58            label = 'Bad End',
 59            utilities = [
 60                ConfigUtility(
 61                    value = 0,
 62                    unit = 'USD',
 63                ),
 64            ],
 65        ),
 66    },
 67)
 68
 69# Create simulation.
 70simulation: aplusml.Simulation = aplusml.Simulation.create_from_config(config)
 71
 72# Set random seed for reproducibility
 73np.random.seed(0)
 74
 75# Create Patients from CSV
 76df = pd.DataFrame(
 77    data = {
 78        'patient_id': [1, 2, 3, 4, 5, 6],
 79        'patient_property_1': [1, 1, 6, 6, 2, 2],
 80        'patient_property_2': [2, 5, 5, 1, 1, 8],
 81        'start_timestep': [0, 1, 2, 0, 1, 0],
 82    }
 83)
 84patients: List[aplusml.Patient] = [
 85    aplusml.Patient(
 86        id = row['patient_id'],
 87        start_timestep=row['start_timestep'],
 88        properties = {
 89            'patient_property_1': row['patient_property_1'],
 90            'patient_property_2': row['patient_property_2'],
 91        }
 92    )
 93    for _, row in df.iterrows()
 94]
 95
 96# Initialize patients for simulation.
 97# NOTE: Do not overwrite existing properties b/c we just manually set them above!
 98patients: List[aplusml.Patient] = simulation.create_patients_for_simulation(patients,
 99                                                                            is_overwrite_existing_properties=False, # ! IMPORTANT
100                                                                            random_seed = 0)
101
102# Run simulation
103patients = simulation.run(patients)
104
105# Sum up the utilities achieved across all patient histories
106sum_utilities: Dict[str, float] = collections.defaultdict(float)
107for p in patients:
108        _u: dict = p.get_sum_utilities(simulation)
109        for key, val in _u.items():
110                sum_utilities[key] += val
111
112# Print workflow diagram
113simulation.draw_workflow_diagram('workflow.png', is_display=False)
114
115# Print results
116print('Utilities:', sum_utilities)
117# > Utilities: {'USD': 300.0}
118
119# Print patient histories
120for p in patients:
121        print('Patient', p.id, 'History:', p.repr_state_history())
122# > Patient 1 History: start > state_2 > state_4
123# > Patient 2 History: start > state_2 > state_3
124# > Patient 3 History: start > state_2 > state_4
125# > Patient 4 History: start > state_2 > state_4
126# > Patient 5 History: start > state_2 > state_3
127# > Patient 6 History: start > state_2 > state_3

2. Example with YAML config + Patient Properties CSV file๏ƒ

For more complex configs, you might want to specify them as YAML + CSV files instead of Python objects. Hereโ€™s an example specifying the same workflow as above.

config.yaml๏ƒ
 1 metadata:
 2    name: "Hello World Workflow"
 3    path_to_properties: "patient_properties.csv"
 4    properties_col_for_patient_id: "patient_id"
 5
 6variables:
 7  patient_property_1:
 8    type: "property"
 9    column: "patient_property_1"
10  patient_property_2:
11    type: "property"
12    column: "patient_property_2"
13  some_constant:
14    type: "scalar"
15    value: 10
16
17states:
18  start:
19    label: "Start"
20    type: "start"
21    transitions:
22      - dest: "state_2"
23  state_2:
24    label: "Switch"
25    type: "intermediate"
26    transitions:
27      - dest: "state_3"
28        if: patient_property_1 > patient_property_2
29      - dest: "state_4"
30        if: patient_property_1 <= patient_property_2
31  state_3:
32    label: "Good End"
33    type: "end"
34    utilities:
35      - value: 100
36        unit: "USD"
37  state_4:
38    label: "Bad End"
39    type: "end"
40    utilities:
41      - value: 0
42        unit: "USD"
patient_properties.csv๏ƒ
 patient_id,patient_property_1,patient_property_2,start_timestep
 1,1,2,0
 2,1,5,1
 3,6,5,2
 4,6,1,0
 5,2,1,1
 6,2,8,0
script_with_yaml.py๏ƒ
 1import aplusml
 2import numpy as np
 3import pandas as pd
 4from typing import List, Dict
 5import collections
 6
 7PATH_TO_CONFIG_YAML: str = "config.yaml"
 8PATH_TO_PATIENT_PROPERTIES: str = "patient_properties.csv"
 9
10# Create simulation. Loads workflow + simulation parameters from YAML file, patient properties from CSV file.
11# If `path_to_patient_properties` is None, then the default `metadata.path_to_properties` key in the YAML file is used. Here, we explicitly override it.
12simulation: aplusml.Simulation = aplusml.Simulation.create_from_yaml(PATH_TO_CONFIG_YAML, PATH_TO_PATIENT_PROPERTIES)
13
14# Set random seed for reproducibility
15np.random.seed(0)
16
17# Create Patients from CSV
18df = pd.read_csv(PATH_TO_PATIENT_PROPERTIES)
19patients: List[aplusml.Patient] = [
20  aplusml.Patient(
21    id = row['patient_id'],
22    start_timestep=row['start_timestep'],
23    properties = {
24      'patient_property_1': row['patient_property_1'],
25      'patient_property_2': row['patient_property_2'],
26    }
27  )
28  for _, row in df.iterrows()
29]
30
31# Initialize patients for simulation.
32patients: List[aplusml.Patient] = simulation.create_patients_for_simulation(patients, random_seed = 0)
33
34# Run simulation
35patients = simulation.run(patients)
36
37# Sum up the utilities achieved across all patient histories
38sum_utilities: Dict[str, float] = collections.defaultdict(float)
39for p in patients:
40    _u: dict = p.get_sum_utilities(simulation)
41    for key, val in _u.items():
42        sum_utilities[key] += val
43
44# Print workflow diagram
45simulation.draw_workflow_diagram('workflow.png', is_display=False)
46
47# Print results
48print('Utilities:', sum_utilities)
49# > Utilities: {'USD': 300.0}
50
51# Print patient histories
52for p in patients:
53    print('Patient', p.id, 'History:', p.repr_state_history())
54# > Patient 1 History: start > state_2 > state_4
55# > Patient 2 History: start > state_2 > state_3
56# > Patient 3 History: start > state_2 > state_4
57# > Patient 4 History: start > state_2 > state_4
58# > Patient 5 History: start > state_2 > state_3
59# > Patient 6 History: start > state_2 > state_3