Skip to content

Time

Helper functions for handling timeseries in Pyrenew

Days of the week in pyrenew are 0-indexed and follow ISO standards, so 0 is Monday at 6 is Sunday.

daily_to_mmwr_epiweekly

daily_to_mmwr_epiweekly(
    daily_values: ArrayLike, input_data_first_dow: int = 6
) -> ArrayLike

Aggregate daily values to weekly values using pyrenew.time.daily_to_weekly with MMWR epidemiological weeks (begin on Sundays, end on Saturdays).

Parameters:

Name Type Description Default
daily_values ArrayLike

Daily timeseries values.

required
input_data_first_dow int

First day of the week in the input timeseries daily_values. An integer between 0 and 6, inclusive (0 for Monday, 1 for Tuesday, ..., 6 for Sunday). If input_data_first_dow is not the MMWR epiweek start day (6, Sunday), the incomplete first week is ignored and weekly values starting from the second week are returned. Defaults to 6 (Sunday).

6

Returns:

Type Description
ArrayLike

Data converted to epiweekly values.

Source code in pyrenew/time.py
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
def daily_to_mmwr_epiweekly(
    daily_values: ArrayLike,
    input_data_first_dow: int = 6,
) -> ArrayLike:
    """
    Aggregate daily values to weekly values
    using [`pyrenew.time.daily_to_weekly`][] with
    MMWR epidemiological weeks (begin on Sundays,
    end on Saturdays).

    Parameters
    ----------
    daily_values
        Daily timeseries values.
    input_data_first_dow
        First day of the week in the input timeseries `daily_values`.
        An integer between 0 and 6, inclusive (0 for Monday, 1 for
        Tuesday, ..., 6 for Sunday).
        If `input_data_first_dow` is _not_ the MMWR epiweek start day
        (6, Sunday), the incomplete first week is ignored and
        weekly values starting from the second week are returned.
        Defaults to 6 (Sunday).

    Returns
    -------
    ArrayLike
        Data converted to epiweekly values.
    """
    return daily_to_weekly(daily_values, input_data_first_dow, week_start_dow=6)

daily_to_weekly

daily_to_weekly(
    daily_values: ArrayLike,
    input_data_first_dow: int = 0,
    week_start_dow: int = 0,
) -> ArrayLike

Aggregate daily values (e.g. incident hospital admissions) to weekly total values.

Parameters:

Name Type Description Default
daily_values ArrayLike

Daily timeseries values (e.g. incident infections or incident ed visits).

required
input_data_first_dow int

First day of the week in the input timeseries daily_values. An integer between 0 and 6, inclusive (0 for Monday, 1 for Tuesday, ..., 6 for Sunday). If input_data_first_dow does not match week_start_dow, the incomplete first week is ignored and weekly values starting from the second week are returned. Defaults to 0.

0
week_start_dow int

Day of the week on which weeks are considered to start in the output timeseries of weekly values (e.g. ISO weeks start on Mondays and end on Sundays; MMWR epiweeks start on Sundays and end on Saturdays). An integer between 0 and 6, inclusive (0 for Monday, 1 for Tuesday, ..., 6 for Sunday). Default 0 (i.e. ISO weeks, starting on Mondays).

0

Returns:

Type Description
ArrayLike

Data converted to weekly values starting with the first full week available.

Raises:

Type Description
ValueError

If the specified days of the week fail validation.

Notes

This is not a simple inverse of pyrenew.time.weekly_to_daily. This function aggregates (by summing) daily values to create a timeseries of weekly total values. pyrenew.time.weekly_to_daily broadcasts a single shared value for a given week as the (repeated) daily value for each day of that week.

Source code in pyrenew/time.py
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
def daily_to_weekly(
    daily_values: ArrayLike,
    input_data_first_dow: int = 0,
    week_start_dow: int = 0,
) -> ArrayLike:
    """
    Aggregate daily values (e.g.
    incident hospital admissions)
    to weekly total values.

    Parameters
    ----------
    daily_values
        Daily timeseries values (e.g. incident infections or
        incident ed visits).
    input_data_first_dow
        First day of the week in the input timeseries `daily_values`.
        An integer between 0 and 6, inclusive (0 for Monday, 1 for Tuesday,
        ..., 6 for Sunday).
        If `input_data_first_dow` does not match `week_start_dow`, the
        incomplete first week is ignored and weekly values starting
        from the second week are returned. Defaults to 0.
    week_start_dow
        Day of the week on which weeks are considered to
        start in the output timeseries of weekly values
        (e.g. ISO weeks start on Mondays and end on Sundays;
        MMWR epiweeks start on Sundays and end on Saturdays).
        An integer between 0 and 6, inclusive (0 for Monday,
        1 for Tuesday, ..., 6 for Sunday).
        Default 0 (i.e. ISO weeks, starting on Mondays).

    Returns
    -------
    ArrayLike
        Data converted to weekly values starting
        with the first full week available.

    Raises
    ------
    ValueError
        If the specified days of the week fail validation.

    Notes
    -----
    This is _not_ a simple inverse of [`pyrenew.time.weekly_to_daily`][].
    This function aggregates (by summing) daily values to
    create a timeseries of weekly total values.
    [`pyrenew.time.weekly_to_daily`][] broadcasts a _single shared value_
    for a given week as the (repeated) daily value for each day
    of that week.
    """

    validate_dow(input_data_first_dow, "input_data_first_dow")
    validate_dow(week_start_dow, "week_start_dow")

    offset = (week_start_dow - input_data_first_dow) % 7
    daily_values = daily_values[offset:]

    if daily_values.shape[0] < 7:
        raise ValueError("No complete weekly values available")

    n_weeks = daily_values.shape[0] // 7
    trimmed = daily_values[: n_weeks * 7]
    weekly_values = trimmed.reshape(n_weeks, 7, *daily_values.shape[1:]).sum(axis=1)

    return weekly_values

mmwr_epiweekly_to_daily

mmwr_epiweekly_to_daily(
    weekly_values: ArrayLike, output_data_first_dow: int = 6
) -> ArrayLike

Convert an MMWR epiweekly timeseries to a daily timeseries using pyrenew.time.weekly_to_daily.

Parameters:

Name Type Description Default
weekly_values ArrayLike

Timeseries of weekly values, where (discrete) time is the first dimension of the array (following Pyrenew convention).

required
output_data_first_dow int

Day of the week on which to start the output timeseries. An integer between 0 and 6, inclusive (0 for Monday, 1 for Tuesday, ..., 6 for Sunday). Defaults to the MMWR epiweek start day (6, Sunday). If output_data_first_dow is not equal to 6 (Sunday, the start of an MMWR epiweek), the first weekly value will be partial (i.e. represented by between 1 and 6 entries in the output timeseries) and all subsequent weeks will be complete (represented by 7 values each).

6

Returns:

Type Description
ArrayLike

The daily timeseries.

Source code in pyrenew/time.py
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
def mmwr_epiweekly_to_daily(
    weekly_values: ArrayLike,
    output_data_first_dow: int = 6,
) -> ArrayLike:
    """
    Convert an MMWR epiweekly timeseries to a daily
    timeseries using [`pyrenew.time.weekly_to_daily`][].

    Parameters
    ----------
    weekly_values
        Timeseries of weekly values, where
        (discrete) time is the first dimension of
        the array (following Pyrenew convention).

    output_data_first_dow
        Day of the week on which to start the output timeseries.
        An integer between 0 and 6, inclusive (0 for Monday,
        1 for Tuesday, ..., 6 for Sunday). Defaults to the MMWR
        epiweek start day (6, Sunday).
        If `output_data_first_dow` is _not_ equal to 6 (Sunday,
        the start of an MMWR epiweek), the first weekly value will
        be partial (i.e. represented by between 1 and 6 entries
        in the output timeseries) and all subsequent weeks will be
        complete (represented by 7 values each).

    Returns
    -------
    ArrayLike
        The daily timeseries.
    """
    return weekly_to_daily(
        weekly_values,
        output_data_first_dow=output_data_first_dow,
        week_start_dow=6,
    )

validate_dow

validate_dow(day_of_week: int, variable_name: str) -> None

Confirm that an integer is a valid Pyrenew day of the week index, with informative error messages on failure.

Parameters:

Name Type Description Default
day_of_week int

Integer to validate.

required
variable_name str

Name of the variable being validated, to increase the informativeness of the error message.

required

Returns:

Type Description
None

If validation passes.

Raises:

Type Description
ValueError

If validation fails.

Source code in pyrenew/time.py
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def validate_dow(day_of_week: int, variable_name: str) -> None:
    """
    Confirm that an integer is a valid Pyrenew day of the week
    index, with informative error messages on failure.

    Parameters
    ----------
    day_of_week
        Integer to validate.

    variable_name
        Name of the variable being validated, to increase the informativeness of the error message.

    Returns
    -------
    None
        If validation passes.

    Raises
    ------
    ValueError
        If validation fails.
    """
    if not isinstance(day_of_week, int):
        raise ValueError(
            "Day-of-week indices must be integers "
            "between 0 and 6, inclusive. "
            f"Got {day_of_week} for {variable_name}, "
            "which is a "
            f"{type(day_of_week)}"
        )
    if day_of_week < 0 or day_of_week > 6:
        raise ValueError(
            "Day-of-week indices must be a integers "
            "between 0 and 6, inclusive. "
            f"Got {day_of_week} for {variable_name}."
        )
    return None

weekly_to_daily

weekly_to_daily(
    weekly_values: ArrayLike,
    week_start_dow: int = 0,
    output_data_first_dow: int = None,
) -> ArrayLike

Broadcast a weekly timeseries to a daily timeseries. The value for the week will be used as the value each day in that week, via jax.numpy.repeat.

Parameters:

Name Type Description Default
weekly_values ArrayLike

Timeseries of weekly values, where (discrete) time is the first dimension of the array (following Pyrenew convention).

required
week_start_dow int

Day of the week on which weeks are considered to start in the input weekly_values timeseries (e.g. ISO weeks start on Mondays and end on Sundays; MMWR epiweeks start on Sundays and end on Saturdays). An integer between 0 and 6, inclusive (0 for Monday, 1 for Tuesday, ..., 6 for Sunday). Default 0 (i.e. ISO weeks, starting on Mondays).

0
output_data_first_dow int

Day of the week on which to start the output timeseries. An integer between 0 and 6, inclusive (0 for Monday, 1 for Tuesday, ..., 6 for Sunday). Defaults to the week start date as specified by week_start_dow. If output_data_first_dow is not equal to week_start_dow, the first weekly value will be partial (i.e. represented by between 1 and 6 entries in the output timeseries) and all subsequent weeks will be complete (represented by 7 values each).

None

Returns:

Type Description
ArrayLike

The daily timeseries.

Raises:

Type Description
ValueError

If the specified days of the week fail validation.

Notes

This is not a simple inverse of pyrenew.time.daily_to_weekly. pyrenew.time.daily_to_weekly aggregates (by summing) daily values to create a timeseries of weekly total values. This function broadcasts a single shared value for a given week as the (repeated) daily value for each day of that week.

Source code in pyrenew/time.py
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
def weekly_to_daily(
    weekly_values: ArrayLike,
    week_start_dow: int = 0,
    output_data_first_dow: int = None,
) -> ArrayLike:
    """
    Broadcast a weekly timeseries to a daily
    timeseries. The value for the week will be used
    as the value each day in that week, via
    [`jax.numpy.repeat`][].

    Parameters
    ----------
    weekly_values
        Timeseries of weekly values, where
        (discrete) time is the first dimension of
        the array (following Pyrenew convention).

    week_start_dow
        Day of the week on which weeks are considered to
        start in the input `weekly_values` timeseries
        (e.g. ISO weeks start on Mondays and end on Sundays;
        MMWR epiweeks start on Sundays and end on Saturdays).
        An integer between 0 and 6, inclusive (0 for Monday,
        1 for Tuesday, ..., 6 for Sunday).
        Default 0 (i.e. ISO weeks, starting on Mondays).

    output_data_first_dow
        Day of the week on which to start the output timeseries.
        An integer between 0 and 6, inclusive (0 for Monday,
        1 for Tuesday, ..., 6 for Sunday). Defaults to the week
        start date as specified by `week_start_dow`.
        If `output_data_first_dow` is _not_ equal to `week_start_dow`,
        the first weekly value will be partial (i.e. represented by
        between 1 and 6 entries in the output timeseries) and
        all subsequent weeks will be complete (represented by 7
        values each).

    Returns
    -------
    ArrayLike
        The daily timeseries.

    Raises
    ------
    ValueError
        If the specified days of the week fail validation.

    Notes
    -----
    This is _not_ a simple inverse of [`pyrenew.time.daily_to_weekly`][].
    [`pyrenew.time.daily_to_weekly`][] aggregates (by summing) daily values to
    create a timeseries of weekly total values.
    This function broadcasts a _single shared value_
    for a given week as the (repeated) daily value for each day
    of that week.
    """

    validate_dow(week_start_dow, "week_start_dow")
    if output_data_first_dow is None:
        output_data_first_dow = week_start_dow
    validate_dow(output_data_first_dow, "output_data_first_dow")

    offset = (output_data_first_dow - week_start_dow) % 7
    return jnp.repeat(
        weekly_values,
        repeats=7,
        axis=0,
    )[offset:]