Degree Days

Degree Days

Weather Data for Energy Saving

Regression Analysis of Energy-Usage Data with the Degree Days.net API

If your software needs degree days, quite likely it will also need regression, as regression is core to most good analysis of energy-usage data.

Our API makes regression analysis as easy as fetching degree days. But it offers a lot more than basic regression. Send the API a set of energy data, and it will test thousands of regressions against it to find the regression model with the HDD/CDD base temperatures that give the best statistical fit.

Your software can then repeat this process to get an optimal regression model for each building in your system.

It essentially works like this:

  1. You send a RegressionRequest containing the energy-usage data (dated records of energy usage), and either the location of the building it came from, or the ID of the nearby weather station that you want the API to use. You can optionally provide extra-predictor data like occupancy or production figures too.
  2. The API will internally generate HDD and CDD in a wide range of base temperatures and use them to test thousands of regressions against the input data you provided.
  3. The API will return a list of the regressions that give the best statistical fit, together with a range of statistics to help you assess their quality.
  4. You can choose the best regression (usually the first listed), and use it as the baseline for future analysis.

If this is unclear, it would probably help you to check out the regression tool on our website. It has most of the regression functionality of the API (the API has a few more options), but you don't need any programming to use it. You couldn't practically run data from thousands of buildings through our online regression tool (like you could with our API), but it is great for testing out individual data sets to get a better understanding of the regression process and how best to take advantage of it. If you have an API Standard, Plus, or Premium account already, make sure to take advantage of the free Pro website access that comes included, as that will get the online regression tool running at full API speed rather than the much slower speed of the free website.

It would also be worthwhile to go through our articles on degree days and how best to use them. There's a lot of information there, but we can't stress enough how important it is to understand degree days and their analysis techniques well before building them into your software.

On this page:

A simple example

The code below shows a sample RegressionRequest, containing dated energy-usage data, the location of the building it came from (or you can specify a weather station to use for the degree days in the regressions), and some additional configuration to give you control over the regression process that the API will use:

{
    "securityInfo": {
        // Like for any request to our API, you will need to set these
        // securityInfo properties as explained at www.degreedays.net/api/json
        "endpoint": "http://apiv1.degreedays.net/json",
        "accountKey": "test-test-test",
        "timestamp": "2024-05-24T01:49:12Z",
        "random": "664ff218df882"
    },
    "request": {
        "type": "RegressionRequest",
        // Specify the location of the building the energy data came from (so
        // the API can choose the best weather station to use for the degree
        // days it uses in its regressions), or specify the weather station
        // explicitly.  See www.degreedays.net/api/json for more on the different
        // location options.
        "location": {
            "type": "PostalCodeLocation",
            "postalCode": "02630",
            "countryCode": "US"
        },
        "regressionTestPlan": {
            // Specify whether the regressions should use Celsius-based or
            // Fahrenheit-based degree days.
            "temperatureUnit": "C",
            // "Weighted" day normalization is recommended, but you can also
            // specify "Unweighted" or "None".  For more on these options see
            // www.degreedays.net/regression
            "dayNormalization": "Weighted"
            // The properties above are required, but you can also optionally
            // include "customTestHeatingBaseTemperatures",
            // "customTestCoolingBaseTemperatures", "extraPredictorSpecs", and
            // "requestedRegressionSpecs".  These are all explained further down
            // in the docs at www.degreedays.net/api/regression
        },
        // inputData is the energy-usage data that the API will run regressions
        // on.  It's a chronological list of input periods, each with a
        // "dayRange" and a "usage" value.
        "inputData": [
            {
                "dayRange": {
                    "first": "2023-02-01",
                    "last": "2023-02-28"
                },
                // "usage" is the energy usage for the period, typically in kWh,
                // but other units are fine too.  The API just processes the
                // usage figures as numbers, and the regressions you get back in
                // the response will use whatever units you use here.
                "usage": 48415
                // You can also include extra-predictor data here, as explained
                // further down in the docs at www.degreedays.net/api/regression
            },
            {
                "dayRange": {
                    "first": "2023-03-01",
                    "last": "2023-03-31"
                },
                "usage": 29518
            },
            {
                "dayRange": {
                    "first": "2023-04-01",
                    "last": "2023-04-30"
                },
                "usage": 21815
            },
            {
                "dayRange": {
                    "first": "2023-05-01",
                    "last": "2023-05-31"
                },
                "usage": 11141
            },
            {
                "dayRange": {
                    "first": "2023-06-01",
                    "last": "2023-06-30"
                },
                "usage": 7689
            }
            // In reality you would want more periods, and ideally covering at
            // least a full year, but this is just an example to show the
            // request format.
        ]
    }
}
// Sending a RegressionRequest to the API is just like sending a
// LocationDataRequest or LocationInfoRequest.  See the instructions at
//   www.degreedays.net/api/json#send
// or follow the code samples for the various languages listed at
//   https://www.degreedays.net/api/integration#programming-language-options
// You can also try sending this request using the JSON API test tool at
//   www.degreedays.net/api/json/test
<?xml version="1.0" encoding="UTF-8" ?>

<RequestEnvelope>
  
  <SecurityInfo>
    <!-- Like for any request to our API, you will need to set these
    SecurityInfo properties as explained at www.degreedays.net/api/xml -->
    <Endpoint>http://apiv1.degreedays.net/xml</Endpoint>
    <AccountKey>test-test-test</AccountKey>
    <Timestamp>2024-05-24T01:49:12Z</Timestamp>
    <Random>664ff218df882</Random>
  </SecurityInfo>      

  <RegressionRequest>
    <!-- Specify the location of the building the energy data came from (so the
    API can choose the best weather station to use for the degree days it uses
    in its regressions), or specify the weather station explicitly.  See
    www.degreedays.net/api/xml for more on the different location options. -->
    <PostalCodeLocation>
      <PostalCode>02630</PostalCode>
      <CountryCode>US</CountryCode>
    </PostalCodeLocation>
    
    <RegressionTestPlan>
      <!-- Specify whether the regressions should use Celsius-based or
      Fahrenheit-based degree days. -->
      <TemperatureUnit>Celsius</TemperatureUnit>
      <!-- Weighted day normalization is recommended, but you can also specify
      Unweighted or None.  See www.degreedays.net/regression for more. -->
      <DayNormalization>Weighted</DayNormalization>
      <!-- The elements above are required, but you can also optionally
      include CustomTestHeatingBaseTemperatures,
      CustomTestCoolingBaseTemperatures, ExtraPredictorSpecs, and
      RequestedRegressionSpecs.  These are all explained further down in the
      docs at www.degreedays.net/api/regression -->
    </RegressionTestPlan>
    
    <!-- InputData is the energy-usage data that the API will run regressions
    on.  It's a chronological list of input periods, each with a DayRange and a
    Usage value. -->
    <InputData>
      <InputPeriod>
        <DayRange first="2023-02-01" last="2023-02-28"/>
        <!-- The Usage is the energy usage for the period, typically in kWh, but
        other units are fine too.  The API just processes the usage figures as
        numbers, and the regressions you get back in the response will use
        whatever units you use here. -->
        <Usage>48415</Usage>
        <!-- You can also include extra-predictor data here, as explained
        further down in the docs at www.degreedays.net/api/regression -->
      </InputPeriod>
      <InputPeriod>
        <DayRange first="2023-03-01" last="2023-03-31"/>
        <Usage>29518</Usage>
      </InputPeriod>
      <InputPeriod>
        <DayRange first="2023-04-01" last="2023-04-30"/>
        <Usage>21815</Usage>
      </InputPeriod>
      <InputPeriod>
        <DayRange first="2023-05-01" last="2023-05-31"/>
        <Usage>11141</Usage>
      </InputPeriod>
      <InputPeriod>
        <DayRange first="2023-06-01" last="2023-06-30"/>
        <Usage>7689</Usage>
      </InputPeriod>
      <!-- In reality you would want more periods, and ideally covering at least
      a full year, but this is just an example to show the request format. -->
    </InputData>
    
  </RegressionRequest>

</RequestEnvelope>

<!-- Sending a RegressionRequest to the API is just like sending a 
LocationDataRequest or LocationInfoRequest.  See the instructions at
  www.degreedays.net/api/xml#send
You can also try sending this request using the XML API test tool at
  www.degreedays.net/api/xml/test -->
import java.util.List;
import net.degreedays.api.*;
import net.degreedays.api.data.*;
import net.degreedays.api.regression.*;
import net.degreedays.geo.*;
import net.degreedays.time.*;


DegreeDaysApi api = new DegreeDaysApi(
    new AccountKey(yourStringAccountKey),
    new SecurityKey(yourStringSecurityKey));

// InputData is made up of InputPeriod objects, each representing the energy
// usage over a dated period (represented by a net.degreedays.time.DayRange).
InputData inputData = new InputData(
    new InputPeriod( // DayRange spelt out in full, to show the types clearly:
        new DayRange(Day.of(2023, 2, 1), Day.of(2023, 2, 28)),
        48415), // The energy usage for the period.  Typically this would be in
                // kWh, but other units are fine too.  The API just processes the
                // usage figures as numbers, and the regressions you get back in
                // the response will use whatever units you use here.
    new InputPeriod(Day.of(2023, 3, 1).to(2023, 3, 31), 29518), // more concise
    new InputPeriod(Day.of(2023, 4, 1).to(2023, 4, 30), 21815),
    new InputPeriod(Day.of(2023, 5, 1).to(2023, 5, 31), 11141),
    new InputPeriod(Day.of(2023, 6, 1).to(2023, 6, 30), 7689));
    // In reality you would want more periods, and ideally covering at least a
    // full year, but this is just an example to show the request format.

// Specify the location of the building the energy data came from (so the API
// can choose the best weather station to use for the degree days it uses in its
// regressions), or specify the weather station explicitly.
Location location = Location.postalCode("02630", "US");
// Location location = Location.longLat(new LongLat(-70.28846, 41.66881));
// Location location = Location.stationId("KHYA");

RegressionRequest request = new RegressionRequest(
    location,
    inputData,
    new RegressionTestPlan.Builder(TemperatureUnit.CELSIUS).build());

// The line below could throw quite a few different exceptions.  See the notes
// on error handling further below at www.degreedays.net/api/regression
RegressionResponse response = api.regressionApi().runRegressions(request);

System.out.println(response);
using DegreeDays.Api;
using DegreeDays.Api.Data;
using DegreeDays.Api.Regressions;
using DegreeDays.Geo;
using DegreeDays.Time;


DegreeDaysApi api = new DegreeDaysApi(
    new AccountKey(yourStringAccountKey),
    new SecurityKey(yourStringSecurityKey));

// InputData is made up of InputPeriod objects, each representing the energy
// usage over a dated period (represented by a DegreeDays.Time.DayRange).
InputData inputData = new InputData(
    new InputPeriod( // DayRange spelt out in full, to show the types clearly:
        new DayRange(new Day(2023, 2, 1), new Day(2023, 2, 28)),
        48415), // The energy usage for the period.  Typically this would be in
                // kWh, but other units are fine too.  The API just processes the
                // usage figures as numbers, and the regressions you get back in
                // the response will use whatever units you use here.
    new InputPeriod(new Day(2023, 3, 1).To(2023, 3, 31), 29518), // more concise
    new InputPeriod(new Day(2023, 4, 1).To(2023, 4, 30), 21815),
    new InputPeriod(new Day(2023, 5, 1).To(2023, 5, 31), 11141),
    new InputPeriod(new Day(2023, 6, 1).To(2023, 6, 30), 7689));
    // In reality you would want more periods, and ideally covering at least a
    // full year, but this is just an example to show the request format.

// Specify the location of the building the energy data came from (so the API
// can choose the best weather station to use for the degree days it uses in its
// regressions), or specify the weather station explicitly.
Location location = Location.PostalCode("02630", "US");
// Location location = Location.LongLat(new LongLat(-70.28846, 41.66881));
// Location location = Location.StationId("KHYA");

RegressionRequest request = new RegressionRequest(
    location,
    inputData,
    new RegressionTestPlan.Builder(TemperatureUnit.Celsius).Build());

// The line below could throw quite a few different exceptions.  See the notes
// on error handling further below at www.degreedays.net/api/regression
RegressionResponse response = api.RegressionApi.RunRegressions(request);

