Combination Generators¶
CombinationGenerator
¶
Bases: Protocol
Protocol for generating and counting combinations of candidate slices.
This protocol defines the interface for combination generators used in Generate-and-Test workflows. Implementations determine which k-element subsets of candidate slices should be evaluated.
Attributes:
| Name | Type | Description |
|---|---|---|
k |
int
|
Number of elements in each combination to generate. |
Source code in energy_repset/combi_gens/combination_generator.py
9 10 11 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 50 51 52 53 54 | |
generate
¶
generate(unique_slices: Sequence[Hashable]) -> Iterator[SliceCombination]
Generate k-combinations from the candidate slices.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unique_slices
|
Sequence[Hashable]
|
Sequence of candidate slice labels. |
required |
Yields:
| Type | Description |
|---|---|
SliceCombination
|
Tuples of length k representing candidate selections. |
Source code in energy_repset/combi_gens/combination_generator.py
22 23 24 25 26 27 28 29 30 31 | |
count
¶
count(unique_slices: Sequence[Hashable]) -> int
Count the total number of combinations that will be generated.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unique_slices
|
Sequence[Hashable]
|
Sequence of candidate slice labels. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Total number of k-combinations. |
Source code in energy_repset/combi_gens/combination_generator.py
33 34 35 36 37 38 39 40 41 42 | |
combination_is_valid
¶
combination_is_valid(combination: SliceCombination, unique_slices: Sequence[Hashable]) -> bool
Check if a combination is valid according to generator constraints.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
combination
|
SliceCombination
|
Tuple of slice labels to validate. |
required |
unique_slices
|
Sequence[Hashable]
|
Sequence of candidate slice labels. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the combination satisfies the generator's constraints. |
Source code in energy_repset/combi_gens/combination_generator.py
44 45 46 47 48 49 50 51 52 53 54 | |
ExhaustiveCombiGen
¶
Bases: CombinationGenerator
Generate all k-combinations of the candidate slices.
This generator produces every possible k-element subset using itertools.combinations. It is suitable for small problem sizes where the total number of combinations (n choose k) is computationally feasible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
k
|
int
|
Number of elements in each combination. |
required |
Attributes:
| Name | Type | Description |
|---|---|---|
k |
Number of elements per combination. |
Note
The count is computed via binomial coefficient (n choose k) and matches the number of yielded combinations exactly.
Examples:
Generate all 3-month combinations from a year:
>>> from energy_repset.combi_gens import ExhaustiveCombiGen
>>> import pandas as pd
>>>
>>> months = [pd.Period('2024-01', 'M'), pd.Period('2024-02', 'M'),
... pd.Period('2024-03', 'M'), pd.Period('2024-04', 'M')]
>>> generator = ExhaustiveCombiGen(k=3)
>>> generator.count(months) # 4 choose 3
4
>>> list(generator.generate(months))
[(Period('2024-01', 'M'), Period('2024-02', 'M'), Period('2024-03', 'M')),
(Period('2024-01', 'M'), Period('2024-02', 'M'), Period('2024-04', 'M')),
(Period('2024-01', 'M'), Period('2024-03', 'M'), Period('2024-04', 'M')),
(Period('2024-02', 'M'), Period('2024-03', 'M'), Period('2024-04', 'M'))]
Source code in energy_repset/combi_gens/simple_exhaustive.py
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 50 51 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 | |
__init__
¶
__init__(k: int) -> None
Initialize exhaustive generator with target combination size.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
k
|
int
|
Number of elements in each combination. |
required |
Source code in energy_repset/combi_gens/simple_exhaustive.py
48 49 50 51 52 53 54 | |
generate
¶
generate(unique_slices: Sequence[Hashable]) -> Iterator[SliceCombination]
Generate all k-combinations using itertools.combinations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unique_slices
|
Sequence[Hashable]
|
Sequence of candidate slice labels. |
required |
Yields:
| Type | Description |
|---|---|
SliceCombination
|
All possible k-element tuples from unique_slices. |
Source code in energy_repset/combi_gens/simple_exhaustive.py
56 57 58 59 60 61 62 63 64 65 | |
count
¶
count(unique_slices: Sequence[Hashable]) -> int
Count total combinations using binomial coefficient.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unique_slices
|
Sequence[Hashable]
|
Sequence of candidate slice labels. |
required |
Returns:
| Type | Description |
|---|---|
int
|
n choose k, where n is the number of unique slices. |
Source code in energy_repset/combi_gens/simple_exhaustive.py
67 68 69 70 71 72 73 74 75 76 | |
combination_is_valid
¶
combination_is_valid(combination: SliceCombination, unique_slices: Sequence[Hashable]) -> bool
Check if combination has exactly k elements from unique_slices.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
combination
|
SliceCombination
|
Tuple of slice labels to validate. |
required |
unique_slices
|
Sequence[Hashable]
|
Sequence of candidate slice labels. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if combination has k elements all in unique_slices. |
Source code in energy_repset/combi_gens/simple_exhaustive.py
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | |
GroupQuotaCombiGen
¶
Bases: CombinationGenerator
Generate combinations that respect exact quotas per group.
This generator enforces that selections contain a specific number of elements from each group. It is useful for ensuring balanced representation across categories (e.g., seasons, must-have periods, etc.).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
k
|
int
|
Total number of elements in each combination. Must equal sum of group quotas. |
required |
slice_to_group_mapping
|
dict[Hashable, Hashable]
|
Mapping from each candidate slice to its group label. |
required |
group_quota
|
dict[Hashable, int]
|
Mapping from group label to the required count in the selection. |
required |
Attributes:
| Name | Type | Description |
|---|---|---|
k |
Number of elements per combination. |
|
group_of |
Mapping from slice to group. |
|
group_quota |
Required count per group. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If sum of group quotas does not equal k. |
Note
Use this to enforce constraints like "exactly one month per season" or "2 must-have periods plus 2 optional periods".
Examples:
Example 1 - Seasonal constraints (one month per season):
>>> from energy_repset.combi_gens import GroupQuotaCombiGen
>>> import pandas as pd
>>>
>>> # Define months and their seasons
>>> months = [pd.Period(f'2024-{i:02d}', 'M') for i in range(1, 13)]
>>> season_map = {}
>>> for month in months:
... if month.month in [12, 1, 2]: season_map[month] = 'winter'
... elif month.month in [3, 4, 5]: season_map[month] = 'spring'
... elif month.month in [6, 7, 8]: season_map[month] = 'summer'
... else: season_map[month] = 'fall'
>>>
>>> # Select 4 months, one per season
>>> generator = GroupQuotaCombiGen(
... k=4,
... slice_to_group_mapping=season_map,
... group_quota={'winter': 1, 'spring': 1, 'summer': 1, 'fall': 1}
... )
>>> generator.count(months) # 3 * 3 * 3 * 3 = 81 combinations
81
Example 2 - Optional and must-have categories:
>>> # Force specific periods to be included
>>> months = [pd.Period(f'2024-{i:02d}', 'M') for i in range(1, 13)]
>>> group_mapping = {p: 'optional' for p in months}
>>> group_mapping[pd.Period('2024-01', 'M')] = 'must'
>>> group_mapping[pd.Period('2024-12', 'M')] = 'must'
>>>
>>> # Select 4 total: 2 must-have + 2 optional
>>> generator = GroupQuotaCombiGen(
... k=4,
... slice_to_group_mapping=group_mapping,
... group_quota={'optional': 2, 'must': 2}
... )
>>> # All combinations will include Jan and Dec plus 2 from the other 10
>>> generator.count(months) # 1 * 45 = 45 combinations
45
Source code in energy_repset/combi_gens/simple_group_quota.py
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 50 51 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 118 119 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 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | |
__init__
¶
__init__(k: int, slice_to_group_mapping: dict[Hashable, Hashable], group_quota: dict[Hashable, int]) -> None
Initialize generator with group quotas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
k
|
int
|
Total number of elements in each combination. |
required |
slice_to_group_mapping
|
dict[Hashable, Hashable]
|
Mapping from slice to its group label. |
required |
group_quota
|
dict[Hashable, int]
|
Required count per group. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If sum of group quotas does not equal k. |
Source code in energy_repset/combi_gens/simple_group_quota.py
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | |
generate
¶
generate(unique_slices: Sequence[Hashable]) -> Iterator[SliceCombination]
Generate combinations respecting group quotas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unique_slices
|
Sequence[Hashable]
|
Sequence of candidate slice labels. |
required |
Yields:
| Type | Description |
|---|---|
SliceCombination
|
Tuples of length k where each group contributes exactly its quota. |
Source code in energy_repset/combi_gens/simple_group_quota.py
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | |
count
¶
count(unique_slices: Sequence[Hashable]) -> int
Count total combinations respecting group quotas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unique_slices
|
Sequence[Hashable]
|
Sequence of candidate slice labels. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Product of binomial coefficients across all groups. For each group |
int
|
with n members and quota q, contributes C(n, q) to the product. |
Source code in energy_repset/combi_gens/simple_group_quota.py
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | |
combination_is_valid
¶
combination_is_valid(combination: SliceCombination, unique_slices: Sequence[Hashable]) -> bool
Check if combination satisfies group quotas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
combination
|
SliceCombination
|
Tuple of slice labels to validate. |
required |
unique_slices
|
Sequence[Hashable]
|
Sequence of candidate slice labels. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if combination has exactly k elements with each group contributing |
bool
|
its required quota. |
Source code in energy_repset/combi_gens/simple_group_quota.py
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | |
ExhaustiveHierarchicalCombiGen
¶
Bases: CombinationGenerator
Generate combinations where child slices are selected in complete parent groups.
This generator enforces hierarchical selection: child slices (e.g., days) can only be selected as complete parent groups (e.g., months). It enables high-resolution features (e.g. per-day) while enforcing structural constraints at the parent level (e.g. months).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
parent_k
|
int
|
Number of parent groups to select. |
required |
slice_to_parent_mapping
|
dict[Hashable, Hashable]
|
Mapping from each child slice to its parent group. Example: {Period('2024-01-01', 'D'): Period('2024-01', 'M'), ...} |
required |
Attributes:
| Name | Type | Description |
|---|---|---|
k |
Number of parent groups per combination (same as parent_k for protocol compliance). |
|
parent_k |
Number of parent groups per combination. |
|
slice_to_parent |
Child to parent mapping. |
Note
The generate() method yields flattened tuples of child slices, but internally
enforces parent-level constraints. Use the factory method from_slicers()
for automatic parent grouping based on TimeSlicer objects.
Examples:
Manual construction with custom grouping:
>>> from energy_repset.combi_gens import ExhaustiveHierarchicalCombiGen
>>> import pandas as pd
>>>
>>> # Define child-to-parent mapping
>>> slice_to_parent = {
... pd.Period('2024-01-01', 'D'): pd.Period('2024-01', 'M'),
... pd.Period('2024-01-02', 'D'): pd.Period('2024-01', 'M'),
... pd.Period('2024-02-01', 'D'): pd.Period('2024-02', 'M'),
... pd.Period('2024-02-02', 'D'): pd.Period('2024-02', 'M'),
... }
>>>
>>> # Select 2 months, but combinations contain days
>>> gen = ExhaustiveHierarchicalCombiGen(
... parent_k=2,
... slice_to_parent_mapping=slice_to_parent
... )
>>> gen.count(list(slice_to_parent.keys())) # C(2, 2) = 1
1
Using factory method with TimeSlicer:
>>> import pandas as pd
>>> from energy_repset.time_slicer import TimeSlicer
>>> from energy_repset.combi_gens import ExhaustiveHierarchicalCombiGen
>>>
>>> dates = pd.date_range('2024-01-01', periods=366, freq='D')
>>> child_slicer = TimeSlicer(unit='day')
>>> parent_slicer = TimeSlicer(unit='month')
>>>
>>> gen = ExhaustiveHierarchicalCombiGen.from_slicers(
... parent_k=3,
... dt_index=dates,
... child_slicer=child_slicer,
... parent_slicer=parent_slicer
... )
>>> unique_days = child_slicer.unique_slices(dates)
>>> gen.count(unique_days) # C(12, 3) = 220 combinations of months
220
Source code in energy_repset/combi_gens/hierarchical_exhaustive.py
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 50 51 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 118 119 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 149 150 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 | |
__init__
¶
__init__(parent_k: int, slice_to_parent_mapping: dict[Hashable, Hashable]) -> None
Initialize hierarchical generator with child-to-parent mapping.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
parent_k
|
int
|
Number of parent groups to select. |
required |
slice_to_parent_mapping
|
dict[Hashable, Hashable]
|
Dict mapping each child slice to its parent. |
required |
Source code in energy_repset/combi_gens/hierarchical_exhaustive.py
80 81 82 83 84 85 86 87 88 89 90 91 92 93 | |
from_slicers
classmethod
¶
from_slicers(parent_k: int, dt_index: DatetimeIndex, child_slicer: TimeSlicer, parent_slicer: TimeSlicer) -> ExhaustiveHierarchicalCombiGen
Factory method to create generator from child and parent TimeSlicer objects.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
parent_k
|
int
|
Number of parent groups to select. |
required |
dt_index
|
DatetimeIndex
|
DatetimeIndex of the time series data. |
required |
child_slicer
|
TimeSlicer
|
TimeSlicer defining child slice granularity (e.g., daily). |
required |
parent_slicer
|
TimeSlicer
|
TimeSlicer defining parent slice granularity (e.g., monthly). |
required |
Returns:
| Type | Description |
|---|---|
ExhaustiveHierarchicalCombiGen
|
ExhaustiveHierarchicalCombinationGenerator with auto-constructed mappings. |
Examples:
Select 4 months from a year of daily data:
>>> import pandas as pd
>>> from energy_repset.time_slicer import TimeSlicer
>>> from energy_repset.combi_gens import ExhaustiveHierarchicalCombiGen
>>>
>>> dates = pd.date_range('2024-01-01', periods=366, freq='D')
>>> child_slicer = TimeSlicer(unit='day')
>>> parent_slicer = TimeSlicer(unit='month')
>>>
>>> gen = ExhaustiveHierarchicalCombiGen.from_slicers(
... parent_k=4,
... dt_index=dates,
... child_slicer=child_slicer,
... parent_slicer=parent_slicer
... )
>>> gen.count(child_slicer.unique_slices(dates)) # C(12, 4) = 495
495
Source code in energy_repset/combi_gens/hierarchical_exhaustive.py
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | |
generate
¶
generate(unique_slices: Sequence[Hashable]) -> Iterator[SliceCombination]
Generate combinations of k parent groups, yielding flattened child slices.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unique_slices
|
Sequence[Hashable]
|
Sequence of child slice labels. |
required |
Yields:
| Type | Description |
|---|---|
SliceCombination
|
Tuples containing all child slices from k selected parent groups. |
Source code in energy_repset/combi_gens/hierarchical_exhaustive.py
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | |
count
¶
count(unique_slices: Sequence[Hashable]) -> int
Count total number of parent-level combinations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unique_slices
|
Sequence[Hashable]
|
Sequence of child slice labels. |
required |
Returns:
| Type | Description |
|---|---|
int
|
C(n_parents, parent_k) where n_parents is the number of unique parent groups. |
Source code in energy_repset/combi_gens/hierarchical_exhaustive.py
166 167 168 169 170 171 172 173 174 175 176 177 | |
combination_is_valid
¶
combination_is_valid(combination: SliceCombination, unique_slices: Sequence[Hashable]) -> bool
Check if combination represents exactly parent_k complete parent groups.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
combination
|
SliceCombination
|
Tuple of child slice labels to validate. |
required |
unique_slices
|
Sequence[Hashable]
|
Sequence of all valid child slice labels. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if combination contains all children from exactly parent_k parent groups. |
Source code in energy_repset/combi_gens/hierarchical_exhaustive.py
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 | |
GroupQuotaHierarchicalCombiGen
¶
Bases: CombinationGenerator
Generate combinations respecting quotas per parent-level group.
This generator combines hierarchical selection (child slices selected in complete parent groups) with group quotas (e.g., exactly 1 month per season). It enables high-resolution features (e.g. per-day) while enforcing structural constraints at the parent level (e.g. months).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
parent_k
|
int
|
Total number of parent groups to select. Must equal sum of group quotas. |
required |
slice_to_parent_mapping
|
dict[Hashable, Hashable]
|
Mapping from each child slice to its parent group. |
required |
parent_to_group_mapping
|
dict[Hashable, Hashable]
|
Mapping from parent ID to its group label (e.g., season). |
required |
group_quota
|
dict[Hashable, int]
|
Required count of parents per group. |
required |
Attributes:
| Name | Type | Description |
|---|---|---|
k |
Number of parent groups per combination (same as parent_k for protocol compliance). |
|
slice_to_parent |
Child to parent mapping. |
|
parent_to_group |
Parent to group label mapping. |
|
group_quota |
Required count per group. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If sum of group quotas does not equal parent_k. |
Note
Use factory methods from_slicers() for automatic parent mapping and
from_slicers_with_seasons() for automatic seasonal grouping.
Examples:
Manual construction for seasonal month selection:
>>> from energy_repset.combi_gens import GroupQuotaHierarchicalCombiGen
>>> import pandas as pd
>>>
>>> slice_to_parent = {
... pd.Period('2024-01-01', 'D'): pd.Period('2024-01', 'M'),
... pd.Period('2024-01-02', 'D'): pd.Period('2024-01', 'M'),
... pd.Period('2024-07-01', 'D'): pd.Period('2024-07', 'M'),
... pd.Period('2024-07-02', 'D'): pd.Period('2024-07', 'M'),
... }
>>> parent_to_group = {
... pd.Period('2024-01', 'M'): 'winter',
... pd.Period('2024-07', 'M'): 'summer',
... }
>>>
>>> gen = GroupQuotaHierarchicalCombiGen(
... parent_k=2,
... slice_to_parent_mapping=slice_to_parent,
... parent_to_group_mapping=parent_to_group,
... group_quota={'winter': 1, 'summer': 1}
... )
>>> gen.count(list(slice_to_parent.keys())) # 1 * 1 = 1
1
Source code in energy_repset/combi_gens/hierarchical_group_quota.py
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 50 51 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 118 119 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 149 150 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 220 221 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 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | |
__init__
¶
__init__(parent_k: int, slice_to_parent_mapping: dict[Hashable, Hashable], parent_to_group_mapping: dict[Hashable, Hashable], group_quota: dict[Hashable, int]) -> None
Initialize hierarchical quota generator.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
parent_k
|
int
|
Total number of parent groups to select. |
required |
slice_to_parent_mapping
|
dict[Hashable, Hashable]
|
Dict mapping each child slice to its parent. |
required |
parent_to_group_mapping
|
dict[Hashable, Hashable]
|
Mapping from parent ID to group label. |
required |
group_quota
|
dict[Hashable, int]
|
Required count per group. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If sum of group quotas does not equal parent_k, or if any parent in slice_to_parent_mapping is missing from parent_to_group_mapping. |
Source code in energy_repset/combi_gens/hierarchical_group_quota.py
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 | |
from_slicers
classmethod
¶
from_slicers(parent_k: int, dt_index: DatetimeIndex, child_slicer: TimeSlicer, parent_slicer: TimeSlicer, parent_to_group_mapping: dict[Hashable, Hashable], group_quota: dict[Hashable, int]) -> GroupQuotaHierarchicalCombiGen
Factory method to create generator from slicers with custom group mapping.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
parent_k
|
int
|
Total number of parent groups to select. |
required |
dt_index
|
DatetimeIndex
|
DatetimeIndex of the time series data. |
required |
child_slicer
|
TimeSlicer
|
TimeSlicer defining child slice granularity (e.g., daily). |
required |
parent_slicer
|
TimeSlicer
|
TimeSlicer defining parent slice granularity (e.g., monthly). |
required |
parent_to_group_mapping
|
dict[Hashable, Hashable]
|
Dict mapping parent IDs to group labels. |
required |
group_quota
|
dict[Hashable, int]
|
Required count per group. |
required |
Returns:
| Type | Description |
|---|---|
GroupQuotaHierarchicalCombiGen
|
GroupQuotaHierarchicalCombinationGenerator with auto-constructed child-to-parent mapping. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If quotas invalid. |
Examples:
Custom grouping of months into seasons:
>>> import pandas as pd
>>> from energy_repset.time_slicer import TimeSlicer
>>> from energy_repset.combi_gens import GroupQuotaHierarchicalCombiGen
>>>
>>> dates = pd.date_range('2024-01-01', periods=366, freq='D')
>>> child_slicer = TimeSlicer(unit='day')
>>> parent_slicer = TimeSlicer(unit='month')
>>>
>>> parent_to_group = {
... pd.Period('2024-01', 'M'): 'winter',
... pd.Period('2024-02', 'M'): 'winter',
... # ... define for all 12 months
... }
>>>
>>> gen = GroupQuotaHierarchicalCombiGen.from_slicers(
... parent_k=4,
... dt_index=dates,
... child_slicer=child_slicer,
... parent_slicer=parent_slicer,
... parent_to_group_mapping=parent_to_group,
... group_quota={'winter': 1, 'spring': 1, 'summer': 1, 'fall': 1}
... )
Source code in energy_repset/combi_gens/hierarchical_group_quota.py
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 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 149 150 151 152 153 154 155 156 157 158 159 160 161 | |
from_slicers_with_seasons
classmethod
¶
from_slicers_with_seasons(parent_k: int, dt_index: DatetimeIndex, child_slicer: TimeSlicer, group_quota: dict[Literal['winter', 'spring', 'summer', 'fall'], int]) -> GroupQuotaHierarchicalCombiGen
Factory method with automatic seasonal grouping of months.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
parent_k
|
int
|
Total number of parent groups to select (must equal sum of quotas). |
required |
dt_index
|
DatetimeIndex
|
DatetimeIndex of the time series data. |
required |
child_slicer
|
TimeSlicer
|
TimeSlicer defining child slice granularity (e.g., daily). |
required |
group_quota
|
dict[Literal['winter', 'spring', 'summer', 'fall'], int]
|
Required count per season. Keys must be subset of {'winter', 'spring', 'summer', 'fall'}. |
required |
Returns:
| Type | Description |
|---|---|
GroupQuotaHierarchicalCombiGen
|
GroupQuotaHierarchicalCombinationGenerator with seasonal parent grouping. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If quotas invalid. |
Note
This factory method uses monthly parents regardless of child slicer. Seasons are assigned as: winter (Dec/Jan/Feb), spring (Mar/Apr/May), summer (Jun/Jul/Aug), fall (Sep/Oct/Nov).
Examples:
Select 4 months (1 per season) from daily data:
>>> import pandas as pd
>>> from energy_repset.time_slicer import TimeSlicer
>>> from energy_repset.combi_gens import GroupQuotaHierarchicalCombiGen
>>>
>>> dates = pd.date_range('2024-01-01', periods=366, freq='D')
>>> child_slicer = TimeSlicer(unit='day')
>>>
>>> gen = GroupQuotaHierarchicalCombiGen.from_slicers_with_seasons(
... parent_k=4,
... dt_index=dates,
... child_slicer=child_slicer,
... group_quota={'winter': 1, 'spring': 1, 'summer': 1, 'fall': 1}
... )
>>> gen.count(child_slicer.unique_slices(dates)) # 3 * 3 * 3 * 3 = 81
81
Source code in energy_repset/combi_gens/hierarchical_group_quota.py
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 220 221 222 223 224 225 226 227 228 | |
generate
¶
generate(unique_slices: Sequence[Hashable]) -> Iterator[SliceCombination]
Generate combinations respecting group quotas, yielding flattened child slices.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unique_slices
|
Sequence[Hashable]
|
Sequence of child slice labels. |
required |
Yields:
| Type | Description |
|---|---|
SliceCombination
|
Tuples containing all child slices from parent_k parent groups satisfying quotas. |
Source code in energy_repset/combi_gens/hierarchical_group_quota.py
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | |
count
¶
count(unique_slices: Sequence[Hashable]) -> int
Count total combinations respecting group quotas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unique_slices
|
Sequence[Hashable]
|
Sequence of child slice labels. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Product of C(n_parents_in_group, quota) across all groups. |
Source code in energy_repset/combi_gens/hierarchical_group_quota.py
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 | |
combination_is_valid
¶
combination_is_valid(combination: SliceCombination, unique_slices: Sequence[Hashable]) -> bool
Check if combination satisfies group quotas and completeness.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
combination
|
SliceCombination
|
Tuple of child slice labels to validate. |
required |
unique_slices
|
Sequence[Hashable]
|
Sequence of all valid child slice labels. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if combination contains complete parent groups satisfying quotas. |
Source code in energy_repset/combi_gens/hierarchical_group_quota.py
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | |