Open
Description
Yesterday I created the following function (for vs):
def monthly_to_quarterly(axis_or_group, first_year=None, last_year=None):
"""
Produces a tuple of groups to aggregate an array with a monthly axis to a quarterly axis
The monthly axis must have labels using the "{YYYY}M{M}" format
(M goes from 1 to 12, not 01 to 12).
The quarterly axis will have labels using the "{YYYY}Q{Q}" format.
Parameters
----------
axis_or_group : Axis or Group
Original monthly axis (or selection on it).
first_year : int, optional
First year taken into account. Defaults to the first year present on the axis.
last_year : int, optional
Last year taken into account. Defaults to the last year present on the axis.
Returns
-------
tuple
Groups which can be used to aggregate an array with the original monthly axis
into a quarterly axis
Examples
--------
>>> time = Axis(f"2024M3..2024M10", 'time')
>>> arr = ndtest(time)
>>> arr
time 2024M3 2024M4 2024M5 2024M6 2024M7 2024M8 2024M9 2024M10
0 1 2 3 4 5 6 7
>>> quarter_months = monthly_to_quarterly(time)
>>> quarter_months
(time['2024M3'] >> '2024Q1',
time['2024M4', '2024M5', '2024M6'] >> '2024Q2',
time['2024M7', '2024M8', '2024M9'] >> '2024Q3',
time['2024M10'] >> '2024Q4')
>>> arr.sum(quarter_months)
time 2024Q1 2024Q2 2024Q3 2024Q4
0 6 15 7
"""
labels = axis_or_group.labels if isinstance(axis_or_group, Axis) else axis_or_group.eval()
axis = axis_or_group if isinstance(axis_or_group, Axis) else axis_or_group.axis
group = axis[:] if isinstance(axis_or_group, Axis) else axis_or_group
if first_year is None or last_year is None:
years = set(int(label[:4]) for label in labels)
if first_year is None:
first_year = min(years)
if last_year is None:
last_year = max(years)
quarters = []
for y in range(first_year, last_year + 1):
for q in range(1, 5):
quarter_months = f"{y}M{(q - 1) * 3 + 1}..{y}M{(q - 1) * 3 + 3}"
# support axes/selections which do not start at the first month
quarter_months_in_selection = group.intersection(quarter_months)
# avoid "empty" quarters, if the axis has no month for some quarters
if quarter_months_in_selection:
# transform the LSet returned by .intersection() to a normal LGroup
# this step is not strictly necessary but produces nicer groups
quarter_months_in_selection = axis[quarter_months_in_selection.eval()]
quarters.append(quarter_months_in_selection >> f'{y}Q{q}')
return tuple(quarters)
I think we should generalize this further and add something which can do this kind of conversion in LArray.
A few references:
- this is very similar to iode's high_to_low and low_to_high
- Pandas asfreq and resample