Last active
September 22, 2022 19:47
-
-
Save MatthewCaseres/d338f85d768025623dcded0dd92e33ec to your computer and use it in GitHub Desktop.
Creating exposure intervals for policy/calendar intervals
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### A Pluto.jl notebook ### | |
# v0.19.11 | |
using Markdown | |
using InteractiveUtils | |
# ╔═╡ fb2b4952-3a91-11ed-116b-db769de7e1cc | |
begin | |
using Dates | |
end | |
# ╔═╡ 6d618467-eed2-4851-961e-e45ed4a455d0 | |
md""" | |
When simultaneously partitioning by policy and calendar `Month`/`Years` we can solve this with a two-pointers approach where our pointers are - | |
* `next_calendar_partition` | |
* `next_anniversary_partition` | |
In each iteration we place the next partition, `min(next_calendar_partition, next_anniversary_partition)`, increment the partition that was placed according to its increment size, and move to the next time step. | |
This is the basic idea of the algorithm. We also have to handle starting/ending dates of the study, which we now define some utility functions for. | |
""" | |
# ╔═╡ 2a8585fb-c4f8-4635-a999-963f442cc997 | |
begin | |
""" | |
Returns either the first anniversary strictly after the study start date, or the first anniversary up to and including the study start date. | |
""" | |
function get_maybe_first_anniversary(timestep::Month, anniv_date::Date, study_start::Date)::Date | |
return Date(year(study_start), month(study_start), day(anniv_date)) | |
end | |
function get_maybe_first_anniversary(timestep::Year, anniv_date::Date, study_start::Date)::Date | |
return Date(year(study_start), month(anniv_date), day(anniv_date)) | |
end | |
""" | |
get_first_anniversary_partition(timestep::Union{Year, Month}, anniv_date::Date, study_start::Date)::Date | |
The first anniversary strictly after the study start date | |
""" | |
function get_first_anniversary_partition(timestep::Union{Year, Month}, anniv_date::Date, study_start::Date)::Date | |
if anniv_date < study_start | |
maybe_first_anniversary = get_maybe_first_anniversary(timestep, anniv_date, study_start) | |
return maybe_first_anniversary < study_start ? maybe_first_anniversary + timestep : maybe_first_anniversary | |
else | |
return anniv_date + timestep | |
end | |
end | |
end | |
# ╔═╡ 48378996-32d7-45a8-b11f-616903d859e1 | |
begin | |
@assert get_first_anniversary_partition(Year(1), Date(2012, 1, 4), Date(2017, 2, 2)) == Date(2018, 1, 4) | |
@assert get_first_anniversary_partition(Year(1), Date(2012, 7, 4), Date(2017, 2, 2)) == Date(2017, 7, 4) | |
@assert get_first_anniversary_partition(Month(1), Date(2012, 7, 4), Date(2017, 2, 2)) == Date(2017, 2, 4) | |
@assert get_first_anniversary_partition(Month(1), Date(2012, 1, 1), Date(2017, 2, 2)) == Date(2017, 3, 1) | |
end | |
# ╔═╡ a42f02bd-e33a-406e-b4c1-13b51e39b99c | |
""" | |
get_first_calendar_partition(timestep::Union{Year, Month}, anniv_date::Date, study_start::Date)::Date | |
The first calendar partition strictly after the study start date | |
""" | |
function get_first_calendar_partition(timestep::Union{Year, Month}, anniv_date::Date, study_start::Date)::Date | |
return ceil(max(study_start, anniv_date) + Day(1), timestep) | |
end | |
# ╔═╡ 66f45298-6d5e-48e8-81fb-4b77deb85836 | |
begin | |
@assert get_first_calendar_partition(Month(1), Date(2018, 1, 31), Date(2018, 2, 28)) == Date(2018, 3, 1) | |
@assert get_first_calendar_partition(Month(1), Date(2018, 2, 1), Date(2018, 1, 1)) == Date(2018, 3, 1) | |
@assert get_first_calendar_partition(Year(1), Date(2018, 12, 31), Date(2019, 12, 31)) == Date(2020, 1, 1) | |
@assert get_first_calendar_partition(Year(1), Date(2019, 1, 1), Date(2018, 1, 1)) == Date(2020, 1, 1) | |
end | |
# ╔═╡ df60e747-e48f-4572-b699-14bba7a156f3 | |
struct AnniversaryCalendar | |
pol_period::Union{Month,Year} | |
cal_period::Union{Month,Year} | |
end | |
# ╔═╡ 76aa4c7f-a412-41d1-ae98-c10c14606b0a | |
""" | |
Create `Vector{Date}` of ordered interval endpoints | |
""" | |
function create_partition_endpoints(basis::AnniversaryCalendar, anniv_date::Date, termination_date::Union{Date, Nothing}, study_start::Date, study_end::Date)::Vector{Date} | |
# Get the partition start and end | |
partition_start = max(anniv_date, study_start) | |
if isnothing(termination_date) | |
partition_end = study_end | |
else | |
partition_end = min(termination_date, study_end) | |
end | |
# Empty if no overlap, if single day, endpoints are beggining and end of day | |
if partition_start > partition_end | |
return Vector{Date}[] | |
elseif partition_start == partition_end | |
return [partition_start, partition_end] # A single day | |
end | |
# now partition_start < partition_end | |
# Get the next partitions | |
next_anniv_partition = get_first_anniversary_partition(basis.pol_period, anniv_date, study_start) | |
next_cal_partition = get_first_calendar_partition(basis.cal_period, anniv_date, study_start) | |
# Increment pointers until we go past `partition_end` | |
result = [partition_start] | |
while result[end] < partition_end | |
if next_anniv_partition < next_cal_partition | |
push!(result, next_anniv_partition) | |
next_anniv_partition += basis.pol_period | |
elseif next_cal_partition < next_anniv_partition | |
push!(result, next_cal_partition) | |
next_cal_partition += basis.cal_period | |
else # next_cal_partition == next_anniv_partition | |
push!(result, next_anniv_partition) | |
next_anniv_partition += basis.pol_period | |
next_cal_partition += basis.cal_period | |
end | |
end | |
# clip to partition_end | |
result[end] = partition_end | |
return result | |
end | |
# ╔═╡ a176cd07-0a14-4916-95f4-bdc77be1a1a9 | |
begin | |
# If policy not in study, return empty array | |
@assert create_partition_endpoints( | |
AnniversaryCalendar(Month(1), Year(1)), # AnniversaryCalendar | |
Date(2010, 5, 7), # anniv_date | |
Date(2012, 12, 31), # termination_date | |
Date(2013, 1, 1), # study_start | |
Date(2014, 3, 10) # study_end | |
) == [] | |
# if termination_date == study_start, return [study_start, termination_date] | |
@assert create_partition_endpoints( | |
AnniversaryCalendar(Month(1), Year(1)), # AnniversaryCalendar | |
Date(2010, 5, 7), # anniv_date | |
Date(2013, 1, 1), # termination_date | |
Date(2013, 1, 1), # study_start | |
Date(2014, 3, 10) # study_end | |
) == [Date(2013, 1, 1), Date(2013, 1, 1)] | |
# termination_date == nothing | |
@assert create_partition_endpoints( | |
AnniversaryCalendar(Year(1), Year(1)), # AnniversaryCalendar | |
Date(2010, 5, 7), # anniv_date | |
nothing, # termination_date | |
Date(2013, 1, 1), # study_start | |
Date(2014, 3, 10) # study_end | |
) == [Date(2013, 1, 1), Date(2013, 5, 7), Date(2014, 1, 1), Date(2014, 3, 10)] | |
# termination_date < study_end | |
@assert create_partition_endpoints( | |
AnniversaryCalendar(Month(1), Year(1)), # AnniversaryCalendar | |
Date(2012, 5, 7), # anniv_date | |
Date(2013, 3, 1), # termination_date | |
Date(2013, 1, 1), # study_start | |
Date(2014, 3, 10) # study_end | |
) == [Date(2013, 1, 1), Date(2013, 1, 7), Date(2013, 2, 7), Date(2013, 3, 1)] | |
# termination_date > study_end | |
@assert create_partition_endpoints( | |
AnniversaryCalendar(Year(1), Month(1)), # AnniversaryCalendar | |
Date(2012, 2, 10), # anniv_date | |
Date(2016, 4, 4), # termination_date | |
Date(2013, 2, 4), # study_start | |
Date(2013, 4, 1) # study_end | |
) == [Date(2013, 2, 4), Date(2013, 2, 10), Date(2013, 3, 1), Date(2013, 4, 1)] | |
end | |
# ╔═╡ 00000000-0000-0000-0000-000000000001 | |
PLUTO_PROJECT_TOML_CONTENTS = """ | |
[deps] | |
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" | |
""" | |
# ╔═╡ 00000000-0000-0000-0000-000000000002 | |
PLUTO_MANIFEST_TOML_CONTENTS = """ | |
# This file is machine-generated - editing it directly is not advised | |
julia_version = "1.7.3" | |
manifest_format = "2.0" | |
[[deps.Dates]] | |
deps = ["Printf"] | |
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" | |
[[deps.Printf]] | |
deps = ["Unicode"] | |
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" | |
[[deps.Unicode]] | |
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" | |
""" | |
# ╔═╡ Cell order: | |
# ╠═6d618467-eed2-4851-961e-e45ed4a455d0 | |
# ╠═fb2b4952-3a91-11ed-116b-db769de7e1cc | |
# ╠═2a8585fb-c4f8-4635-a999-963f442cc997 | |
# ╠═48378996-32d7-45a8-b11f-616903d859e1 | |
# ╠═a42f02bd-e33a-406e-b4c1-13b51e39b99c | |
# ╠═66f45298-6d5e-48e8-81fb-4b77deb85836 | |
# ╠═df60e747-e48f-4572-b699-14bba7a156f3 | |
# ╠═76aa4c7f-a412-41d1-ae98-c10c14606b0a | |
# ╠═a176cd07-0a14-4916-95f4-bdc77be1a1a9 | |
# ╟─00000000-0000-0000-0000-000000000001 | |
# ╟─00000000-0000-0000-0000-000000000002 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment