GeoMA
Overview
Binary occupancy inference from electricity demand via a Geometric Moving Average (GeoMA).
Purpose and scope Compares the log-transformed instantaneous power against its exponentially weighted moving average (EWM). If the current reading exceeds the EWM (geometric mean on the original scale), occupancy=1 else 0. An optional nightly schedule can force unoccupied states during specified hours.
Notes
Electricity demand supplies the timestamp index; no separate
clock needed. Uses log10 with a small epsilon to avoid log(0)
and stabilize low values. Smoothing parameter Objects.LAMBDA
tunes responsiveness of the EWM.
Related methods See also PHT (Page–Hinkley Test) for change-point based detection on the same input.
Key facts
Method key:
GeoMASupported types:
occupancy
Requirements
Required keys (specify in objects)
None
Optional keys (specify in objects)
lambda_occnight_schedulenight_schedule_startnight_schedule_end
Required data (specify in data)
electricity
Optional data (specify in data)
None
Outputs
Summary metrics
Key |
Description |
|---|---|
|
average occupancy |
Timeseries columns
Column |
Description |
|---|---|
|
binary occupancy schedule (0/1) |
Public methods
generate
def generate( self, obj: dict = None, data: dict = None, results: dict = None, ts_type: str = Types.OCCUPANCY, *, lambda_occ: float = None, night_schedule: bool = None, night_schedule_start: int = None, night_schedule_end: int = None, ): """ Generate a binary occupancy schedule from electricity demand using GeoMA. This method is a thin orchestrator around calculate_timeseries. It prepares inputs, applies defaults for optional parameters (via the Method helpers), and formats the output as expected by the framework (summary and timeseries). Args: obj (dict, optional): Object parameters. Relevant keys (under the current method type) include: - O.LAMBDA (float): Exponential smoothing parameter in (0, 1]. - O.NIGHT_SCHEDULE (bool): Whether to enforce a nightly schedule. - O.NIGHT_SCHEDULE_START (int): Start hour of nightly off period [0-23]. - O.NIGHT_SCHEDULE_END (int): End hour of nightly off period [0-23]. data (dict, optional): Not used directly for this method. The electricity time series is expected to be present in results under Types.ELECTRICITY. results (dict, optional): Dictionary with previously computed time series. Must contain an entry for Types.ELECTRICITY with key Keys.TIMESERIES that provides a pandas DataFrame with a datetime column Columns.DATETIME and at least one power column. ts_type (str, optional): Target time series type. Defaults to Types.OCCUPANCY. lambda_occ (float, optional): Exponential smoothing factor for the EWM used to compute the geometric moving average. Typical range (0.05–0.5). night_schedule (bool, optional): If True, apply nightly zeroing. night_schedule_start (int, optional): Hour of day marking the start of the nightly off period (e.g., 18:00). night_schedule_end (int, optional): Hour of day marking the end of the nightly off period (e.g., 00:00). Returns: dict: A dictionary with two keys: - "summary" (dict): Contains aggregated indicators, including f"{Types.OCCUPANCY}{SEP}{Objects.OCCUPANCY_AVG}" with the average occupancy. - "timeseries" (pd.DataFrame): A DataFrame indexed by datetime with one column f"{Types.OCCUPANCY}{SEP}{Objects.OCCUPANCY}" containing 0/1 occupancy states. Raises: KeyError: If the required electricity time series is missing from results. ValueError: If the electricity data lacks a datetime column or any power column. Examples: >>> method = GeoMA() >>> out = method.generate(results={Types.ELECTRICITY: {K.TIMESERIES: elec_df}}) >>> out["timeseries"].head() """ # Process keyword arguments processed_obj, processed_data = self._process_kwargs( obj, data, lambda_occ=lambda_occ, night_schedule=night_schedule, night_schedule_start=night_schedule_start, night_schedule_end=night_schedule_end, ) # Get input data processed_obj, processed_data = self._get_input_data(processed_obj, processed_data, results, ts_type) # Compute temperature and energy demand occ_schedule = calculate_timeseries(processed_obj, processed_data) return self._format_output(occ_schedule, processed_data)