Console.Out.WriteLine(response);
Imports DegreeDays.Api
Imports DegreeDays.Api.Data
Imports DegreeDays.Api.Regressions
Imports DegreeDays.Geo
Imports DegreeDays.Time


Dim api As New DegreeDaysApi(
    New AccountKey(yourStringAccountKey),
    New SecurityKey(yourStringSecurityKey))

' InputData is made up of InputPeriod objects, each representing the energy
' usage over a dated period (represented by a DegreeDays.Time.DayRange).
Dim inputData As New InputData(
    New InputPeriod( ' DayRange spelt out in full, to show the types clearly:
        New DayRange(New Day(2022, 2, 1), New Day(2022, 2, 28)),
        48415), _' The energy usage for the period.  Typically this would be in
                _' kWh, but other units are fine too.  The API just processes
                _' the usage figures as numbers, and the regressions you get
                _' back in the response will use whatever units you use here.
    New InputPeriod(New Day(2022, 3, 1).To(2022, 3, 31), 29518), ' more concise
    New InputPeriod(New Day(2022, 4, 1).To(2022, 4, 30), 21815),
    New InputPeriod(New Day(2022, 5, 1).To(2022, 5, 31), 11141),
    New InputPeriod(New Day(2022, 6, 1).To(2022, 6, 30), 7689))
    ' In reality you would want more periods, and ideally covering at least a
    ' full year, but this is just an example to show the request format.

' Specify the location of the building the energy data came from (so the API
' can choose the best weather station to use for the degree days it uses in its
' regressions), or specify the weather station explicitly.
Dim location As Location = Location.PostalCode("02630", "US")
' Dim location As Location = Location.LongLat(New LongLat(-70.28846, 41.66881))
' Dim location As Location = Location.StationId("KHYA")

Dim request As New RegressionRequest(
    location,
    inputData,
    New RegressionTestPlan.Builder(TemperatureUnit.Celsius).Build())

' The line below could throw quite a few different exceptions.  See the notes
' on error handling further below at www.degreedays.net/api/regression
Dim response As RegressionResponse = api.RegressionApi.RunRegressions(request)

Console.Out.WriteLine(response)
from datetime import date
from degreedays.api import DegreeDaysApi, AccountKey, SecurityKey
from degreedays.api.data import Location, TemperatureUnit, Temperature
from degreedays.api.regression import InputData, InputPeriod, \
    RegressionTestPlan, RegressionRequest, RegressionSpec, RegressionTag, \
    ExtraPredictorSpec, PredictorType, ExpectedCorrelation
from degreedays.time import DayRange
from degreedays.geo import LongLat


api = DegreeDaysApi.fromKeys(
    AccountKey(yourStringAccountKey),
    SecurityKey(yourStringSecurityKey))

# InputData is made up of InputPeriod objects, each representing the energy
# usage over a dated period (represented by a net.degreedays.time.DayRange).
inputData = InputData(
    # The energy usage (48415 in the first InputPeriod below) would typically be
    # in kWh, but other units are fine too.  The API just processes the usage
    # figures as numbers, and the regressions you get back in the response will
    # use whatever units you use here.
    InputPeriod(DayRange(date(2023, 2, 1), date(2023, 2, 28)), 48415),
    InputPeriod(DayRange(date(2023, 3, 1), date(2023, 3, 31)), 29518),
    InputPeriod(DayRange(date(2023, 4, 1), date(2023, 4, 30)), 21815),
    InputPeriod(DayRange(date(2023, 5, 1), date(2023, 5, 31)), 11141),
    InputPeriod(DayRange(date(2023, 6, 1), date(2023, 6, 30)), 7689))
    # In reality you would want more periods, and ideally covering at least a
    # full year, but this is just an example to show the request format.

# Specify the location of the building the energy data came from (so the API
# can choose the best weather station to use for the degree days it uses in its
# regressions), or specify the weather station explicitly.
location = Location.postalCode("02630", "US")
# location = Location.longLat(LongLat(-70.28846, 41.66881))
# location = Location.stationId('KHYA')

request = RegressionRequest(
    location,
    inputData,
    RegressionTestPlan(TemperatureUnit.CELSIUS))

# The line below could throw quite a few different exceptions.  See the notes
# on error handling further below at www.degreedays.net/api/regression
response = api.regressionApi.runRegressions(request)

print(response)

You'll get a RegressionResponse back from the API, containing the results of the regression analysis that the API performed on your input data. Here's an annotated sample:

{
    // metadata is included with every response.  For more on this see
    // www.degreedays.net/api/json
    "metadata": {
        "rateLimit": {
            "requestUnitsAvailable": 852,
            "minutesToReset": 32
        }
    },
    // Since you made a RegressionRequest, the "response" will be a
    // RegressionResponse.  (Unless it's a Failure instead - see the notes
    // further below at www.degreedays.net/api/regression for more on this.)
    "response": {
        "type": "RegressionResponse",
        // The "stationId", "targetLongLat", and "sources" explain the origin of
        // the data used to generate degree days for your regressions.  For more
        // on these elements please see the sample LocationDataResponse at
        // www.degreedays.net/api/json#response
        "stationId": "KHYA",
        "targetLongLat": {
            "longitude": -70.30007,
            "latitude": 41.69829
        },
        "sources": [
            {
                "station": {
                    "id": "KHYA",
                    "longLat": {
                        "longitude": -70.28036,
                        "latitude": 41.66933
                    },
                    "elevationMetres": 16,
                    "displayName": "HYANNIS BARNSTABLE BOARDMN, MA, US"
                },
                "metresFromTarget": 3612
            }
        ],
        // In the usual case, "dataSets" and "regressions" (below it) will both
        // be present.  If the location does not have enough weather data for
        // the API to generate the degree days necessary to run the regressions,
        // you will get a single "failure" here instead.  More on this in the
        // notes at www.degreedays.net/api/regression
        "dataSets": {
            // This will contain each set of degree days used for the
            // regressions listed further below, in the same format used in
            // LocationDataResponse as described at www.degreeday.net/api/json
            // The names (like "heating11_5C") are auto-assigned by the API.
            "heating11_5C": {
                "type": "DatedDataSet",
                "percentageEstimated": 0.05,
                "values": [
                    {
                        "d": "2023-02-01",
                        "ld": "2023-02-28",
                        "v": 260.8,
                        "pe": 0.04
                    },
                    {
                        "d": "2023-03-01",
                        "ld": "2023-03-31",
                        "v": 182.4
                    }
                    // The rest of the values in this DatedDataSet have been
                    // omitted for clarity.
                ]
            }
            // The other sets of degree days have been omitted for clarity
            // too.  If you want to see a full response, you can run the example
            // JSON request at www.degreedays.net/api/regression through the
            // JSON API test tool at www.degreedays.net/api/json/test
        },
        "regressions": [
            // The regression listed first is the one with the best stats.  If
            // you know nothing about the building, its likely base
            // temperature(s), or whether its energy-usage data covers heating,
            // cooling, or both, the first regression is probably the best
            // choice.  But, if you know more, your code could look through all
            // regressions with the "Shortlist" tag to make a more informed
            // choice.  For more on choosing the best regression, see
            // www.degreedays.net/regression
            {
                "tags": [
                    "Shortlist"
                ],
                // The components describe the various parts of the regression
                // equation.  For example, in
                //   E = b*days + h*HDD
                // b*days is the baseload component; and
                // h*HDD is the heatingDegreeDays component.
                // For more on regression equations see
                // www.degreedays.net/regression
                "components": {
                    // Every regression will have a "baseload" component:
                    "baseload": {
                        // If you chose "Weighted" day normalization in your
                        // request (as recommended), "multiplyByNumberOfDays"
                        // will be true to indicate that, in your regression
                        // equation, you should multiply the baseload
                        // coefficient by the number of days covered by the
                        // period you are calculating energy usage E for.
                        "multiplyByNumberOfDays": true,
                        // The baseload coefficient is the b in a regression
                        // equation like E = b*days + h*HDD
                        "coefficient": 260.3608413444563,
                        "coefficientStandardError": 83.70316180823093,
                        "coefficientPValue": 0.05285986107372276
                    },
                    // Not all regressions will have a "heatingDegreeDays"
                    // component:
                    "heatingDegreeDays": {
                        // The base temperature of the heating degree days.
                        "baseTemperature": {
                            "unit": "C",
                            "value": 11.5
                        },
                        // This key enables you to get the appropriate degree
                        // days from the "dataSets" further above.
                        "sampleDegreeDaysDataSetKey": "heating11_5C",
                        "sampleDegreeDaysTotal": {
                            "v": 539.1,
                            "pe": 0.05
                        },
                        // The heatingDegreeDays coefficient is the h in a
                        // regression equation like E = b*days + h*HDD
                        "coefficient": 147.5122867711585,
                        "coefficientStandardError": 16.846394266791744,
                        "coefficientPValue": 0.00313676968063481
                    }
                    // You might also get a "coolingDegreeDays" component here,
                    // and components for any extra predictors you included (see
                    // www.degreedays.net/api/regression for more on these).
                },
                // The number of energy-usage figures that were used for the
                // regression.  This could be less than the number of input
                // periods included in your request, if the location could
                // not provide enough weather data to cover all of them.
                "sampleSize": 5,
                // The number of days covered by the sample, excluding any gaps
                // between input periods.
                "sampleDays": 150,
                "sampleSpan": {
                    "first": "2023-02-01",
                    "last": "2023-06-30"
                },
                // This will include any gaps between input periods.
                "sampleSpanDays": 150,
                // See www.degreedays.net/regression for more on these stats.
                "rSquared": 0.9623460907927606,
                "adjustedRSquared": 0.9497947877236806,
                "crossValidatedRSquared": 0.8663153959993393,
                "standardError": 129.236378890448,
                "cvrmse": 0.16348274413101252
            }
            // In reality you'll get a list of the best regressions (out of the
            // thousands tested by the API), but, to keep this example response
            // short, we've included only the one above.
            // To see a full response you can run the example JSON request at
            // www.degreedays.net/api/regression through the JSON API test tool
            // at www.degreedays.net/api/json/test
        ]
    }
}
<Response>
  
  <!-- Metadata is included with every response.  For more on this see
  www.degreedays.net/api/xml -->
  <Metadata>
    <RateLimit>
      <RequestUnitsAvailable>852</RequestUnitsAvailable>
      <MinutesToReset>32</MinutesToReset>
    </RateLimit>
  </Metadata>
  
  <!-- Since you made a RegressionRequest, you'll get a RegressionResponse back.
  (Unless it's a Failure instead - see the notes further below at
  www.degreedays.net/api/regression for more on this.) -->
  <RegressionResponse>
  
    <Head>
      <!-- The StationId, TargetLocation, and Sources explain the origin of the
      data used to generate degree days for your regressions.  For more on these
      elements please see the sample LocationDataResponse at
      www.degreedays.net/api/xml#response -->
      <StationId>KHYA</StationId>
      <TargetLocation>
        <LongLat longitude="-70.30007" latitude="41.69829"/>
      </TargetLocation>
      <Sources>
        <Source>
          <Station>
            <Id>KHYA</Id>
            <LongLat longitude="-70.28036" latitude="41.66933"/>
            <ElevationMetres>16</ElevationMetres>
            <DisplayName>HYANNIS BARNSTABLE BOARDMN, MA, US</DisplayName>
          </Station>
          <MetresFromTarget>3612</MetresFromTarget>
        </Source>
      </Sources>
    </Head>
    
    <!-- In the usual case, DataSets and Regressions (below it) will both be
    present.  If the location does not have enough weather data for the API to
    generate the degree days necessary to run the regressions, you will get a
    single Failure here instead.  More on this in the notes at
    www.degreedays.net/api/regression -->
    <DataSets>
      <!-- This will contain each set of degree days used for the regressions
      listed further below, in the same format used in LocationDataResponse as
      described at www.degreedays.net/api/xml 
      The keys (like heating11.5C) are auto-assigned by the API. -->
      <DatedDataSet key="heating11.5C">
        <Head>
          <PercentageEstimated>0.05</PercentageEstimated>
        </Head>
        <Values>
          <V d="2023-02-01" ld="2023-02-28" pe="0.04">260.8</V>
          <V d="2023-03-01" ld="2023-03-31">182.4</V>
          <!-- The rest of the values in this DatedDataSet have been omitted for
          clarity. -->
        </Values>
      </DatedDataSet>
      <!-- The other sets of degree days have been omitted for clarity too.  If
      you want to see a full response, you can run the example XML request at
      www.degreedays.net/api/regression through the XML API test tool at
      www.degreedays.net/api/xml/test -->
    </DataSets>
    
    <Regressions>
      <!-- The regression listed first is the one with the best stats.  If you
      know nothing about the building, its likely base temperature(s), or
      whether its energy-usage data covers heating, cooling, or both, the first
      regression is probably the best choice.  But, if you know more, your code
      could look through all regressions with the Shortlist tag to make a more
      informed choice.  For more on choosing the best regression, see
      www.degreedays.net/regression -->
      <Regression>
        <Tags>
          <Tag>Shortlist</Tag>
        </Tags>
        <!-- The regression listed first is the one with the best stats.  If you
        know nothing about the building, its likely base temperature(s), or
        whether its energy-usage data covers heating, cooling, or both, the
        first regression is probably the best choice.  But, if you know more,
        your code could look through all regressions with the "Shortlist" tag to
        make a more informed choice.  For more on choosing the best regression,
        see www.degreedays.net/regression -->
        <Components>
          <!-- Every regression will have a Baseload component. -->
          <Baseload>
            <BaseloadInfo>
              <!-- If you chose Weighted day normalization in your request (as
              recommended), MultiplyByNumberOfDays will be true to indicate that
              that, in your regression equation, you should multiply the
              baseload coefficient by the number of days covered by the period
              you are calculating energy usage E for. -->
              <MultiplyByNumberOfDays>true</MultiplyByNumberOfDays>
            </BaseloadInfo>
            <!-- The baseload coefficient is the b in a regression equation like
            E = b*days + h*HDD -->
            <Coefficient>260.3608413444563</Coefficient>
            <CoefficientStandardError>83.70316180823093</CoefficientStandardError>
            <CoefficientPValue>0.05285986107372276</CoefficientPValue>
          </Baseload>
          <!-- Not all regressions will have a HeatingDegreeDays component. -->
          <HeatingDegreeDays>
            <HeatingDegreeDaysInfo>
              <!-- The base temperature of the heating degree days. -->
              <CelsiusBaseTemperature>11.5</CelsiusBaseTemperature>
              <!-- This key enables you to get the appropriate degree days from
              the DataSets further above. -->
              <SampleDegreeDaysDataSetKey>heating11.5C</SampleDegreeDaysDataSetKey>
              <SampleDegreeDaysTotal pe="0.05">539.1</SampleDegreeDaysTotal>
            </HeatingDegreeDaysInfo>
            <!-- The HeatingDegreeDays Coefficient is the h in a regression
            equation like E = b*days + h*HDD -->
            <Coefficient>147.5122867711585</Coefficient>
            <CoefficientStandardError>16.846394266791744</CoefficientStandardError>
            <CoefficientPValue>0.00313676968063481</CoefficientPValue>
          </HeatingDegreeDays>
          <!-- You might also get a CoolingDegreeDays component here, and
          components for any extra predictors you included (see
          www.degreedays.net/api/regression for more on these). -->
        </Components>
        <!-- The number of energy-usage figures that were used for the
        regression.  This could be less than the number of input periods
        included in your request, if the location could not provide enough
        weather data to cover all of them. -->
        <SampleSize>5</SampleSize>
        <!-- The number of days covered by the sample, excluding any gaps
        between input periods. -->
        <SampleDays>150</SampleDays>
        <SampleSpan first="2023-02-01" last="2023-06-30"/>
        <!-- This will include any gaps between input periods. -->
        <SampleSpanDays>150</SampleSpanDays>
        <!-- See www.degreedays.net/regression for more on these stats. -->
        <RSquared>0.9623460907927606</RSquared>
        <AdjustedRSquared>0.9497947877236806</AdjustedRSquared>
        <CrossValidatedRSquared>0.8663153959993393</CrossValidatedRSquared>
        <StandardError>129.236378890448</StandardError>
        <Cvrmse>0.16348274413101252</Cvrmse>
      </Regression>
      <!-- In reality you'll get a list of the best regressions (out of the
      thousands tested by the API), but, to keep this example response short,
      we've included only the one above.  To see a full response you can run the
      example JSON request at www.degreedays.net/api/regression through the JSON
      API test tool at www.degreedays.net/api/json/test -->
    </Regressions>
    
  </RegressionResponse>
  
</Response>
// This continues on from the Java request sample near the top of the page at
// www.degreedays.net/api/regression
// So we already have our RegressionResponse object (response) from that.

System.out.println("Weather station for degree days: " + response.stationId());

// In the usual case the response will contain a list of the most promising or
// notable regressions out of the thousands tested by the API.
// Though the line below could throw a SourceDataException if your specified
// location did not have enough good weather data for the API to generate the
// degree days necessary to run regressions against your InputData.
List<Regression> regressions = response.getRegressions();

// The regression listed first is the one with the best stats.  If you know
// nothing about the building, its likely base temperature(s), or whether its
// energy-usage data covers heating, cooling, or both, the first regression is
// probably the best choice.  But, if you know more, your code could look
// through all the regressions with .hasTag(RegressionTag.SHORTLIST) to make a
// more informed choice.  For more on choosing the best regression, see
// www.degreedays.net/regression
Regression chosen = regressions.get(0);

// Each Regression object contains lots of data.  We reconstruct the regression
// equation to show you how to access the coefficients and degree-day base
// temperature(s):
System.out.println("E = " +
        chosen.baseload().coefficient() +
        (chosen.baseload().multiplyByNumberOfDays() ? "*days" : ""));
if (chosen.hasHeatingDegreeDays()) {
    DegreeDaysRegressionComponent hddComponent =
            chosen.getHeatingDegreeDays();
    System.out.println("  + " + hddComponent.coefficient() +
            "*HDD (base temperature " + hddComponent.baseTemperature() + ")");
}
if (chosen.hasCoolingDegreeDays()) {
    DegreeDaysRegressionComponent cddComponent =
            chosen.getCoolingDegreeDays();
    System.out.println("  + " + cddComponent.coefficient() +
            "*CDD (base temperature " + cddComponent.baseTemperature() + ")");
}

// We also output some of the additional data to show you what is available in
// each Regression object:

// sampleSize is the number of energy-usage figures used for the regression.
// This could be less than the number of input periods included in your request,
// if the location could not provide enough weather data to cover all of them.
System.out.println("Sample size = " + chosen.sampleSize());
// sampleDays is the number of days covered by the sample, excluding any gaps
// between input periods.
System.out.println("Sample days = " + chosen.sampleDays());
// sampleSpan is a DayRange object.
System.out.println("Sample span = " + chosen.sampleSpan());
// sampleSpanDays will include any gaps between input periods.
System.out.println("Sample span days = " + chosen.sampleSpanDays());
// The stats are explained at www.degreedays.net/regression
System.out.println("R-squared = " + chosen.rSquared());
System.out.println("Adjusted R-squared = " + chosen.adjustedRSquared());
System.out.println("Cross-validated R-squared = " +
        chosen.crossValidatedRSquared());
System.out.println("Standard error = " + chosen.standardError());
System.out.println("CVRMSE = " + chosen.cvrmse());
// This continues on from the C# request sample near the top of the page at
// www.degreedays.net/api/regression
// So we already have our RegressionResponse object (response) from that.

Console.Out.WriteLine("Weather station for degree days: " + response.StationId);

// In the usual case the response will contain a list of the most promising or
// notable regressions out of the thousands tested by the API.
// Though the line below could throw a SourceDataException if your specified
// location did not have enough good weather data for the API to generate the
// degree days necessary to run regressions against your InputData.
ICollection<Regression> regressions = response.GetRegressions();

// The regression listed first is the one with the best stats.  If you know
// nothing about the building, its likely base temperature(s), or whether its
// energy-usage data covers heating, cooling, or both, the first regression is
// probably the best choice.  But, if you know more, your code could look
// through all the regressions with .HasTag(RegressionTag.Shortlist) to make a
// more informed choice.  For more on choosing the best regression, see
// www.degreedays.net/regression
Regression chosen = regressions.First();

// Each Regression object contains lots of data.  We reconstruct the regression
// equation to show you how to access the coefficients and degree-day base
// temperature(s):
Console.Out.WriteLine("E = " +
        chosen.Baseload.Coefficient +
        (chosen.Baseload.MultiplyByNumberOfDays ? "*days" : ""));
if (chosen.HasHeatingDegreeDays) {
    DegreeDaysRegressionComponent hddComponent =
            chosen.GetHeatingDegreeDays();
    Console.Out.WriteLine("  + " + hddComponent.Coefficient +
            "*HDD (base temperature " + hddComponent.BaseTemperature + ")");
}
if (chosen.HasCoolingDegreeDays) {
    DegreeDaysRegressionComponent cddComponent =
            chosen.GetCoolingDegreeDays();
    Console.Out.WriteLine("  + " + cddComponent.Coefficient +
            "*CDD (base temperature " + cddComponent.BaseTemperature + ")");
}

// We also output some of the additional data to show you what is available in
// each Regression object:

// SampleSize is the number of energy-usage figures used for the regression.
// This could be less than the number of input periods included in your request,
// if the location could not provide enough weather data to cover all of them.
Console.Out.WriteLine("Sample size = " + chosen.SampleSize);
// SampleDays is the number of days covered by the sample, excluding any gaps
// between input periods.
Console.Out.WriteLine("Sample days = " + chosen.SampleDays);
// SampleSpan is a DayRange object.
Console.Out.WriteLine("Sample span = " + chosen.SampleSpan);
// SampleSpanDays will include any gaps between input periods.
Console.Out.WriteLine("Sample span days = " + chosen.SampleSpanDays);
// The stats are explained at www.degreedays.net/regression
Console.Out.WriteLine("R-squared = " + chosen.RSquared);
Console.Out.WriteLine("Adjusted R-squared = " + chosen.AdjustedRSquared);
Console.Out.WriteLine("Cross-validated R-squared = " +
        chosen.CrossValidatedRSquared);
Console.Out.WriteLine("Standard error = " + chosen.StandardError);
Console.Out.WriteLine("CVRMSE = " + chosen.Cvrmse);
' This continues on from the C# request sample near the top of the page at
' www.degreedays.net/api/regression
' So we already have our RegressionResponse object (response) from that.

Console.Out.WriteLine("Weather station for degree days: " + response.StationId)

' In the usual case the response will contain a list of the most promising or
' notable regressions out of the thousands tested by the API.
' Though the line below could throw a SourceDataException if your specified
' location did not have enough good weather data for the API to generate the
' degree days necessary to run regressions against your InputData.
Dim regressions as ICollection(Of Regression) = response.GetRegressions()

' The regression listed first is the one with the best stats.  If you know
' nothing about the building, its likely base temperature(s), or whether its
' energy-usage data covers heating, cooling, or both, the first regression is
' probably the best choice.  But, if you know more, your code could look
' through all the regressions with .HasTag(RegressionTag.Shortlist) to make a
' more informed choice.  For more on choosing the best regression, see
' www.degreedays.net/regression
Dim chosen As Regression = regressions.First()

' Each Regression object contains lots of data.  We reconstruct the regression
' equation to show you how to access the coefficients and degree-day base
' temperature(s):
Console.Out.WriteLine("E = " &
    chosen.Baseload.Coefficient &
    If(chosen.Baseload.MultiplyByNumberOfDays, "*days", ""))
if chosen.HasHeatingDegreeDays Then
    Dim hddComponent As DegreeDaysRegressionComponent =
            chosen.GetHeatingDegreeDays()
    Console.Out.WriteLine("  + " & hddComponent.Coefficient &
            "*HDD (base temperature " &
            hddComponent.BaseTemperature.ToString() & ")")
End If
if chosen.HasCoolingDegreeDays Then
    Dim cddComponent As DegreeDaysRegressionComponent =
            chosen.GetCoolingDegreeDays()
    Console.Out.WriteLine("  + " & cddComponent.Coefficient &
            "*CDD (base temperature " &
            cddComponent.BaseTemperature.ToString() & ")")
End If

' We also output some of the additional data to show you what is available in
' each Regression object:

' SampleSize is the number of energy-usage figures used for the regression.
' This could be less than the number of input periods included in your request,
' if the location could not provide enough weather data to cover all of them.
Console.Out.WriteLine("Sample size = " & chosen.SampleSize)
' SampleDays is the number of days covered by the sample, excluding any gaps
' between input periods.
Console.Out.WriteLine("Sample days = " & chosen.SampleDays)
' SampleSpan is a DayRange object.
Console.Out.WriteLine("Sample span = " & chosen.SampleSpan.ToString())
' SampleSpanDays will include any gaps between input periods.
Console.Out.WriteLine("Sample span days = " & chosen.SampleSpanDays)
' The stats are explained at www.degreedays.net/regression
Console.Out.WriteLine("R-squared = " & chosen.RSquared)
Console.Out.WriteLine("Adjusted R-squared = " & chosen.AdjustedRSquared)
Console.Out.WriteLine("Cross-validated R-squared = " &
        chosen.CrossValidatedRSquared)
Console.Out.WriteLine("Standard error = " & chosen.StandardError)
Console.Out.WriteLine("CVRMSE = " & chosen.Cvrmse)
# This continues on from the Python request sample near the top of the page at
# www.degreedays.net/api/regression
# So we already have our RegressionResponse object (response) from that.

print('Weather station for degree days: ' + response.stationId)

# In the usual case the response will contain a list of the most promising or
# notable regressions out of the thousands tested by the API.
# Though the line below could throw a SourceDataError if your specified
# location did not have enough good weather data for the API to generate the
# degree days necessary to run regressions against your InputData.
regressions = response.getRegressions()

# The regression listed first is the one with the best stats.  If you know
# nothing about the building, its likely base temperature(s), or whether its
# energy-usage data covers heating, cooling, or both, the first regression is
# probably the best choice.  But, if you know more, your code could look
# through all the regressions with .hasTag(RegressionTag.SHORTLIST) to make a
# more informed choice.  For more on choosing the best regression, see
# www.degreedays.net/regression
chosen = regressions[0]

# Each Regression object contains lots of data.  We reconstruct the regression
# equation to show you how to access the coefficients and degree-day base
# temperature(s):
print('E = %g%s' % (chosen.baseload.coefficient,
    '*days' if chosen.baseload.multiplyByNumberOfDays else ''))
if chosen.heatingDegreeDaysOrNone is not None:
    hddComponent = chosen.heatingDegreeDaysOrNone
    print('  + %g*HDD (base temperature %s)' %
        (hddComponent.coefficient, hddComponent.baseTemperature))
if chosen.coolingDegreeDaysOrNone is not None:
    cddComponent = chosen.coolingDegreeDaysOrNone
    print('  + %g*CDD (base temperature %s)' %
        (cddComponent.coefficient, cddComponent.baseTemperature))

# We also output some of the additional data to show you what is available in
# each Regression object:

# sampleSize is the number of energy-usage figures used for the regression.
# This could be less than the number of input periods included in your request,
# if the location could not provide enough weather data to cover all of them.
print('Sample size = %d' % chosen.sampleSize)
# sampleDays is the number of days covered by the sample, excluding any gaps
# between input periods.
print('Sample days = %d' % chosen.sampleDays)
# sampleSpan is a DayRange object.
print('Sample span = %s' % chosen.sampleSpan)
# sampleSpanDays will include any gaps between input periods.
print('Sample span days = %d' % chosen.sampleSpanDays)
# The stats are explained at www.degreedays.net/regression
print('R-squared = %g' % chosen.rSquared)
print('Adjusted R-squared = %g' % chosen.adjustedRSquared)
print('Cross-validated R-squared = %g' % chosen.crossValidatedRSquared)
print('Standard error = %g' % chosen.standardError)
print('CVRMSE = %g' % chosen.cvrmse)

Just a reminder: if you're looking at all the data above and wondering what the point of it is, we have a useful summary at the top of this page, and links to more information so you can understand why regression of energy data and degree days is important and how you can best make use of it. It also helps to play with our online regression tool which is effectively just a UI on top of the regression API detailed on this page.

Back to top

Error handling

Naturally we would love for all your regression requests to be entirely successful, but, for robust software, it is good to be prepared for the various things that can go wrong:

Request failure

The entire request can fail for several different reasons:

{
    // Note how the "metadata" comes through as usual even though the request
    // failed.  This is expected, you can rely on the "metadata" being there.
    "metadata": {
        "rateLimit": {
            "requestUnitsAvailable": 1954,
            "minutesToReset": 11
        }
    },
    // Note how the "response" property is an object of type "Failure" rather
    // than the "RegressionResponse" you'd usually expect.
    "response": {
        "type": "Failure",
        // "LocationNotRecognized" is just one of many failure codes you might
        // receive.  The main JSON docs at www.degreedays.net/api/json#failure
        // explain more.
        "code": "LocationNotRecognized",
        "message": "Sorry, we do not recognize the location that you specified.  Our postal-code database did not recognize the specified PostalCodeLocation, and was consequently unable to find its longitude/latitude position."
    }
}
<Response>
  
  <!-- Note how the Metadata comes through as usual even though the request
  failed.  This is expected, you can rely on the Metadata being there. -->
  <Metadata>
    <RateLimit>
      <RequestUnitsAvailable>1954</RequestUnitsAvailable>
      <MinutesToReset>11</MinutesToReset>
    </RateLimit>
  </Metadata>
  
  <!-- Note how there's a Failure here instead of the RegressionResponse you'd
  usually expect. -->
  <Failure>
    <!-- "LocationNotRecognized" is just one of the many failure codes you might
    receive.  The main XML docs at www.degreedays.net/api/xml#failure explain
    more. -->
    <Code>LocationNotRecognized</Code>
    <Message>Sorry, we do not recognize the location that you specified.  Our
    postal-code database did not recognize the specified PostalCodeLocation, and
    was consequently unable to find its longitude/latitude position.</Message>
  </Failure>
  
</Response>
// The call to runRegressions can throw a variety of exceptions.  All are
// subclasses of DegreeDaysApiException.  Which, if any, you'll want to catch
// explicitly will depend on your application.  The notes at
// www.degreedays.net/api/java are relevant and useful, as are the javadoc at
// https://javadoc.degreedays.net/net/degreedays/api/regression/RegressionApi#runRegressions(net.degreedays.api.regression.RegressionRequest)
RegressionResponse response = api.regressionApi().runRegressions(request);
// The call to RunRegressions can throw a variety of exceptions.  All are
// subclasses of DegreeDaysApiException.  Which, if any, you'll want to catch
// explicitly will depend on your application.  The notes at
// www.degreedays.net/api/dotnet are relevant and useful, as are the docs at
// https://dotnet.degreedays.net/M_DegreeDays_Api_Regressions_RegressionApi_RunRegressions
RegressionResponse response = api.RegressionApi.RunRegressions(request);
' The call to RunRegressions can throw a variety of exceptions.  All are
' subclasses of DegreeDaysApiException.  Which, if any, you'll want to catch
' explicitly will depend on your application.  The notes at
' www.degreedays.net/api/dotnet are relevant and useful, as are the docs at
' https://dotnet.degreedays.net/M_DegreeDays_Api_Regressions_RegressionApi_RunRegressions
Dim response As RegressionResponse = api.RegressionApi.RunRegressions(request)
# The call to runRegressions can throw a variety of exceptions.  All are
# subclasses of DegreeDaysApiError.  Which, if any, you'll want to catch
# explicitly will depend on your application.  The notes at
# www.degreedays.net/api/python#failure are relevant and useful.
response = api.regressionApi.runRegressions(request)

In virtually all respects the errors you can expect are the same as those you can expect for LocationDataRequest, and which, if any, you should handle explicitly, will depend on the nature of your application. See the relevant docs for JSON, XML, Java, .NET, Python.

Insufficient weather data to run regressions

To run regressions against your input data, the API needs to generate degree days to match its dates. If the location you specify in your RegressionRequest does not have sufficient weather data for the API to do this, you will get a response with details of the weather station, but without any regressions (or degree days):

{
    "metadata": {
        // present as usual, but omitted here for clarity
    },
    "response": {
        "type": "RegressionResponse",
        // "stationId", "targetLongLat", and "sources" will be present as usual
        // as the API did find a working weather station, it's just that it
        // didn't have enough data to fulfil the request.
        "stationId": "KHYA",
        "targetLongLat": {
            // present as usual, but omitted for clarity
        },
        "sources": [
            // present as usual, but omitted for clarity
        ],
        // This "failure" appears instead of "dataSets" and "regressions":
        "failure": {
            "type": "Failure",
            "code": "SourceDataCoverage",
            "message": "Sorry, the source does not have enough recorded temperature readings for us to be able to generate degree days to run regressions against your specified input data."
        }
    }
}
<Response>
  
  <Metadata>
    <!-- present as usual, but omitted here for clarity -->
  </Metadata>
  
  <RegressionResponse>
    
    <Head>
      <!-- The StationId, TargetLocation, and Sources will be present as usual
      as the API did find a working weather swtation, it's just that it didn't
      have enough data to fulfil the request. -->
      <StationId>KHYA</StationId>
      <TargetLocation>
        <!-- present as usual, but omitted for clarity -->
      </TargetLocation>
      <Sources>
        <!-- present as usual, but omitted for clarity -->
      </Sources>
    </Head>
    
    <!-- This Failure appears instead of DataSets and Regressions: -->
    <Failure>
      <Code>SourceDataCoverage</Code>
      <Message>Sorry, the source does not have enough recorded temperature
      readings for us to be able to generate degree days to run regressions
      against your specified input data.</Message>
    </Failure>
    
  </RegressionResponse>
  
</Response>
// If your specified location does not have enough weather data for the API to
// generate degree days to run regressions against your input data, you will get
// a response just fine...
RegressionResponse response = api.regressionApi().runRegressions(request);
// And you will be able to get the location-related details like...
System.out.println("Station ID: " + response.stationId());
System.out.println("Target LongLat: " + response.targetLongLat());
// But calling getRegressions() will throw a SourceDataException.
List<Regression> regressions = response.getRegressions();
// If your specified location does not have enough weather data for the API to
// generate degree days to run regressions against your input data, you will get
// a response just fine...
RegressionResponse response = api.RegressionApi.RunRegressions(request);
// And you will be able to get the location-related details like...
Console.Out.WriteLine("Station ID: " + response.StationId);
Console.Out.WriteLine("Target LongLat: " + response.TargetLongLat);
// But calling GetRegressions() will throw a SourceDataException.
ICollection<Regression> regressions = response.GetRegressions();
' If your specified location does not have enough weather data for the API to
' generate degree days to run regressions against your input data, you will get
' a response just fine...
Dim response As RegressionResponse = api.RegressionApi.RunRegressions(request)
' And you will be able to get the location-related details like...
Console.Out.WriteLine("Station ID: " & response.StationId)
Console.Out.WriteLine("Target LongLat: " & response.TargetLongLat.ToString())
' But calling GetRegressions() will throw a SourceDataException.
Dim regressions As ICollection(Of Regression) = response.GetRegressions()
# If your specified location does not have enough weather data for the API to
# generate degree days to run regressions against your input data, you will get
# a response just fine...
response = api.regressionApi.runRegressions(request)
# And you will be able to get the location-related details like...
print('Station ID: %s' % response.stationId)
print('Target LongLat: %s' % response.targetLongLat)
# But calling getRegressions() will throw a SourceDataError.
regressions = response.getRegressions()

Regressions not covering all of your input data

This is not an error as such, but it's something to watch out for. If the location you specify in your RegressionRequest does not have sufficient weather data for the API to run regressions against your full input data, it may still be able to run regressions against part of it. You can check the sample size and the sample span in the response to see if this has happened.

This is unlikely to happen unless you are trying to run regressions against very old energy data, or very recent energy data e.g. that includes a day that finished in the last hour or two (see the FAQ on accessing the most recent energy data).

Back to top

Controlling the HDD and CDD base temperatures tested

By default the API will test thousands of regressions against your energy data, testing HDD, CDD, and HDD+CDD (multiple regression), in a wide range of base temperatures chosen automatically. This is typically the best way to find the optimal regression model for a building, but you might sometimes want more control over the base temperatures tested. The main reason is if you are fetching and storing degree days in a set range of base temperatures, and you want to ensure that the API will return only regressions with HDD/CDD base temperatures that you have data stored for.

