Skip to content

Commit 124a3fd

Browse files
day zero of graph is now the user inputted date_first_hospitalized
1 parent e9b4fbf commit 124a3fd

File tree

5 files changed

+61
-43
lines changed

5 files changed

+61
-43
lines changed

src/penn_chime/charts.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def new_admissions_chart(
2626

2727
tooltip_dict = {False: "day", True: "date:T"}
2828
if as_date:
29-
projection_admits = add_date_column(projection_admits)
29+
projection_admits = add_date_column(projection_admits, parameters.date_first_hospitalized)
3030
x_kwargs = {"shorthand": "date:T", "title": "Date", "axis": alt.Axis(format=(DATE_FORMAT))}
3131
else:
3232
x_kwargs = {"shorthand": "day", "title": "Days from today"}
@@ -66,7 +66,7 @@ def admitted_patients_chart(
6666
max_y_axis = parameters.max_y_axis
6767
as_date = parameters.as_date
6868
if as_date:
69-
census = add_date_column(census)
69+
census = add_date_column(census, parameters.date_first_hospitalized)
7070
x_kwargs = {"shorthand": "date:T", "title": "Date", "axis": alt.Axis(format=(DATE_FORMAT))}
7171
idx = "date:T"
7272
else:
@@ -113,7 +113,7 @@ def additional_projections_chart(
113113
max_y_axis = parameters.max_y_axis
114114

115115
if as_date:
116-
dat = add_date_column(dat)
116+
dat = add_date_column(dat, parameters.date_first_hospitalized)
117117
x_kwargs = {"shorthand": "date:T", "title": "Date", "axis": alt.Axis(format=(DATE_FORMAT))}
118118
else:
119119
x_kwargs = {"shorthand": "day", "title": "Days from today"}

src/penn_chime/models.py

Lines changed: 40 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ def __init__(self, p: Parameters):
7878
p.n_days,
7979
)
8080
dispositions_df = build_dispositions_df(raw_df, rates, p.market_share)
81-
admits_df = build_admits_df(dispositions_df)
82-
census_df = build_census_df(admits_df, lengths_of_stay)
81+
admits_df = build_admits_df(dispositions_df, p.n_days_since_first_hospitalized)
82+
census_df = build_census_df(admits_df, lengths_of_stay, p.n_days_since_first_hospitalized)
8383

8484
self.susceptible = susceptible
8585
self.infected = infected
@@ -112,8 +112,8 @@ def __init__(self, p: Parameters):
112112
argmin_dt = dt
113113
self.census_df = censes[dt]
114114
p.doubling_time = argmin_dt
115-
#
116-
# update all state dependent on doubling time.
115+
116+
# update all state that is dependent on doubling time.
117117
intrinsic_growth_rate = self._intrinsic_growth_rate(p.doubling_time)
118118
gamma = 1 / recovery_days
119119
beta = self._beta(intrinsic_growth_rate, gamma, susceptible, p.relative_contact_rate)
@@ -129,8 +129,8 @@ def __init__(self, p: Parameters):
129129
p.n_days
130130
)
131131
dispositions_df = build_dispositions_df(raw_df, rates, p.market_share)
132-
admits_df = build_admits_df(dispositions_df)
133-
census_df = build_census_df(admits_df, lengths_of_stay)
132+
admits_df = build_admits_df(dispositions_df, p.n_days_since_first_hospitalized)
133+
census_df = build_census_df(admits_df, lengths_of_stay, p.n_days_since_first_hospitalized)
134134

135135
self.intrinsic_growth_rate = intrinsic_growth_rate
136136
self.gamma = gamma
@@ -167,9 +167,21 @@ def run_projection(self, p: Parameters, doubling_time: float) -> pd.DataFrame:
167167

168168
raw_df = sim_sir_df(S,I,R,beta,gamma,n_days)
169169

170-
dispositions_df = build_dispositions_df(raw_df, self._rates, p.market_share)
171-
admits_df = build_admits_df(dispositions_df)
172-
census_df = build_census_df(admits_df, self._lengths_of_stay)
170+
# dispositions_df = build_dispositions_df(raw_df, self._rates, p.market_share)
171+
172+
i_dict_v = get_dispositions(raw_df.infected, self._rates, market_share)
173+
r_dict_v = get_dispositions(raw_df.recovered, self._rates, market_share)
174+
175+
dispositions = {
176+
key: value + r_dict_v[key]
177+
for key, value in i_dict_v.items()
178+
}
179+
180+
dispositions_df = pd.DataFrame(dispositions)
181+
dispositions_df = dispositions_df.assign(day=dispositions_df.index)
182+
183+
admits_df = build_admits_df(dispositions_df, p.n_days_since_first_hospitalized)
184+
census_df = build_census_df(admits_df, self._lengths_of_stay, p.n_days_since_first_hospitalized)
173185
return census_df
174186

175187
def loss_dt(self, p: Parameters) -> float:
@@ -245,6 +257,19 @@ def sim_sir_df(
245257
columns=("day", "susceptible", "infected", "recovered"),
246258
)
247259

260+
261+
def get_dispositions(
262+
patients: np.ndarray,
263+
rates: Dict[str, float],
264+
market_share: float,
265+
) -> Dict[str, np.ndarray]:
266+
"""Get dispositions of patients adjusted by rate and market_share."""
267+
return {
268+
key: patients * rate * market_share
269+
for key, rate in rates.items()
270+
}
271+
272+
248273
def build_dispositions_df(
249274
sim_sir_df: pd.DataFrame,
250275
rates: Dict[str, float],
@@ -261,16 +286,20 @@ def build_dispositions_df(
261286
})
262287

263288

264-
def build_admits_df(dispositions_df: pd.DataFrame) -> pd.DataFrame:
289+
def build_admits_df(dispositions_df: pd.DataFrame, n_days_since_first_hospitalized: int) -> pd.DataFrame:
265290
"""Build admits dataframe from dispositions."""
266291
admits_df = dispositions_df.iloc[:-1, :] - dispositions_df.shift(1)
267-
admits_df.day = dispositions_df.day
292+
if n_days_since_first_hospitalized is not None:
293+
admits_df.day = dispositions_df.day - n_days_since_first_hospitalized
294+
else:
295+
admits_df.day = dispositions_df.day
268296
return admits_df
269297

270298

271299
def build_census_df(
272300
admits_df: pd.DataFrame,
273301
lengths_of_stay: Dict[str, int],
302+
n_days_since_first_hospitalized: int
274303
) -> pd.DataFrame:
275304
"""Average Length of Stay for each disposition of COVID-19 case (total guesses)"""
276305
return pd.DataFrame({
@@ -285,30 +314,6 @@ def build_census_df(
285314
})
286315

287316

288-
############################
289-
## ARGMIN DOUBLING_TIME ##
290-
############################
291-
292-
293-
def observed_predicted_loss(self, doubling_time: float, p: Parameters) -> float:
294-
"""Squared error between predicted value and actual value
295-
296-
Won't be run if n_days_since_first_hospitalized is None
297-
"""
298-
census_df = self.run_projection(p, dt=doubling_time)
299-
## get the predicted number hospitalized today
300-
pred_current_hospitalized = self.census_df['hospitalized'].loc[p.n_days_since_first_hospitalized]
301-
302-
## compare against the actual (user inputed) number
303-
## squared difference is the loss to be optimized
304-
return (p.current_hospitalized - pred_current_hospitalized)**2
305-
306-
def argmin_dt(self, doubling_times: np.ndarray, p: Parameters) -> float:
307-
"""Argmin of the loss function with respect to doubling time."""
308-
loss = np.array([self.observed_predicted_loss(dt, p) for dt in doubling_times])
309-
fitted_doubling_time = doubling_times[loss.argmin()]
310-
return fitted_doubling_time
311-
312317

313318
#############
314319
## UTILS ##

src/penn_chime/parameters.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,10 @@ def __init__(
4949
self.n_days = n_days
5050
self.recovery_days = recovery_days
5151
if date_first_hospitalized:
52+
self.date_first_hospitalized = date_first_hospitalized # needed for utils.add_date_column
5253
self.n_days_since_first_hospitalized = (date.today() - date_first_hospitalized).days
5354
else:
55+
self.date_first_hospitalized = None # needed for utils.add_date_column
5456
self.n_days_since_first_hospitalized = None
5557

5658
self.labels = {

src/penn_chime/presentation.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,12 @@ def show_additional_projections(
464464

465465

466466
def draw_projected_admissions_table(
467-
st, projection_admits: pd.DataFrame, labels, day_range, as_date: bool = False
467+
st,
468+
projection_admits: pd.DataFrame,
469+
labels,
470+
day_range,
471+
date_first_hospitalized: Optional[date] = None,
472+
as_date: bool = False
468473
):
469474
admits_table = projection_admits[np.mod(projection_admits.index, day_range) == 0].copy()
470475
admits_table["day"] = admits_table.index
@@ -473,7 +478,7 @@ def draw_projected_admissions_table(
473478

474479
if as_date:
475480
admits_table = add_date_column(
476-
admits_table, drop_day_column=True, date_format=DATE_FORMAT
481+
admits_table, date_first_hospitalized, drop_day_column=True, date_format=DATE_FORMAT
477482
)
478483
admits_table.rename(labels)
479484
st.table(admits_table)

src/penn_chime/utils.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Utils."""
22

33
from collections import namedtuple
4-
from datetime import datetime, timedelta
4+
from datetime import datetime, timedelta, date
55
from typing import Optional
66
from base64 import b64encode
77

@@ -36,7 +36,7 @@
3636

3737

3838
def add_date_column(
39-
df: pd.DataFrame, drop_day_column: bool = False, date_format: Optional[str] = None,
39+
df: pd.DataFrame, date_first_hospitalized: Optional[date], drop_day_column: bool = False, date_format: Optional[str] = None,
4040
) -> pd.DataFrame:
4141
"""Copies input data frame and converts "day" column to "date" column
4242
@@ -65,7 +65,13 @@ def add_date_column(
6565

6666
# Allocate (day) continous range for dates
6767
n_days = int(df.day.max())
68-
start = datetime.now()
68+
69+
today = date.today()
70+
if date_first_hospitalized:
71+
delta = today - date_first_hospitalized
72+
start = today - delta
73+
else:
74+
start = today
6975
end = start + timedelta(days=n_days + 1)
7076
# And pick dates present in frame
7177
dates = pd.date_range(start=start, end=end, freq="D")[df.day.tolist()]

0 commit comments

Comments
 (0)