gazoo-research-utils 2.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gazoo_research_utils-2.0.1/LICENSE +7 -0
- gazoo_research_utils-2.0.1/PKG-INFO +176 -0
- gazoo_research_utils-2.0.1/README.md +157 -0
- gazoo_research_utils-2.0.1/pyproject.toml +34 -0
- gazoo_research_utils-2.0.1/src/gazoo_research_utils/Analysis-v1.py +1106 -0
- gazoo_research_utils-2.0.1/src/gazoo_research_utils/Analysis-v2.py +1429 -0
- gazoo_research_utils-2.0.1/src/gazoo_research_utils/Analysis.py +1439 -0
- gazoo_research_utils-2.0.1/src/gazoo_research_utils/__init__.py +0 -0
- gazoo_research_utils-2.0.1/src/gazoo_research_utils/models/filter_model.py +23 -0
- gazoo_research_utils-2.0.1/src/gazoo_research_utils/reframe.ipynb +2537 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright 2026 Andrew Lim
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gazoo-research-utils
|
|
3
|
+
Version: 2.0.1
|
|
4
|
+
Summary: Utilities for the Analysis of Gazoo Research Data
|
|
5
|
+
Author: Andrew Lim MD, Megan Lim MD, Christopher Lim MD, Robert Lim MD
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Dist: lifelines>=0.28.0
|
|
11
|
+
Requires-Dist: pandas>=3.0.0
|
|
12
|
+
Requires-Dist: pydantic>=2.12.5
|
|
13
|
+
Requires-Dist: pytest>=7.4.0 ; extra == 'dev'
|
|
14
|
+
Requires-Dist: pytest-cov>=4.1.0 ; extra == 'dev'
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Project-URL: Homepage, https://gazooresearch.com/
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# GazooResearchUtils
|
|
21
|
+
GazooResearchUtils is a python library whose purpose is to analyze medical data from GazooResearch.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
## Example output from GazooResearch prostate-data.csv
|
|
25
|
+
The data is denormalized on fields, but ultimately has this hierarchy.
|
|
26
|
+
id -> collection -> tag -> (field, data_type, value, phi)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### Column descriptions are as follows
|
|
30
|
+
id: patient identification
|
|
31
|
+
collection: A collection of related tags
|
|
32
|
+
tag: name of tag (eg. dob, psa)
|
|
33
|
+
tag_id: Unique identifier
|
|
34
|
+
field: tag name (date, value, date)
|
|
35
|
+
data_type: data type held in the value column. Options are: text, categorical, number, date). dates will be of this form YYYY-MM-DD
|
|
36
|
+
value: value of field
|
|
37
|
+
phi: 0 or 1, depending on if the data element is protected health information
|
|
38
|
+
|
|
39
|
+
### Issues
|
|
40
|
+
The value field may be empty, or will contain data conforming to the data_type structure.
|
|
41
|
+
|
|
42
|
+
```csv
|
|
43
|
+
id,collection,tag,tag_id,field,data_type,value,phi
|
|
44
|
+
111111,0,id,#6bed55ed-f844-4c88-ab74-af0e74aa2547,mrn,text,111111,1
|
|
45
|
+
111111,0,last-name,bd7e898c-9732-4320-8227-a1b90cc8c80e,value,text,Bing,1
|
|
46
|
+
111111,0,first-name,#4ff0ace3-e804-4d55-97a0-22cc6f927327,value,text,Chandler,1
|
|
47
|
+
111111,0,dob,#5578f001-b34b-4465-b699-8c8ff6c11d89,date,date,1952-12-17,0
|
|
48
|
+
111111,0,document,#ce5ab218-8e98-417b-b843-965ea637ca57,date,date,2023-12-06,0
|
|
49
|
+
111111,0,document,#ce5ab218-8e98-417b-b843-965ea637ca57,type,categorical,clinical,0
|
|
50
|
+
111111,c61,surgery,#6082ea75-06c3-4082-9c69-918d0df8c619,date,date,2010-01-01,0
|
|
51
|
+
111111,c61,surgery,#6082ea75-06c3-4082-9c69-918d0df8c619,type,categorical,prostatectomy-lymphadenectomy,0
|
|
52
|
+
111111,c61,surgery,#6082ea75-06c3-4082-9c69-918d0df8c619,target-id,text,prostate,0
|
|
53
|
+
111111,c61,R,#358ebce7-9e7d-441c-a976-38d02d3da58e,date,date,2010-01-01,0
|
|
54
|
+
111111,c61,R,#358ebce7-9e7d-441c-a976-38d02d3da58e,R,categorical,0,0
|
|
55
|
+
111111,c61,pT,#2485755d-aa2a-4fa9-a263-4d11c9370145,date,date,2010-01-01,0
|
|
56
|
+
111111,c61,pT,#2485755d-aa2a-4fa9-a263-4d11c9370145,T,categorical,2c,0
|
|
57
|
+
111111,c61,pN,#8d04921a-cee6-4c7c-9eb2-d954c1b33008,date,date,2010-01-01,0
|
|
58
|
+
111111,c61,pN,#8d04921a-cee6-4c7c-9eb2-d954c1b33008,N,categorical,0,0
|
|
59
|
+
111111,c61,pN,#8d04921a-cee6-4c7c-9eb2-d954c1b33008,involved-lymph-nodes,number,,0
|
|
60
|
+
111111,c61,pN,#8d04921a-cee6-4c7c-9eb2-d954c1b33008,total-lymph-nodes,number,,0
|
|
61
|
+
111111,c61,gleason-grade-group,#55109b94-41fe-4b11-a47a-824970ab9dfb,date,date,2010-01-01,0
|
|
62
|
+
111111,c61,gleason-grade-group,#55109b94-41fe-4b11-a47a-824970ab9dfb,value,categorical,2,0
|
|
63
|
+
111111,c61,gleason-grade-group,#55109b94-41fe-4b11-a47a-824970ab9dfb,target-id,text,prostate,0
|
|
64
|
+
111111,c61,psa,64987467-bcc2-4c23-a943-899467d93981,date,date,2019-02-22,0
|
|
65
|
+
111111,c61,psa,64987467-bcc2-4c23-a943-899467d93981,value,number,0.28,0
|
|
66
|
+
111111,c61,psa,64987467-bcc2-4c23-a943-899467d93981,units,categorical,ng/ml,0
|
|
67
|
+
111111,c61,psa,91a5221d-de16-4af9-acb6-82b7d37ed118,date,date,2019-06-12,0
|
|
68
|
+
111111,c61,psa,91a5221d-de16-4af9-acb6-82b7d37ed118,value,number,0.31,0
|
|
69
|
+
111111,c61,psa,91a5221d-de16-4af9-acb6-82b7d37ed118,units,categorical,ng/ml,0
|
|
70
|
+
111111,c61,psa,6ed2dc02-af27-4395-a73e-36af30b7fed6,date,date,2023-12-06,0
|
|
71
|
+
111111,c61,psa,6ed2dc02-af27-4395-a73e-36af30b7fed6,value,number,0.01,0
|
|
72
|
+
111111,c61,psa,6ed2dc02-af27-4395-a73e-36af30b7fed6,units,categorical,ng/ml,0
|
|
73
|
+
111111,c61,androgen-deprivation-therapy,#ed2d15d6-2650-41fe-af7d-e9b6ac1140d6,start-date,date,2019-07-15,0
|
|
74
|
+
111111,c61,androgen-deprivation-therapy,#ed2d15d6-2650-41fe-af7d-e9b6ac1140d6,end-date,date,2019-12-06,0
|
|
75
|
+
111111,c61,androgen-deprivation-therapy,#ed2d15d6-2650-41fe-af7d-e9b6ac1140d6,medication,categorical,leuprolide,0
|
|
76
|
+
111111,c61,external-radiation,#407ad0f8-a8ef-4e21-a41c-6ba11a85d777,start-date,date,2019-08-15,0
|
|
77
|
+
111111,c61,external-radiation,#407ad0f8-a8ef-4e21-a41c-6ba11a85d777,end-date,date,2019-10-03,0
|
|
78
|
+
111111,c61,external-radiation,#407ad0f8-a8ef-4e21-a41c-6ba11a85d777,field,categorical,prostate-bed-pelvic-lymph-nodes,0
|
|
79
|
+
111111,c61,external-radiation,#407ad0f8-a8ef-4e21-a41c-6ba11a85d777,dose,number,,0
|
|
80
|
+
111111,c61,external-radiation,#407ad0f8-a8ef-4e21-a41c-6ba11a85d777,unit,categorical,Gy,0
|
|
81
|
+
111111,c61,external-radiation,#407ad0f8-a8ef-4e21-a41c-6ba11a85d777,fractions,number,,0
|
|
82
|
+
111111,c61,external-radiation,#407ad0f8-a8ef-4e21-a41c-6ba11a85d777,technique,categorical,unknown,0
|
|
83
|
+
111111,c61,external-radiation,#407ad0f8-a8ef-4e21-a41c-6ba11a85d777,target-id,text,prostate,0
|
|
84
|
+
111111,c61,biochemical-progression,#e6458863-ceba-4194-a361-df96407d5c3a,date,date,,0
|
|
85
|
+
111111,c61,biochemical-progression,#e6458863-ceba-4194-a361-df96407d5c3a,type,categorical,aua,0
|
|
86
|
+
111111,0,last-name,#3dd60c0d-d51d-4c4a-8250-715a8f415207,value,text,Bing,1
|
|
87
|
+
111111,0,id,#1c9d95e8-7d8b-4102-990b-02ebea1e9a14,mrn,text,111111,1
|
|
88
|
+
111111,0,dob,#47a681ae-23a8-41e8-b569-32039d3f47b4,date,date,1952-12-17,0
|
|
89
|
+
111111,c61,psa,#b482b981-cf18-420f-b518-d3f6279f03c5,date,date,2019-02-22,0
|
|
90
|
+
111111,c61,psa,#b482b981-cf18-420f-b518-d3f6279f03c5,value,number,0.28,0
|
|
91
|
+
111111,c61,psa,#b482b981-cf18-420f-b518-d3f6279f03c5,units,categorical,ng/ml,0
|
|
92
|
+
333333,0,id,c918371b-01f7-49ee-acd8-b00dee6e49e9,mrn,text,333333,1
|
|
93
|
+
333333,0,first-name,dc110270-d5c1-431c-8f90-86459bed3a36,value,text,Joey,1
|
|
94
|
+
333333,0,last-name,2d9ae449-8d3f-4493-82a8-75321f4df6cd,value,text,Tribbiani,1
|
|
95
|
+
333333,0,dob,d1044870-b049-4465-b306-e0eb1a20b8c2,date,date,1948-01-22,0
|
|
96
|
+
333333,c61,surgery,#a5b2b0b0-1752-401f-a4d6-63f41dec128b,date,date,2019-08-31,0
|
|
97
|
+
333333,c61,surgery,#a5b2b0b0-1752-401f-a4d6-63f41dec128b,type,categorical,prostatectomy,0
|
|
98
|
+
333333,c61,surgery,#a5b2b0b0-1752-401f-a4d6-63f41dec128b,target-id,text,prostate,0
|
|
99
|
+
333333,c61,pT,#3d0cf1cf-3608-4f98-95f9-7569d0f57a63,date,date,2019-08-31,0
|
|
100
|
+
333333,c61,pT,#3d0cf1cf-3608-4f98-95f9-7569d0f57a63,T,categorical,3a,0
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
## Anchors
|
|
105
|
+
Often when calculating time based analysis, we need a starting point. An anchor is used to define that starting point. An anchor json follow the same structure as a filter json. **Anchors should have a date field**.
|
|
106
|
+
```json
|
|
107
|
+
anchor = {'collection':str, 'tag': str, 'field': str, 'exact': [str, str,...], 'between': [float, float]}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Tag Sequence
|
|
111
|
+
Sometimes you want to find an ordered scenario, for example you may want to find patients that first have surgery and then adjuvant radiation. Your anchor may have this structure:
|
|
112
|
+
```json
|
|
113
|
+
anchor = [{'tag': 'surgery'},{'tag':'radiation'}]
|
|
114
|
+
```
|
|
115
|
+
Note that you are not interested in the type of surgery, or type of radiation.
|
|
116
|
+
|
|
117
|
+
### Time Delta
|
|
118
|
+
time_delta represents the maximum number of **days** between anchor tags. This is only relavant if there is >1 anchor tag.
|
|
119
|
+
|
|
120
|
+
# Instance
|
|
121
|
+
There may be multiple instances of an anchor sequence. 'instance' defines which one matters.
|
|
122
|
+
instance = 0 - Means that the 1st instance of this anchor sequence will be used.
|
|
123
|
+
|
|
124
|
+
# Time Delta
|
|
125
|
+
Represents the maximum allowable days between anchors.
|
|
126
|
+
```json
|
|
127
|
+
anchor = [{'tag': 'surgery'},{'tag':'radiation'}]
|
|
128
|
+
time_delta = 60
|
|
129
|
+
# the maximum time between surgery and radaition is 60 days. Useful if you don't want to indentify patients with salvage radiotherapy that typically occurs many months to years later.
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Data Filtering
|
|
133
|
+
A filter json will be used to find patients that have matching tags. The filter does not need to include all fields. When you want to find patients matching multiple critera specify 'filters' which is an array of filter json.
|
|
134
|
+
```json
|
|
135
|
+
filter = {'collection':str, 'tag': str, 'field': str, 'exact': [str, str,...], 'between': [float, float]}
|
|
136
|
+
```
|
|
137
|
+
It may include:
|
|
138
|
+
* collection alone
|
|
139
|
+
```json
|
|
140
|
+
filter = {'collection':'c61'}
|
|
141
|
+
```
|
|
142
|
+
* tag alone
|
|
143
|
+
```json
|
|
144
|
+
filter = {'tag':'psa'}
|
|
145
|
+
```
|
|
146
|
+
* field alone
|
|
147
|
+
```json
|
|
148
|
+
filter = {'tag':'psa'}
|
|
149
|
+
```
|
|
150
|
+
* field with a value that exactly matches
|
|
151
|
+
```json
|
|
152
|
+
filter = {'field':'histology', 'exact': ['melanoma', 'squamous-cell-carcinoma']}
|
|
153
|
+
```
|
|
154
|
+
* field with a value that is a number and is between two values
|
|
155
|
+
```json
|
|
156
|
+
filter = {'field':'psa', 'between': [0.2, 0.5]}
|
|
157
|
+
```
|
|
158
|
+
* or a combination of the above
|
|
159
|
+
```json
|
|
160
|
+
filter = {'tag':'psa', 'field':'psa', 'between': [0.2, 0.5]}
|
|
161
|
+
```
|
|
162
|
+
When you want to find patients matching multiple critera specify 'filters' which is an array of filter json.<br>The below filters finds patients who have both gleason grade group 4 OR 5, AND psa between 0.2-0.5.
|
|
163
|
+
```json
|
|
164
|
+
filters = [{'field':'gleason-grade-group', 'exact': [4,5]}, {'tag':'psa', 'field':'psa', 'between': [0.2, 0.5]}]
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Search Range
|
|
168
|
+
The represents the time period before and after the anchor should be examined for the filters criteria (units: days).
|
|
169
|
+
<br>
|
|
170
|
+
For example, imagine you are researching prostate cancer patients getting radiation. You are interested in looking at patients with a pre-RT psa >=20 ng/mL.
|
|
171
|
+
```json
|
|
172
|
+
anchors = [{'tag':'radiation'}]
|
|
173
|
+
filters = [{'tag':'psa', 'field':'psa', 'between': [20, 10000]}]
|
|
174
|
+
search_range = [-90, 1] # Include patients who had a PSA >20 ng/mL 90 days before starting radiation, or 1 day after radiotherapy.
|
|
175
|
+
|
|
176
|
+
```
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# GazooResearchUtils
|
|
2
|
+
GazooResearchUtils is a python library whose purpose is to analyze medical data from GazooResearch.
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
## Example output from GazooResearch prostate-data.csv
|
|
6
|
+
The data is denormalized on fields, but ultimately has this hierarchy.
|
|
7
|
+
id -> collection -> tag -> (field, data_type, value, phi)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Column descriptions are as follows
|
|
11
|
+
id: patient identification
|
|
12
|
+
collection: A collection of related tags
|
|
13
|
+
tag: name of tag (eg. dob, psa)
|
|
14
|
+
tag_id: Unique identifier
|
|
15
|
+
field: tag name (date, value, date)
|
|
16
|
+
data_type: data type held in the value column. Options are: text, categorical, number, date). dates will be of this form YYYY-MM-DD
|
|
17
|
+
value: value of field
|
|
18
|
+
phi: 0 or 1, depending on if the data element is protected health information
|
|
19
|
+
|
|
20
|
+
### Issues
|
|
21
|
+
The value field may be empty, or will contain data conforming to the data_type structure.
|
|
22
|
+
|
|
23
|
+
```csv
|
|
24
|
+
id,collection,tag,tag_id,field,data_type,value,phi
|
|
25
|
+
111111,0,id,#6bed55ed-f844-4c88-ab74-af0e74aa2547,mrn,text,111111,1
|
|
26
|
+
111111,0,last-name,bd7e898c-9732-4320-8227-a1b90cc8c80e,value,text,Bing,1
|
|
27
|
+
111111,0,first-name,#4ff0ace3-e804-4d55-97a0-22cc6f927327,value,text,Chandler,1
|
|
28
|
+
111111,0,dob,#5578f001-b34b-4465-b699-8c8ff6c11d89,date,date,1952-12-17,0
|
|
29
|
+
111111,0,document,#ce5ab218-8e98-417b-b843-965ea637ca57,date,date,2023-12-06,0
|
|
30
|
+
111111,0,document,#ce5ab218-8e98-417b-b843-965ea637ca57,type,categorical,clinical,0
|
|
31
|
+
111111,c61,surgery,#6082ea75-06c3-4082-9c69-918d0df8c619,date,date,2010-01-01,0
|
|
32
|
+
111111,c61,surgery,#6082ea75-06c3-4082-9c69-918d0df8c619,type,categorical,prostatectomy-lymphadenectomy,0
|
|
33
|
+
111111,c61,surgery,#6082ea75-06c3-4082-9c69-918d0df8c619,target-id,text,prostate,0
|
|
34
|
+
111111,c61,R,#358ebce7-9e7d-441c-a976-38d02d3da58e,date,date,2010-01-01,0
|
|
35
|
+
111111,c61,R,#358ebce7-9e7d-441c-a976-38d02d3da58e,R,categorical,0,0
|
|
36
|
+
111111,c61,pT,#2485755d-aa2a-4fa9-a263-4d11c9370145,date,date,2010-01-01,0
|
|
37
|
+
111111,c61,pT,#2485755d-aa2a-4fa9-a263-4d11c9370145,T,categorical,2c,0
|
|
38
|
+
111111,c61,pN,#8d04921a-cee6-4c7c-9eb2-d954c1b33008,date,date,2010-01-01,0
|
|
39
|
+
111111,c61,pN,#8d04921a-cee6-4c7c-9eb2-d954c1b33008,N,categorical,0,0
|
|
40
|
+
111111,c61,pN,#8d04921a-cee6-4c7c-9eb2-d954c1b33008,involved-lymph-nodes,number,,0
|
|
41
|
+
111111,c61,pN,#8d04921a-cee6-4c7c-9eb2-d954c1b33008,total-lymph-nodes,number,,0
|
|
42
|
+
111111,c61,gleason-grade-group,#55109b94-41fe-4b11-a47a-824970ab9dfb,date,date,2010-01-01,0
|
|
43
|
+
111111,c61,gleason-grade-group,#55109b94-41fe-4b11-a47a-824970ab9dfb,value,categorical,2,0
|
|
44
|
+
111111,c61,gleason-grade-group,#55109b94-41fe-4b11-a47a-824970ab9dfb,target-id,text,prostate,0
|
|
45
|
+
111111,c61,psa,64987467-bcc2-4c23-a943-899467d93981,date,date,2019-02-22,0
|
|
46
|
+
111111,c61,psa,64987467-bcc2-4c23-a943-899467d93981,value,number,0.28,0
|
|
47
|
+
111111,c61,psa,64987467-bcc2-4c23-a943-899467d93981,units,categorical,ng/ml,0
|
|
48
|
+
111111,c61,psa,91a5221d-de16-4af9-acb6-82b7d37ed118,date,date,2019-06-12,0
|
|
49
|
+
111111,c61,psa,91a5221d-de16-4af9-acb6-82b7d37ed118,value,number,0.31,0
|
|
50
|
+
111111,c61,psa,91a5221d-de16-4af9-acb6-82b7d37ed118,units,categorical,ng/ml,0
|
|
51
|
+
111111,c61,psa,6ed2dc02-af27-4395-a73e-36af30b7fed6,date,date,2023-12-06,0
|
|
52
|
+
111111,c61,psa,6ed2dc02-af27-4395-a73e-36af30b7fed6,value,number,0.01,0
|
|
53
|
+
111111,c61,psa,6ed2dc02-af27-4395-a73e-36af30b7fed6,units,categorical,ng/ml,0
|
|
54
|
+
111111,c61,androgen-deprivation-therapy,#ed2d15d6-2650-41fe-af7d-e9b6ac1140d6,start-date,date,2019-07-15,0
|
|
55
|
+
111111,c61,androgen-deprivation-therapy,#ed2d15d6-2650-41fe-af7d-e9b6ac1140d6,end-date,date,2019-12-06,0
|
|
56
|
+
111111,c61,androgen-deprivation-therapy,#ed2d15d6-2650-41fe-af7d-e9b6ac1140d6,medication,categorical,leuprolide,0
|
|
57
|
+
111111,c61,external-radiation,#407ad0f8-a8ef-4e21-a41c-6ba11a85d777,start-date,date,2019-08-15,0
|
|
58
|
+
111111,c61,external-radiation,#407ad0f8-a8ef-4e21-a41c-6ba11a85d777,end-date,date,2019-10-03,0
|
|
59
|
+
111111,c61,external-radiation,#407ad0f8-a8ef-4e21-a41c-6ba11a85d777,field,categorical,prostate-bed-pelvic-lymph-nodes,0
|
|
60
|
+
111111,c61,external-radiation,#407ad0f8-a8ef-4e21-a41c-6ba11a85d777,dose,number,,0
|
|
61
|
+
111111,c61,external-radiation,#407ad0f8-a8ef-4e21-a41c-6ba11a85d777,unit,categorical,Gy,0
|
|
62
|
+
111111,c61,external-radiation,#407ad0f8-a8ef-4e21-a41c-6ba11a85d777,fractions,number,,0
|
|
63
|
+
111111,c61,external-radiation,#407ad0f8-a8ef-4e21-a41c-6ba11a85d777,technique,categorical,unknown,0
|
|
64
|
+
111111,c61,external-radiation,#407ad0f8-a8ef-4e21-a41c-6ba11a85d777,target-id,text,prostate,0
|
|
65
|
+
111111,c61,biochemical-progression,#e6458863-ceba-4194-a361-df96407d5c3a,date,date,,0
|
|
66
|
+
111111,c61,biochemical-progression,#e6458863-ceba-4194-a361-df96407d5c3a,type,categorical,aua,0
|
|
67
|
+
111111,0,last-name,#3dd60c0d-d51d-4c4a-8250-715a8f415207,value,text,Bing,1
|
|
68
|
+
111111,0,id,#1c9d95e8-7d8b-4102-990b-02ebea1e9a14,mrn,text,111111,1
|
|
69
|
+
111111,0,dob,#47a681ae-23a8-41e8-b569-32039d3f47b4,date,date,1952-12-17,0
|
|
70
|
+
111111,c61,psa,#b482b981-cf18-420f-b518-d3f6279f03c5,date,date,2019-02-22,0
|
|
71
|
+
111111,c61,psa,#b482b981-cf18-420f-b518-d3f6279f03c5,value,number,0.28,0
|
|
72
|
+
111111,c61,psa,#b482b981-cf18-420f-b518-d3f6279f03c5,units,categorical,ng/ml,0
|
|
73
|
+
333333,0,id,c918371b-01f7-49ee-acd8-b00dee6e49e9,mrn,text,333333,1
|
|
74
|
+
333333,0,first-name,dc110270-d5c1-431c-8f90-86459bed3a36,value,text,Joey,1
|
|
75
|
+
333333,0,last-name,2d9ae449-8d3f-4493-82a8-75321f4df6cd,value,text,Tribbiani,1
|
|
76
|
+
333333,0,dob,d1044870-b049-4465-b306-e0eb1a20b8c2,date,date,1948-01-22,0
|
|
77
|
+
333333,c61,surgery,#a5b2b0b0-1752-401f-a4d6-63f41dec128b,date,date,2019-08-31,0
|
|
78
|
+
333333,c61,surgery,#a5b2b0b0-1752-401f-a4d6-63f41dec128b,type,categorical,prostatectomy,0
|
|
79
|
+
333333,c61,surgery,#a5b2b0b0-1752-401f-a4d6-63f41dec128b,target-id,text,prostate,0
|
|
80
|
+
333333,c61,pT,#3d0cf1cf-3608-4f98-95f9-7569d0f57a63,date,date,2019-08-31,0
|
|
81
|
+
333333,c61,pT,#3d0cf1cf-3608-4f98-95f9-7569d0f57a63,T,categorical,3a,0
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
## Anchors
|
|
86
|
+
Often when calculating time based analysis, we need a starting point. An anchor is used to define that starting point. An anchor json follow the same structure as a filter json. **Anchors should have a date field**.
|
|
87
|
+
```json
|
|
88
|
+
anchor = {'collection':str, 'tag': str, 'field': str, 'exact': [str, str,...], 'between': [float, float]}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Tag Sequence
|
|
92
|
+
Sometimes you want to find an ordered scenario, for example you may want to find patients that first have surgery and then adjuvant radiation. Your anchor may have this structure:
|
|
93
|
+
```json
|
|
94
|
+
anchor = [{'tag': 'surgery'},{'tag':'radiation'}]
|
|
95
|
+
```
|
|
96
|
+
Note that you are not interested in the type of surgery, or type of radiation.
|
|
97
|
+
|
|
98
|
+
### Time Delta
|
|
99
|
+
time_delta represents the maximum number of **days** between anchor tags. This is only relavant if there is >1 anchor tag.
|
|
100
|
+
|
|
101
|
+
# Instance
|
|
102
|
+
There may be multiple instances of an anchor sequence. 'instance' defines which one matters.
|
|
103
|
+
instance = 0 - Means that the 1st instance of this anchor sequence will be used.
|
|
104
|
+
|
|
105
|
+
# Time Delta
|
|
106
|
+
Represents the maximum allowable days between anchors.
|
|
107
|
+
```json
|
|
108
|
+
anchor = [{'tag': 'surgery'},{'tag':'radiation'}]
|
|
109
|
+
time_delta = 60
|
|
110
|
+
# the maximum time between surgery and radaition is 60 days. Useful if you don't want to indentify patients with salvage radiotherapy that typically occurs many months to years later.
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Data Filtering
|
|
114
|
+
A filter json will be used to find patients that have matching tags. The filter does not need to include all fields. When you want to find patients matching multiple critera specify 'filters' which is an array of filter json.
|
|
115
|
+
```json
|
|
116
|
+
filter = {'collection':str, 'tag': str, 'field': str, 'exact': [str, str,...], 'between': [float, float]}
|
|
117
|
+
```
|
|
118
|
+
It may include:
|
|
119
|
+
* collection alone
|
|
120
|
+
```json
|
|
121
|
+
filter = {'collection':'c61'}
|
|
122
|
+
```
|
|
123
|
+
* tag alone
|
|
124
|
+
```json
|
|
125
|
+
filter = {'tag':'psa'}
|
|
126
|
+
```
|
|
127
|
+
* field alone
|
|
128
|
+
```json
|
|
129
|
+
filter = {'tag':'psa'}
|
|
130
|
+
```
|
|
131
|
+
* field with a value that exactly matches
|
|
132
|
+
```json
|
|
133
|
+
filter = {'field':'histology', 'exact': ['melanoma', 'squamous-cell-carcinoma']}
|
|
134
|
+
```
|
|
135
|
+
* field with a value that is a number and is between two values
|
|
136
|
+
```json
|
|
137
|
+
filter = {'field':'psa', 'between': [0.2, 0.5]}
|
|
138
|
+
```
|
|
139
|
+
* or a combination of the above
|
|
140
|
+
```json
|
|
141
|
+
filter = {'tag':'psa', 'field':'psa', 'between': [0.2, 0.5]}
|
|
142
|
+
```
|
|
143
|
+
When you want to find patients matching multiple critera specify 'filters' which is an array of filter json.<br>The below filters finds patients who have both gleason grade group 4 OR 5, AND psa between 0.2-0.5.
|
|
144
|
+
```json
|
|
145
|
+
filters = [{'field':'gleason-grade-group', 'exact': [4,5]}, {'tag':'psa', 'field':'psa', 'between': [0.2, 0.5]}]
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Search Range
|
|
149
|
+
The represents the time period before and after the anchor should be examined for the filters criteria (units: days).
|
|
150
|
+
<br>
|
|
151
|
+
For example, imagine you are researching prostate cancer patients getting radiation. You are interested in looking at patients with a pre-RT psa >=20 ng/mL.
|
|
152
|
+
```json
|
|
153
|
+
anchors = [{'tag':'radiation'}]
|
|
154
|
+
filters = [{'tag':'psa', 'field':'psa', 'between': [20, 10000]}]
|
|
155
|
+
search_range = [-90, 1] # Include patients who had a PSA >20 ng/mL 90 days before starting radiation, or 1 day after radiotherapy.
|
|
156
|
+
|
|
157
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["uv_build >= 0.9.28, <0.10.0", "twine==6.1.0"]
|
|
3
|
+
build-backend = "uv_build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "gazoo-research-utils"
|
|
7
|
+
version = "2.0.1"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name="Andrew Lim MD"},
|
|
10
|
+
{ name="Megan Lim MD" },
|
|
11
|
+
{ name="Christopher Lim MD" },
|
|
12
|
+
{ name="Robert Lim MD" },
|
|
13
|
+
]
|
|
14
|
+
description = "Utilities for the Analysis of Gazoo Research Data"
|
|
15
|
+
readme = "README.md"
|
|
16
|
+
requires-python = ">=3.11"
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
]
|
|
21
|
+
license = "MIT"
|
|
22
|
+
license-files = ["LICEN[CS]E*"]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"lifelines >= 0.28.0", "pandas>=3.0.0", "pydantic>=2.12.5"
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.urls]
|
|
28
|
+
Homepage = "https://gazooresearch.com/"
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
dev = [
|
|
32
|
+
"pytest>=7.4.0",
|
|
33
|
+
"pytest-cov>=4.1.0",
|
|
34
|
+
]
|