The example code below shows the various ways you can control the HDD/CDD base temperatures tested, via your configuration of the RegressionTestPlan:

// The first example shows the default case in which no custom base temperatures
// are specified.  This instructs the API to test regressions with HDD, CDD, and
// HDD+CDD, using a wide range of base temperatures chosen automatically:
"regressionTestPlan": {
    "temperatureUnit": "C",
    "dayNormalization": "Weighted"
}

// The following example instructs the API to test regressions with HDD, CDD,
// and HDD+CDD, using HDD and CDD in the base temperatures specified (up to a
// maximum of 120 in total):
"regressionTestPlan": {
    "temperatureUnit": "C",
    "dayNormalization": "Weighted",
    // The test base temperatures are in the temperatureUnit specified above.
    "customTestHeatingBaseTemperatures": [10, 12, 14, 16, 18, 20],
    "customTestCoolingBaseTemperatures": [18, 20, 22, 24, 26]
}

// The following example instructs the API to test regressions with HDD, CDD,
// and HDD+CDD, specifying up to 60 HDD base temperatures to be tested, and
// leaving the API to choose the CDD base temperatures to test automatically:
"regressionTestPlan": {
    "temperatureUnit": "F",
    "dayNormalization": "Weighted",
    "customTestHeatingBaseTemperatures": [55, 60, 65, 70]
    // "customTestCoolingBaseTemperatures" is omitted, so the API will test a
    // wide range of CDD base temperatures chosen automatically.
}

// The following example instructs the API to test CDD only, in a wide range of
// base temperatures chosen automatically:
"regressionTestPlan": {
    "temperatureUnit": "C",
    "dayNormalization": "Weighted",
    // The empty array below specifies that no HDD should be tested:
    "customTestHeatingBaseTemperatures": []
}

// The following example instructs the API to test HDD only, specifying up to
// 120 base temperatures to be tested:
"regressionTestPlan": {
    "temperatureUnit": "C",
    "dayNormalization": "Weighted",
    "customTestHeatingBaseTemperatures": [10, 11, 12, 13, 14, 15, 16, 17, 18],
    // The empty array below specifies that no CDD should be tested:
    "customTestCoolingBaseTemperatures": []
}
<!-- The first example shows the default case in which no custom base
temperatures are specified.  This instructs the API to test regressions with
HDD, CDD, and  HDD+CDD, using a wide range of base temperatures chosen
automatically: -->
<RegressionTestPlan>
  <TemperatureUnit>Celsius</TemperatureUnit>
  <DayNormalization>Weighted</DayNormalization>
</RegressionTestPlan>

<!-- The following example instructs the API to test regressions with HDD, CDD,
and HDD+CDD, using HDD and CDD in the base temperatures specified (up to a
maximum of 120 in total): -->
<RegressionTestPlan>
  <TemperatureUnit>Celsius</TemperatureUnit>
  <DayNormalization>Weighted</DayNormalization>
  <CustomTestHeatingBaseTemperatures>
    <T>10</T>
    <T>12</T>
    <T>14</T>
    <T>16</T>
    <T>18</T>
    <T>20</T>
  </CustomTestHeatingBaseTemperatures>
  <CustomTestCoolingBaseTemperatures>
    <T>18</T>
    <T>20</T>
    <T>22</T>
    <T>24</T>
    <T>26</T>
  </CustomTestCoolingBaseTemperatures>
</RegressionTestPlan>

<!-- The following example instructs the API to test regressions with HDD, CDD,
and HDD+CDD, specifying up to 60 HDD base temperatures to be tested, and leaving
the API to choose the CDD base temperatures to test automatically: -->
<RegressionTestPlan>
  <TemperatureUnit>Fahrenheit</TemperatureUnit>
  <DayNormalization>Weighted</DayNormalization>
  <CustomTestHeatingBaseTemperatures>
    <T>55</T>
    <T>60</T>
    <T>65</T>
    <T>70</T>
  </CustomTestHeatingBaseTemperatures>
  <!-- CustomTestCoolingBaseTemperatures is omitted, so the API will test a wide
  range of CDD base temperatures chosen automatically. -->
</RegressionTestPlan>

<!-- The following example instructs the API to test CDD only, in a wide range
of base temperatures chosen automatically: -->
<RegressionTestPlan>
  <TemperatureUnit>Celsius</TemperatureUnit>
  <DayNormalization>Weighted</DayNormalization>
  <!-- The empty array below specifies that no HDD should be tested: -->
  <CustomTestHeatingBaseTemperatures/>
</RegressionTestPlan>

<!-- The following example instructs the API to test HDD only, specifying up to
120 base temperatures to be tested: -->
<RegressionTestPlan>
  <TemperatureUnit>Celsius</TemperatureUnit>
  <DayNormalization>Weighted</DayNormalization>
  <CustomTestHeatingBaseTemperatures>
    <T>10</T>
    <T>11</T>
    <T>12</T>
    <T>13</T>
    <T>14</T>
    <T>15</T>
    <T>16</T>
    <T>17</T>
    <T>18</T>
  </CustomTestHeatingBaseTemperatures>
  <!-- The empty array below specifies that no CDD should be tested: -->
  <CustomTestCoolingBaseTemperatures/>
</RegressionTestPlan>
// The first example shows the default case in which no custom base temperatures
// are specified.  This instructs the API to test regressions with HDD, CDD, and
// HDD+CDD, using a wide range of base temperatures chosen automatically:
new RegressionTestPlan.Builder(TemperatureUnit.CELSIUS)
    .build();

// The following example instructs the API to test regressions with HDD, CDD,
// and HDD+CDD, using HDD and CDD in the base temperatures specified (up to a
// maximum of 120 in total):
new RegressionTestPlan.Builder(TemperatureUnit.CELSIUS)
    // The test base temperatures are in the TemperatureUnit specified above.
    .setCustomTestHeatingBaseTemperatures(10, 12, 14, 16, 18, 20)
    .setCustomTestCoolingBaseTemperatures(18, 20, 22, 24, 26)
    .build();

// The following example instructs the API to test regressions with HDD, CDD,
// and HDD+CDD, specifying up to 60 HDD base temperatures to be tested, and
// leaving the API to choose the CDD base temperatures to test automatically:
new RegressionTestPlan.Builder(TemperatureUnit.FAHRENHEIT)
    .setCustomTestHeatingBaseTemperatures(55, 60, 65, 70)
    // setCustomTestCoolingBaseTemperatures is not called, so the API will test
    // a wide range of CDD base temperatures chosen automatically.
    .build();

// The following example instructs the API to test CDD only, in a wide range of
// base temperatures chosen automatically:
new RegressionTestPlan.Builder(TemperatureUnit.CELSIUS)
    // Passing zero arguments below specifies that no HDD should be tested:
    .setCustomTestHeatingBaseTemperatures()
    .build();

// The following example instructs the API to test HDD only, specifying up to
// 120 base temperatures to be tested:
new RegressionTestPlan.Builder(TemperatureUnit.CELSIUS)
    .setCustomTestHeatingBaseTemperatures(10, 11, 12, 13, 14, 15, 16, 17, 18)
    // Passing zero arguments below specifies that no CDD should be tested:
    .setCustomTestCoolingBaseTemperatures()
    .build();

// The following example shows a convenient way to specify a range of test base
// temperatures, in this case running from 15 C to 25 C (inclusive), with a step
// of 0.5 C between each (so 15, 15.5, 16, 16.5, through to 25 C):
new RegressionTestPlan.Builder(TemperatureUnit.CELSIUS)
    .setCustomTestCoolingBaseTemperatures(Temperature.celsiusRange(15, 25, 0.5))
    // setCustomTestHeatingBaseTemperatures is not called, so the API will test
    // a wide range of HDD base temperatures chosen automatically.
    .build();
// The first example shows the default case in which no custom base temperatures
// are specified.  This instructs the API to test regressions with HDD, CDD, and
// HDD+CDD, using a wide range of base temperatures chosen automatically:
new RegressionTestPlan.Builder(TemperatureUnit.Celsius)
    .Build();

// The following example instructs the API to test regressions with HDD, CDD,
// and HDD+CDD, using HDD and CDD in the base temperatures specified (up to a
// maximum of 120 in total):
new RegressionTestPlan.Builder(TemperatureUnit.Celsius)
    // The test base temperatures are in the TemperatureUnit specified above.
    .SetCustomTestHeatingBaseTemperatures(10, 12, 14, 16, 18, 20)
    .SetCustomTestCoolingBaseTemperatures(18, 20, 22, 24, 26)
    .Build();

// The following example instructs the API to test regressions with HDD, CDD,
// and HDD+CDD, specifying up to 60 HDD base temperatures to be tested, and
// leaving the API to choose the CDD base temperatures to test automatically:
new RegressionTestPlan.Builder(TemperatureUnit.Fahrenheit)
    .SetCustomTestHeatingBaseTemperatures(55, 60, 65, 70)
    // SetCustomTestCoolingBaseTemperatures is not called, so the API will test
    // a wide range of CDD base temperatures chosen automatically.
    .Build();

// The following example instructs the API to test CDD only, in a wide range of
// base temperatures chosen automatically:
new RegressionTestPlan.Builder(TemperatureUnit.Celsius)
    // Passing zero arguments below specifies that no HDD should be tested:
    .SetCustomTestHeatingBaseTemperatures()
    .Build();

// The following example instructs the API to test HDD only, specifying up to
// 120 base temperatures to be tested:
new RegressionTestPlan.Builder(TemperatureUnit.Celsius)
    .SetCustomTestHeatingBaseTemperatures(10, 11, 12, 13, 14, 15, 16, 17, 18)
    // Passing zero arguments below specifies that no CDD should be tested:
    .SetCustomTestCoolingBaseTemperatures()
    .Build();

// The following example shows a convenient way to specify a range of test base
// temperatures, in this case running from 15 C to 25 C (inclusive), with a step
// of 0.5 C between each (so 15, 15.5, 16, 16.5, through to 25 C):
new RegressionTestPlan.Builder(TemperatureUnit.Celsius)
    .SetCustomTestCoolingBaseTemperatures(Temperature.CelsiusRange(15, 25, 0.5))
    // SetCustomTestHeatingBaseTemperatures is not called, so the API will test
    // a wide range of HDD base temperatures chosen automatically.
    .Build();
' The first example shows the default case in which no custom base temperatures
' are specified.  This instructs the API to test regressions with HDD, CDD, and
' HDD+CDD, Imports a wide range of base temperatures chosen automatically:
Dim testPlan = New RegressionTestPlan.Builder(TemperatureUnit.Celsius) _
    .Build()

' The following example instructs the API to test regressions with HDD, CDD,
' and HDD+CDD, Imports HDD and CDD in the base temperatures specified (up to a
' maximum of 120 in total):
testPlan = New RegressionTestPlan.Builder(TemperatureUnit.Celsius) _
    _' The test base temperatures are in the TemperatureUnit specified above.
    .SetCustomTestHeatingBaseTemperatures(10, 12, 14, 16, 18, 20) _
    .SetCustomTestCoolingBaseTemperatures(18, 20, 22, 24, 26) _
    .Build()

' The following example instructs the API to test regressions with HDD, CDD,
' and HDD+CDD, specifying up to 60 HDD base temperatures to be tested, and
' leaving the API to choose the CDD base temperatures to test automatically:
testPlan = New RegressionTestPlan.Builder(TemperatureUnit.Fahrenheit) _
    .SetCustomTestHeatingBaseTemperatures(55, 60, 65, 70) _
    _' SetCustomTestCoolingBaseTemperatures is not called, so the API will test
    _' a wide range of CDD base temperatures chosen automatically.
    .Build()

' The following example instructs the API to test CDD only, in a wide range of
' base temperatures chosen automatically:
testPlan = New RegressionTestPlan.Builder(TemperatureUnit.Celsius) _
    _' Passing zero arguments below specifies that no HDD should be tested:
    .SetCustomTestHeatingBaseTemperatures() _
    .Build()

