Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement outlier code and tests #296

Open
AdamFinkle opened this issue Feb 12, 2025 · 0 comments
Open

Implement outlier code and tests #296

AdamFinkle opened this issue Feb 12, 2025 · 0 comments

Comments

@AdamFinkle
Copy link
Collaborator

AdamFinkle commented Feb 12, 2025

We removed this code that would help support derived outliers, should they be chosen to be implemented in a later version.

test_engine.py

@pytest.fixture()
def sample_intermediate_energy_bill_inputs_with_outlier() -> (
    list[engine.IntermediateEnergyBill]
):
    intermediate_energy_bill_inputs = [
        engine.IntermediateEnergyBill(
            _dummy_processed_energy_bill_input,
            [41.7, 41.6, 32, 25.4],
            60,
            AnalysisType.ALLOWED_HEATING_USAGE,
            True,
            False,
        ),
        engine.IntermediateEnergyBill(
            _dummy_processed_energy_bill_input,
            [28, 29, 30, 29],
            50,
            AnalysisType.ALLOWED_HEATING_USAGE,
            True,
            False,
        ),
        engine.IntermediateEnergyBill(
            _dummy_processed_energy_bill_input,
            [32, 35, 35, 38],
            45,
            AnalysisType.ALLOWED_HEATING_USAGE,
            True,
            False,
        ),
        engine.IntermediateEnergyBill(
            _dummy_processed_energy_bill_input,
            [41, 43, 42, 42],
            30,
            AnalysisType.ALLOWED_HEATING_USAGE,
            True,
            False,
        ),
        engine.IntermediateEnergyBill(
            _dummy_processed_energy_bill_input,
            [72, 71, 70, 69],
            0.96,
            AnalysisType.NOT_ALLOWED_IN_CALCULATIONS,
            False,
            False,
        ),
    ]

    return intermediate_energy_bill_inputs

...

def test_bp_ua_with_outlier(
    sample_heat_load_inputs, sample_intermediate_energy_bill_inputs_with_outlier
):
    home = engine.Home.calculate(
        sample_heat_load_inputs,
        sample_intermediate_energy_bill_inputs_with_outlier,
        dhw_input=None,
        initial_balance_point=58,
    )

    # expect that ua_1 is considered an outlier and not used in winter_processed_energy_bills
    ua_2, ua_3, ua_4 = [bill.ua for bill in home.winter_processed_energy_bills]

    assert home.balance_point == 60.5
    assert ua_2 == approx(1455.03, abs=0.01)
    assert ua_3 == approx(1617.65, abs=0.01)
    assert ua_4 == approx(1486.49, abs=0.01)
    assert home.avg_ua == approx(1519.72, abs=1)
    assert home.stdev_pct == approx(0.0463, abs=0.01)

engine.py

        while new_stdev_pct > stdev_pct_max:
            outliers = [
                abs(bill.ua - avg_ua)
                for bill in winter_processed_energy_bills
                if bill.ua is not None
            ]
            biggest_outlier = max(outliers)
            biggest_outlier_idx = outliers.index(biggest_outlier)
            outlier = winter_processed_energy_bills.pop(
                biggest_outlier_idx
            )  # removes the biggest outlier
            outlier.eliminated_as_outlier = True
            uas_i = [
                processed_energy_bill.ua
                for processed_energy_bill in winter_processed_energy_bills
                if processed_energy_bill.ua is not None
            ]
            avg_ua_i = sts.mean(uas_i)
            stdev_pct_i = sts.pstdev(uas_i) / avg_ua_i
            if (
                # the outlier has been removed
                new_stdev_pct - stdev_pct_i
                < max_stdev_pct_diff
            ):  # if it's a small enough change
                # add the outlier back in
                winter_processed_energy_bills.append(
                    outlier
                )  # then it's not worth removing it, and we exit
                outlier.eliminated_as_outlier = False
                break  # may want some kind of warning to be raised as well
            else:
                uas, avg_ua, stdev_pct = uas_i, avg_ua_i, stdev_pct_i

            results = Home._refine_balance_point(
                balance_point=balance_point,
                balance_point_sensitivity=next_balance_point_sensitivity,
                avg_ua=avg_ua,
                stdev_pct=stdev_pct,
                thermostat_set_point=thermostat_set_point,
                winter_processed_energy_bills=winter_processed_energy_bills,
            )

            new_balance_point = results.balance_point
            new_avg_ua = results.avg_ua
            new_stdev_pct = results.stdev_pct
            balance_point_graph_records_extension = (
                results.balance_point_graph_records_extension
            )

            if isinstance(balance_point_graph_records_extension, list):
                balance_point_graph.records.extend(
                    balance_point_graph_records_extension
                )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant