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