' The following example instructs the API to test HDD only, specifying up to
' 120 base temperatures to be tested:
testPlan = New RegressionTestPlan.Builder(TemperatureUnit.Celsius) _
    .SetCustomTestHeatingBaseTemperatures(10, 11, 12, 13, 14, 15, 16, 17, 18) _
    _' Passing zero arguments below specifies that no CDD should be tested:
    .SetCustomTestCoolingBaseTemperatures() _
    .Build()

' The following example shows a convenient way to specify a range of test base
' temperatures, in this case running from 15 C to 25 C (inclusive), with a step
' of 0.5 C between each (so 15, 15.5, 16, 16.5, through to 25 C):
testPlan = New RegressionTestPlan.Builder(TemperatureUnit.Celsius) _
    .SetCustomTestCoolingBaseTemperatures(Temperature.CelsiusRange(15, 25, 0.5)) _
    _' SetCustomTestHeatingBaseTemperatures is not called, so the API will test
    _' a wide range of HDD base temperatures chosen automatically.
    .Build()
# The first example shows the default case in which no custom base temperatures
# are specified.  This instructs the API to test regressions with HDD, CDD, and
# HDD+CDD, using a wide range of base temperatures chosen automatically:
RegressionTestPlan(TemperatureUnit.CELSIUS)

# The following example instructs the API to test regressions with HDD, CDD,
# and HDD+CDD, using HDD and CDD in the base temperatures specified (up to a
# maximum of 120 in total):
RegressionTestPlan(TemperatureUnit.CELSIUS,
    # The test base temperatures are in the TemperatureUnit specified above.
    customTestHeatingBaseTemperaturesOrNone=(10, 12, 14, 16, 18, 20),
    customTestCoolingBaseTemperaturesOrNone=(18, 20, 22, 24, 26))

# The following example instructs the API to test regressions with HDD, CDD,
# and HDD+CDD, specifying up to 60 HDD base temperatures to be tested, and
# leaving the API to choose the CDD base temperatures to test automatically:
RegressionTestPlan(TemperatureUnit.FAHRENHEIT,
    customTestHeatingBaseTemperaturesOrNone=(55, 60, 65, 70))
    # customTestCoolingBaseTemperaturesOrNone is not specified, so it will have
    # its default value of None, and the API will test a wide range of CDD base
    # temperatures chosen automatically.

# The following example instructs the API to test CDD only, in a wide range of
# base temperatures chosen automatically:
RegressionTestPlan(TemperatureUnit.CELSIUS,
    # Passing an empty tuple below specifies that no HDD should be tested:
    customTestHeatingBaseTemperaturesOrNone=())

# The following example instructs the API to test HDD only, specifying up to
# 120 base temperatures to be tested:
RegressionTestPlan(TemperatureUnit.CELSIUS,
    customTestHeatingBaseTemperaturesOrNone=(10, 11, 12, 13, 14, 15, 16, 17, 18),
    # Passing an empty tuple below specifies that no CDD should be tested:
    customTestCoolingBaseTemperaturesOrNone=())

# The following example shows a convenient way to specify a range of test base
# temperatures, in this case running from 15 C to 25 C (inclusive), with a step
# of 0.5 C between each (so 15, 15.5, 16, 16.5, through to 25 C):
RegressionTestPlan(TemperatureUnit.CELSIUS,
    customTestCoolingBaseTemperaturesOrNone=Temperature.celsiusRange(15, 25, 0.5))
    # customTestHeatingBaseTemperaturesOrNone is not specified, so it will have
    # its default value of None, and the API will test a wide range of HDD base
    # temperatures chosen automatically.

Back to top

Requesting specific regressions to be returned

In the RegressionTestPlan you can also request specific regressions that you want the API to test and return. As the API will, by default, test thousands of different regressions (with different HDD/CDD base temperatures) automatically, quite likely it will test your specified regressions anyway, but it probably wouldn't return them by default, unless they happened to have particularly good stats. Requesting them specifically ensures that they are tested and returned.

If you define empty custom HDD and CDD base temperatures, you can also make the API test and return only the regressions you specify (up to 12).

Both these use cases are shown in the examples below:

// This first example shows how we can specify up to 60 particular regressions
// that we want to be tested and returned alongside the ones returned
// automatically:
"regressionTestPlan": {
    "temperatureUnit": "C",
    "dayNormalization": "Weighted",
    "requestedRegressionSpecs": [
        // Specify a regression with baseload (always present) and HDD:
        {
            // Temperatures are in the temperatureUnit specified above.
            "heatingBaseTemperature": 15.5
        },
        // Specify a regression with baseload (always present), HDD, and CDD:
        {    
            "heatingBaseTemperature": 14,
            "coolingBaseTemperature": 21
        }
    ]
}

// This second example shows how we can define empty custom HDD and CDD base
// temperatures to get the API to test only the exact regressions we specify:
"regressionTestPlan": {
    "temperatureUnit": "F",
    "dayNormalization": "Weighted",
    "customTestHeatingBaseTemperatures": [],
    "customTestCoolingBaseTemperatures": [],
    "requestedRegressionSpecs": [
        {
            "heatingBaseTemperature": 60
        },
        {
            "coolingBaseTemperature": 70
        },
        {    
            "heatingBaseTemperature": 60,
            "coolingBaseTemperature": 70
        }
    ]
}
<!-- This first example shows how we can specify up to 60 particular regressions
that we want to be tested and returned alongside the ones returned
automatically: -->
<RegressionTestPlan>
  <TemperatureUnit>Celsius</TemperatureUnit>
  <DayNormalization>Weighted</DayNormalization>
  <RequestedRegressionSpecs>
    <!-- Specify a regression with baseload (always present) and HDD: -->
    <RegressionSpec>
      <HeatingBaseTemperature>15.5</HeatingBaseTemperature>
    </RegressionSpec>
    <!-- Specify a regression with baseload (always present), HDD, and CDD: -->
    <RegressionSpec>
      <HeatingBaseTemperature>14</HeatingBaseTemperature>
      <CoolingBaseTemperature>21</CoolingBaseTemperature>
    </RegressionSpec>
  </RequestedRegressionSpecs>
</RegressionTestPlan>

<!-- This second example shows how we can define empty custom HDD and CDD base
temperatures to get the API to test only the exact regressions we specify: -->
<RegressionTestPlan>
  <TemperatureUnit>Fahrenheit</TemperatureUnit>
  <DayNormalization>Weighted</DayNormalization>
  <CustomTestHeatingBaseTemperatures/>
  <CustomTestCoolingBaseTemperatures/>
  <RequestedRegressionSpecs>
    <RegressionSpec>
      <HeatingBaseTemperature>60</HeatingBaseTemperature>
    </RegressionSpec>
    <RegressionSpec>
      <CoolingBaseTemperature>70</CoolingBaseTemperature>
    </RegressionSpec>
    <RegressionSpec>
      <HeatingBaseTemperature>60</HeatingBaseTemperature>
      <CoolingBaseTemperature>70</CoolingBaseTemperature>
    </RegressionSpec>
  </RequestedRegressionSpecs>
</RegressionTestPlan>
// This first example shows how we can specify up to 60 particular regressions
// that we want to be tested and returned alongside the ones returned
// automatically:
new RegressionTestPlan.Builder(TemperatureUnit.CELSIUS)
    .setRequestedRegressionSpecs(
        // Specify a regression with baseload (always present) and HDD (with
        // a base temperature defined in the units of the RegressionTestPlan):
        RegressionSpec.baseload()
            .withHeating(Temperature.celsius(15.5)),
        // Specify a regression with baseload (always present), HDD, and CDD:
        RegressionSpec.baseload()
            .withHeating(Temperature.celsius(14))
            .withCooling(Temperature.celsius(21)))
    .build();

// This second example shows how we can define empty custom HDD and CDD base
// temperatures to get the API to test only the exact regressions we specify:
new RegressionTestPlan.Builder(TemperatureUnit.FAHRENHEIT)
    .setCustomTestHeatingBaseTemperatures()
    .setCustomTestCoolingBaseTemperatures()
    .setRequestedRegressionSpecs(
        RegressionSpec.baseload()
            .withHeating(Temperature.fahrenheit(60)),
        RegressionSpec.baseload()
            .withCooling(Temperature.fahrenheit(70)),
        RegressionSpec.baseload()
            .withHeating(Temperature.fahrenheit(60))
            .withCooling(Temperature.fahrenheit(70)))
    .build();
// This first example shows how we can specify up to 60 particular regressions
// that we want to be tested and returned alongside the ones returned
// automatically:
new RegressionTestPlan.Builder(TemperatureUnit.Celsius)
    .SetRequestedRegressionSpecs(
        // Specify a regression with baseload (always present) and HDD (with
        // a base temperature defined in the units of the RegressionTestPlan):
        RegressionSpec.Baseload
            .WithHeating(Temperature.Celsius(15.5)),
        // Specify a regression with baseload (always present), HDD, and CDD:
        RegressionSpec.Baseload
            .WithHeating(Temperature.Celsius(14))
            .WithCooling(Temperature.Celsius(21)))
    .Build();

// This second example shows how we can define empty custom HDD and CDD base
// temperatures to get the API to test only the exact regressions we specify:
new RegressionTestPlan.Builder(TemperatureUnit.Fahrenheit)
    .SetCustomTestHeatingBaseTemperatures()
    .SetCustomTestCoolingBaseTemperatures()
    .SetRequestedRegressionSpecs(
        RegressionSpec.Baseload
            .WithHeating(Temperature.Fahrenheit(60)),
        RegressionSpec.Baseload
            .WithCooling(Temperature.Fahrenheit(70)),
        RegressionSpec.Baseload
            .WithHeating(Temperature.Fahrenheit(60))
            .WithCooling(Temperature.Fahrenheit(70)))
    .Build();
' This first example shows how we can specify up to 60 particular regressions
' that we want to be tested and returned alongside the ones returned
' automatically:
testPlan = New RegressionTestPlan.Builder(TemperatureUnit.Celsius) _
    .SetRequestedRegressionSpecs(
        _' Specify a regression with baseload (always present) and HDD (with
        _' a base temperature defined in the units of the RegressionTestPlan):
        RegressionSpec.Baseload _
            .WithHeating(Temperature.Celsius(15.5)),
        _' Specify a regression with baseload (always present), HDD, and CDD:
        RegressionSpec.Baseload _
            .WithHeating(Temperature.Celsius(14)) _
            .WithCooling(Temperature.Celsius(21))) _
    .Build()

' This second example shows how we can define empty custom HDD and CDD base
' temperatures to get the API to test only the exact regressions we specify:
testPlan = New RegressionTestPlan.Builder(TemperatureUnit.Fahrenheit) _
    .SetCustomTestHeatingBaseTemperatures() _
    .SetCustomTestCoolingBaseTemperatures() _
    .SetRequestedRegressionSpecs(
        RegressionSpec.Baseload _
            .WithHeating(Temperature.Fahrenheit(60)),
        RegressionSpec.Baseload _
            .WithCooling(Temperature.Fahrenheit(70)),
        RegressionSpec.Baseload _
            .WithHeating(Temperature.Fahrenheit(60)) _
            .WithCooling(Temperature.Fahrenheit(70))) _
    .Build()
# This first example shows how we can specify up to 60 particular regressions
# that we want to be tested and returned alongside the ones returned
# automatically:
RegressionTestPlan(TemperatureUnit.CELSIUS,
    requestedRegressionSpecs=(
        # Specify a regression with baseload (always present) and HDD (with
        # a base temperature defined in the units of the RegressionTestPlan):
        RegressionSpec(heatingBaseTemperatureOrNone=Temperature.celsius(15.5)),
        # Specify a regression with baseload (always present), HDD, and CDD:
        RegressionSpec(heatingBaseTemperatureOrNone=Temperature.celsius(14),
            coolingBaseTemperatureOrNone=Temperature.celsius(21))))

# This second example shows how we can define empty custom HDD and CDD base
# temperatures to get the API to test only the exact regressions we specify:
RegressionTestPlan(TemperatureUnit.FAHRENHEIT,
    customTestHeatingBaseTemperaturesOrNone=(),
    customTestCoolingBaseTemperaturesOrNone=(),
    requestedRegressionSpecs=(
        RegressionSpec(heatingBaseTemperatureOrNone=Temperature.fahrenheit(60)),
        RegressionSpec(coolingBaseTemperatureOrNone=Temperature.fahrenheit(70)),
        RegressionSpec(heatingBaseTemperatureOrNone=Temperature.fahrenheit(60),
            coolingBaseTemperatureOrNone=Temperature.fahrenheit(70))))

To find our requested regressions in the RegressionResponse, we can check the tags included with each regression:

"regressions": [
    {
        "tags": [
            "Requested" // this is the tag we'd be looking for
        ]
        // rest of regression data omitted for clarity
    }
    // other regressions omitted for clarity
]
<Regressions>
  <Regression>
    <Tags>
      <Tag>Requested</Tag> <!-- this is the tag we'd be looking for -->
    </Tags>
    <!-- rest of regression data omitted for clarity -->
  </Regression>
  <!-- other regressions omitted for clarity -->
</Regressions>
for (Regression r : response.getRegressions()) {
    if (r.hasTag(RegressionTag.REQUESTED)) {
        // found one!
    }
}
foreach (Regression r in response.GetRegressions()) {
    if (r.HasTag(RegressionTag.Requested)) {
        // found one!
    }
}
For Each r As Regression In response.GetRegressions()
    If r.HasTag(RegressionTag.Requested) Then
        ' found one!
    End If
Next
for r in response.getRegressions():
    if r.hasTag(RegressionTag.REQUESTED):
        # found one!

Back to top

Extra predictors

You can optionally include up to two extra predictors, like occupancy or production figures, in your regression analysis. You give each extra predictor a key (like "occupancy" or "production") that you will use throughout your regression request, and that will be used in the response as well.

Extra-predictor figures in your input data

For each input period in your InputData, you'll need a figure for each extra predictor you want to include:

"inputData": [
    {
        "dayRange": {
            "first": "2023-02-01",
            "last": "2023-02-28"
        },
        "usage": 48415,
        "extraPredictors": {
            "occupancy": 70,
            "production": 567
        }
    },
    {
        "dayRange": {
            "first": "2023-03-01",
            "last": "2023-03-31"
        },
        "usage": 29518,
        "extraPredictors": {
            "occupancy": 62,
            "production": 412
        }
    }
    // In reality we'd need more input periods for regression analysis to work,
    // but the two above are enough to show the format for extra-predictor data.
]
<InputData>
  <InputPeriod>
    <DayRange first="2023-02-01" last="2023-02-28"/>
    <Usage>48415</Usage>
    <ExtraPredictor key="occupancy">70</ExtraPredictor>
    <ExtraPredictor key="production">567</ExtraPredictor>
  </InputPeriod>
  <InputPeriod>
    <DayRange first="2023-03-01" last="2023-03-31"/>
    <Usage>29518</Usage>
    <ExtraPredictor key="occupancy">62</ExtraPredictor>
    <ExtraPredictor key="production">412</ExtraPredictor>
  </InputPeriod>
  <!-- In reality we'd need more input periods for regression analysis to work,
  but the two above are enough to show the format for extra-predictor data. -->
</InputData>
InputData inputData = new InputData(
    new InputPeriod(Day.of(2023, 2, 1).to(2023, 2, 28), 48415)
        .withExtraPredictor("occupancy", 70)
        .withExtraPredictor("production", 567),
    new InputPeriod(Day.of(2023, 3, 1).to(2023, 3, 31), 29518)
        .withExtraPredictor("occupancy", 62)
        .withExtraPredictor("production", 412));
    // In reality we'd need more input periods for regression analysis to work,
    // but the two above are enough to show the format for extra-predictor data.
InputData inputData = new InputData(
    new InputPeriod(new Day(2023, 2, 1).To(2023, 2, 28), 48415)
        .WithExtraPredictor("occupancy", 70)
        .WithExtraPredictor("production", 567),
    new InputPeriod(new Day(2023, 3, 1).To(2023, 3, 31), 29518)
        .WithExtraPredictor("occupancy", 62)
        .WithExtraPredictor("production", 412));
    // In reality we'd need more input periods for regression analysis to work,
    // but the two above are enough to show the format for extra-predictor data.
Dim inputData As InputData = New InputData(
    New InputPeriod(New Day(2023, 2, 1).To(2023, 2, 28), 48415) _
        .WithExtraPredictor("occupancy", 70) _
        .WithExtraPredictor("production", 567),
    New InputPeriod(New Day(2023, 3, 1).To(2023, 3, 31), 29518) _
        .WithExtraPredictor("occupancy", 62) _
        .WithExtraPredictor("production", 412))
    ' In reality we'd need more input periods for regression analysis to work,
    ' but the two above are enough to show the format for extra-predictor data.
inputData = InputData(
    InputPeriod(DayRange(date(2023, 2, 1), date(2023, 2, 28)), 48415,
        {'occupancy': 70, 'production': 567}),
    InputPeriod(DayRange(date(2023, 3, 1), date(2023, 3, 31)), 29518,
        {"occupancy": 62, 'production': 412}))
    # In reality we'd need more input periods for regression analysis to work,
    # but the two above are enough to show the format for extra-predictor data.

If, for whatever reason, you don't have all the necessary extra-predictor data for any input periods, you'll need to leave those input periods out of the InputData you send in your RegressionRequest.

Extra-predictor specs in your RegressionTestPlan

Your RegressionTestPlan will also need an extra-predictor spec for each extra predictor you use in your request. These tell the API about the extra-predictor data you are using, so it can process its figures appropriately in the regression analysis:

"regressionTestPlan": {
    "temperatureUnit": "C",
    "dayNormalization": "Weighted",
    "extraPredictorSpecs": {
        // We must define an extra-predictor spec for each extra predictor we
        // include in our input data:
        "occupancy": {
            // The predictorType can be "Average" or "Cumulative".  Both are
            // explained at www.degreedays.net/regression#extra-predictors
            "predictorType": "Average",
            // The expectedCorrelation can be "Positive", "Negative", or 
            // "PositiveOrNegative".  These options are also explained at
            // www.degreedays.net/regression#extra-predictors
            "expectedCorrelation": "Positive"
        },
        "production": {
            "predictorType": "Cumulative",
            "expectedCorrelation": "Positive"
        }
    },
    // requestedRegressionSpecs are optional, but we include some here to show
    // how a regression with extra predictors can be specified (to ensure it is
    // tested by the API and returned in the RegressionResponse):
    "requestedRegressionSpecs": [
        {
            "heatingBaseTemperature": 15,
            "extraPredictorKeys": [
                "occupancy",
                "production"
            ]
        },
        // We can also get the API to run and return specific regressions that
        // include just one, or none, of our extra predictors:
        {
            "coolingBaseTemperature": 21
        }
    ]
}
<RegressionTestPlan>
  <TemperatureUnit>Celsius</TemperatureUnit>
  <DayNormalization>Weighted</DayNormalization>
  <ExtraPredictorSpecs>
    <!-- We must define an extra-predictor spec for each extra predictor we
    include in our input data: -->
    <ExtraPredictorSpec key="occupancy">
      <!-- The PredictorType can be "Average" or "Cumulative".  Both are
      explained at www.degreedays.net/regression#extra-predictors -->
      <PredictorType>Average</PredictorType>
      <!-- The ExpectedCorrelation can be "Positive", "Negative", or 
      "PositiveOrNegative".  These options are also explained at
      www.degreedays.net/regression#extra-predictors -->
      <ExpectedCorrelation>Positive</ExpectedCorrelation>
    </ExtraPredictorSpec>
    <ExtraPredictorSpec key="production">
      <PredictorType>Cumulative</PredictorType>
      <ExpectedCorrelation>Positive</ExpectedCorrelation>
    </ExtraPredictorSpec>
  </ExtraPredictorSpecs>
  <!-- RequestedRegressionSpecs are optional, but we include some here to show
  how a regression with extra predictors can be specified (to ensure it is
  tested by the API and returned in the RegressionResponse): -->
  <RequestedRegressionSpecs>
    <RegressionSpec>
      <HeatingBaseTemperature>15</HeatingBaseTemperature>
      <ExtraPredictorKey>occupancy</ExtraPredictorKey>
      <ExtraPredictorKey>production</ExtraPredictorKey>
    </RegressionSpec>
    <!-- We can also get the API to run and return specific regressions that
    include just one, or none, of our extra predictors: -->
    <RegressionSpec>
      <CoolingBaseTemperature>21</CoolingBaseTemperature>
    </RegressionSpec>
  </RequestedRegressionSpecs>
</RegressionTestPlan>
new RegressionTestPlan.Builder(TemperatureUnit.CELSIUS)
    // We must define an extra-predictor spec for each extra predictor we
    // include in our input data:
    .addExtraPredictorSpec("occupancy", new ExtraPredictorSpec(
        // A PredictorType can be AVERAGE or CUMULATIVE.  Both are explained at
        // www.degreedays.net/regression#extra-predictors
        PredictorType.AVERAGE,
        // An ExpectedCorrelation can be POSITIVE, NEGATIVE, or
        // POSITIVE_OR_NEGATIVE.  These options are also explained at
        // www.degreedays.net/regression#extra-predictors
        ExpectedCorrelation.POSITIVE))
    .addExtraPredictorSpec("production", new ExtraPredictorSpec(
        PredictorType.CUMULATIVE,
        ExpectedCorrelation.POSITIVE))
    // requestedRegressionSpecs are optional, but we include some here to show
    // how a regression with extra predictors can be specified (to ensure it is
    // tested by the API and returned in the RegressionResponse):
    .setRequestedRegressionSpecs(
        RegressionSpec.baseload()
            .withHeating(Temperature.celsius(15))
            .withExtraPredictorKeys("occupancy", "production"),
        // We can also get the API to run and return specific regressions that
        // include just one, or none, of our extra predictors:
        RegressionSpec.baseload()
            .withCooling(Temperature.celsius(21)))
    .build();
new RegressionTestPlan.Builder(TemperatureUnit.Celsius)
    // We must define an extra-predictor spec for each extra predictor we
    // include in our input data:
    .AddExtraPredictorSpec("occupancy", new ExtraPredictorSpec(
        // A PredictorType can be Average or Cumulative.  Both are explained at
        // www.degreedays.net/regression#extra-predictors
        PredictorType.Average,
        // An ExpectedCorrelation can be Positive, Negative, or
        // PositiveOrNegative.  These options are also explained at
        // www.degreedays.net/regression#extra-predictors
        ExpectedCorrelation.Positive))
    .AddExtraPredictorSpec("production", new ExtraPredictorSpec(
        PredictorType.Cumulative,
        ExpectedCorrelation.Positive))
    // requestedRegressionSpecs are optional, but we include some here to show
    // how a regression with extra predictors can be specified (to ensure it is
    // tested by the API and returned in the RegressionResponse):
    .SetRequestedRegressionSpecs(
        RegressionSpec.Baseload
            .WithHeating(Temperature.Celsius(15))
            .WithExtraPredictorKeys("occupancy", "production"),
        // We can also get the API to run and return specific regressions that
        // include just one, or none, of our extra predictors:
        RegressionSpec.Baseload
            .WithCooling(Temperature.Celsius(21)))
    .Build();
testPlan = New RegressionTestPlan.Builder(TemperatureUnit.Celsius) _
    _' We must define an extra-predictor spec for each extra predictor we
    _' include in our input data:
    .AddExtraPredictorSpec("occupancy", New ExtraPredictorSpec(
        _' A PredictorType can be Average or Cumulative.  Both are explained at
        _' www.degreedays.net/regression#extra-predictors
        PredictorType.Average,
        _' An ExpectedCorrelation can be Positive, Negative, or
        _' PositiveOrNegative.  These options are also explained at
        _' www.degreedays.net/regression#extra-predictors
        ExpectedCorrelation.Positive)) _
    .AddExtraPredictorSpec("production", New ExtraPredictorSpec(
        PredictorType.Cumulative,
        ExpectedCorrelation.Positive)) _
    _' requestedRegressionSpecs are optional, but we include some here to show
    _' how a regression with extra predictors can be specified (to ensure it is
    _' tested by the API and returned in the RegressionResponse):
    .SetRequestedRegressionSpecs(
        RegressionSpec.Baseload _
            .WithHeating(Temperature.Celsius(15)) _
            .WithExtraPredictorKeys("occupancy", "production"),
        _' We can also get the API to run and return specific regressions that
        _' include just one, or none, of our extra predictors:
        RegressionSpec.Baseload _
            .WithCooling(Temperature.Celsius(21))) _
    .Build()
RegressionTestPlan(TemperatureUnit.CELSIUS,
    # We must define an extra-predictor spec for each extra predictor we
    # include in our input data:
    extraPredictorSpecs={
        'occupancy': ExtraPredictorSpec(
            # A PredictorType can be AVERAGE or CUMULATIVE.  Both are explained at
            # www.degreedays.net/regression#extra-predictors
            PredictorType.AVERAGE,
            # An ExpectedCorrelation can be POSITIVE, NEGATIVE, or
            # POSITIVE_OR_NEGATIVE.  These options are also explained at
            # www.degreedays.net/regression#extra-predictors
            ExpectedCorrelation.POSITIVE),
        'production': ExtraPredictorSpec(
            PredictorType.CUMULATIVE,
            ExpectedCorrelation.POSITIVE)},
    # requestedRegressionSpecs are optional, but we include some here to show
    # how a regression with extra predictors can be specified (to ensure it is
    # tested by the API and returned in the RegressionResponse):
    requestedRegressionSpecs=(
        RegressionSpec(heatingBaseTemperatureOrNone=Temperature.celsius(15),
            extraPredictorKeys=('occupancy', 'production')),
        # We can also get the API to run and return specific regressions that
        # include just one, or none, of our extra predictors:
        RegressionSpec(coolingBaseTemperatureOrNone=Temperature.celsius(21))))

Extra components in the regressions you get back

The example response above shows how a RegressionResponse contains a list of regressions, and each regression has regression components (for baseload and usually HDD and/or CDD) within it. When you include extra predictors in your request, you can expect the response to contain regressions with extra components, like so:

// "components" will appear within each regression object in the "regressions"
// array that you will receive in any successful RegressionResponse.  The
// example at www.degreedays.net/api/regression#response shows it in context.
"components": {
    "baseload": {
        // details omitted for clarity
    },
    // "heatingDegreeDays" and/or "coolingDegreeDays" may also be present.
    // Any extra components in the regression will appear with the keys that you
    // you assigned them in your request, for example:
    "occupancy": {
        // Since "multiplyByNumberOfDays" is true here, your regression equation
        // would multiply the occupancy figure by the number of days it (and the
        // period you are calculating energy usage E for) covers.  For example:
        //   E = b*days + coefficient*occupancy*days
        "multiplyByNumberOfDays": true,
        "coefficient": 1.843000993131035,
        "coefficientStandardError": 0.155282796055957,
        "coefficientPValue": 0.0304239151301268
    }
    // Components for any other extra predictors you defined in your request
    // could appear here too.
}
<!-- A Components element will appear within each Regression you receive in any
successful RegressionResponse.  The example response at
www.degreedays.net/api/regression#response shows it in context. -->
<Components>
  <Baseload>
    <!-- details omitted for clarity -->
  </Baseload>
  <!-- HeatingDegreeDays and/or CoolingDegreeDays may also be present. -->
  <!-- Any extra components in the regression will appear with the keys that you
  you assigned them in your request, for example: -->
  <Extra key="occupancy">
    <ExtraInfo>
      <!-- Since MultiplyByNumberOfDays is true here, your regression equation
      would multiply the occupancy figure by the number of days it (and the
      period you are calculating energy usage E for) covers.  For example:
        E = b*days + coefficient*occupancy*days -->
      <MultiplyByNumberOfDays>true</MultiplyByNumberOfDays>
    </ExtraInfo>
    <Coefficient>1.843000993131035</Coefficient>
    <CoefficientStandardError>0.155282796055957</CoefficientStandardError>
    <CoefficientPValue>0.0304239151301268</CoefficientPValue>
  </Extra>
  <!-- Components for any other extra predictors you defined in your request
  could appear here too. -->
</Components>
Regression regression = response.getRegressions().get(0);
// The sample response at www.degreedays.net/api/regression#response shows the
// baseload component (always present) and the heatingDegreeDays and
// coolingDegreeDays components that may be present as well.  Extra components
// are additional to these.  They won't appear in every regression so we need to
// check if they are present first before trying to get them.
if (regression.hasExtraComponent("occupancy")) {
    ExtraRegressionComponent extra = regression.getExtraComponent("occupancy");
    System.out.println("coefficient = " + extra.coefficient());
    // If multiplyByNumberOfDays() returns true, your regression equation would
    // multiply the occupancy figure by the number of days it (and the period
    // you are calculating energy usage E for) covers.  For example:
    //   E = b*days + coefficient*occupancy*days
    System.out.println("multiply by number of days = " +
            extra.multiplyByNumberOfDays());
}
Regression regression = response.GetRegressions().First();
// The sample response at www.degreedays.net/api/regression#response shows the
// Baseload component (always present) and the HeatingDegreeDays and
// CoolingDegreeDays components that may be present as well.  Extra components
// are additional to these.  They won't appear in every regression so we need to
// check if they are present first before trying to get them.
if (regression.HasExtraComponent("occupancy")) {
    ExtraRegressionComponent extra = regression.GetExtraComponent("occupancy");
    Console.Out.WriteLine("coefficient = " + extra.Coefficient);
    // If MultiplyByNumberOfDays is true, your regression equation would
    // multiply the occupancy figure by the number of days it (and the period
    // you are calculating energy usage E for) covers.  For example:
    //   E = b*days + coefficient*occupancy*days
    Console.Out.WriteLine("multiply by number of days = " +
            extra.MultiplyByNumberOfDays);
}
Dim regression As Regression = response.GetRegressions().First()
' The sample response at www.degreedays.net/api/regression#response shows the
' Baseload component (always present) and the HeatingDegreeDays and
' CoolingDegreeDays components that may be present as well.  Extra components
' are additional to these.  They won't appear in every regression so we need to
' check if they are present first before trying to get them.
if regression.HasExtraComponent("occupancy") Then
    Dim extra As ExtraRegressionComponent =
            regression.GetExtraComponent("occupancy")
    Console.Out.WriteLine("coefficient = " & extra.Coefficient)
    ' If MultiplyByNumberOfDays is true, your regression equation would
    ' multiply the occupancy figure by the number of days it (and the period
    ' you are calculating energy usage E for) covers.  For example:
    '   E = b*days + coefficient*occupancy*days
    Console.Out.WriteLine("multiply by number of days = " &
            extra.MultiplyByNumberOfDays)
End If
regression = response.getRegressions()[0]
# The sample response at www.degreedays.net/api/regression#response shows the
# baseload component (always present) and the heatingDegreeDaysOrNone and
# coolingDegreeDaysOrNone components that may be present as well.  Extra
# components are additional to these.  They won't appear in every regression so
# we need to check if they are present first before trying to get them.
if regression.hasExtraComponent('occupancy'):
    extra = regression.getExtraComponent('occupancy')
    print('coefficient = %g' % extra.coefficient)
    # If multiplyByNumberOfDays is True, your regression equation would multiply
    # the occupancy figure by the number of days it (and the period you are
    # calculating energy usage E for) covers.  For example:
    # E = b*days + coefficient*occupancy*days
    print('multiply by number of days = %s' % extra.multiplyByNumberOfDays)

You should not expect every regression to contain a component for every extra predictor you include in your request. The API will test regressions with and without any extra predictors you define, and, if you define more than one extra predictor, it will test all different combinations of those extra predictors too. You will often find that the regression with the best stats does not include all the extra predictors you defined.

Additional guidance on extra predictors

The docs above explain how to include extra predictors in your regressions, but they won't help you decide whether (or when) it makes sense to do so. The docs for the regression web tool have some additional guidance on extra predictors that may help.

Back to top

Tips to help you get good results

Most of these tips are covered elsewhere on our site, but we cover them again here as they are important:

Consider the timescale of your input data

Longer-period energy-usage data, like monthly data, is not ideal, but it is certainly usable, and it may be all that is available. If you are using it, remember:

Weekly energy-usage data is typically very good for regression analysis, as most buildings operate on a weekly cycle. So if you have that, that's great.

Daily data is good for buildings that operate the same every day of the week, but, for buildings with different operation/occupancy patterns on different days of the week, it needs some special treatment:

The simplest approach is to sum the daily data into weekly data and run the regressions on that.

A more sophisticated approach is to combine it into multiple sets of daily input data, each covering different days (with gaps for the other days), and make a RegressionRequest for each set separately:

Once you have made regression requests for each set of input data, you can choose the best regression from each response, such that, for any day of the week, you will know which regression model to use. Then, if you want to calculate the predicted energy usage for, say, some particular month, you would fetch daily degree days for that month, in all the base temperatures required by your chosen regression models, then use the appropriate figures in each of your chosen models to calculate the total predicted energy usage over that month.

You could even compare the regression shortlists for each day of the week, looking for days of the week with similar regression models, then combine the input data for those similar days and run regression requests once more, to hopefully come up with a simpler occupied/unoccupied model like the weekdays/weekends split described above (but maybe with different days).

Fine-grained interval data like hourly data or 15-minute data isn't nearly as useful for analyzing heating/cooling energy consumption as people who are new to this sort of analysis often assume. We explain the reasons why in this FAQ. Generally we would suggest combining it into daily or weekly data and running regressions as described above. Use the local time zone of the building when combining interval data into days or weeks.

Choose a good baseline period

The baseline period is the period of time that your regressions cover. Assuming your chosen location has the weather data to match your dates, the baseline period will be the period covered by your input data.

General guidance is to run regressions over data covering one or multiple full years. These don't have to be calendar years, just any period covering roughly 365 days, 52 weeks, 12 months, or a multiple thereof, like 730 days, 156 weeks, or 48 months. The idea is to ensure that all seasons are represented equally in the regression process.

You should also aim to choose a period over which the building construction and usage patterns were fairly consistent. We appreciate that this may be difficult if your system doesn't know anything about the building or how it may have changed over time. If possible and applicable, perhaps you could ask the end user of your system, or apply a default but give the end user the option to change it.

On the one hand, more data gives better regressions, so in that respect a longer baseline period is better. But on the other hand, the longer the baseline period, the more likely it is that the building will have seen some significant changes to its construction or usage within that period. You may have to balance these two factors, especially if your system doesn't know much about the buildings that the data you are analyzing comes from.

In some circumstances it may even make sense to try several different baseline periods and choose the one that gives the best regression stats. If you are doing this, make sure that your test baseline periods are similar in length and have the same number of input periods within them (i.e. the same sample size).

Run regressions separately for each fuel/meter

Different fuels/meters are likely to be associated with different heating/cooling systems and different areas of buildings with different base temperatures. Combining data before running regressions will typically make it harder for the regression process to find clear patterns of weather dependency and give good results. It's usually better to run regressions on the data from each fuel/meter separately, and then, if you need a combined energy model, build one yourself by combining the regression models for each fuel/meter afterwards.

This is explained in our general guidance on handling data from multiple fuels/meters in regression analysis. Though that guidance does assume that the reader knows about each meter and what it is used for. API users dealing with data from thousands of buildings often won't have these details, and may also need their systems to cope with buildings with excessive submetering (like hundreds of meters for one small building). So, even though it's generally best to run regressions for each meter separately, we appreciate that in certain circumstances it may still make practical sense to combine some meters before running regressions.

Choose the most appropriate regression using any knowledge your system has of the building/meter

The RegressionResponse will usually contain several regressions with the Shortlist tag. These should all be quite close in statistical quality. If you know nothing about the building/meter, the first regression (which the API sees as having the best stats) is likely the best choice. But, if you know more about the building/meter, you may want to run through all Shortlist regressions and choose one that fits your expectations. For example, if you know that the meter fuels a heating system, you'll want to find a regression with heating degree days in it; if you know that the building has no cooling, you'll want to find a regression that does not have cooling degree days.

The docs for our online regression tool have some further guidance on choosing the best regression that we suggest you read. Again, we appreciate that your system might not know much about the buildings/meters that the data you are analyzing has come from. Also you may need to be prepared for the possibility of some of what your system thinks it knows about a building/meter being wrong. So you will need to use your best judgement when designing your system to choose the best regression from the results returned by our API.

Back to top

Choose your API Plan and Start Today!

© 2008–2024 BizEE Software – About | Contact | Privacy | Free Website | API | Integration Guide | API FAQ | API Sign-Up