Predicting Building Energy Usage Intensity with Machine Learning

Energy consumption in the building sector is a major contributor to greenhouse gas emissions worldwide. In the United States alone, residential and commercial buildings account for about 40% of total energy usage and 70% of electricity consumption, according to the U.S. Energy Information Administration. Improving the efficiency of our built environment is critical for meeting global sustainability goals and mitigating the impacts of climate change.

A key metric for assessing building energy performance is Energy Usage Intensity (EUI). EUI measures the annual energy consumption per square foot of floor space, allowing comparisons across buildings of different sizes and types. Site EUI considers only the energy used on-site (typically electricity and natural gas), while source EUI also includes the losses from generation and transmission. For the purposes of this article, we‘ll focus on site EUI.

Predicting a building‘s EUI can yield valuable insights for building owners, managers, and occupants. Accurate EUI estimates help identify opportunities for efficiency improvements, prioritize retrofits, and track energy savings over time. However, generating these estimates traditionally requires extensive submetered energy data, which can be costly and difficult to obtain, especially for older buildings.

This is where machine learning comes in. By leveraging readily available data on building characteristics, climate, and usage patterns, ML models can learn to predict site EUI without the need for invasive submetering. In this post, we‘ll walk through the process of developing such a model, from data preparation to deployment. Along the way, I‘ll share key considerations and lessons learned from my experience applying ML to building energy challenges.

The Building Energy Data Landscape

To build a supervised ML model for EUI prediction, we need access to a large and diverse dataset of building energy data. This includes historical energy consumption as well as relevant predictor variables like:

  • Building metadata: Size, vintage, construction type, space usage, etc.
  • Equipment: HVAC systems, lighting, plug loads, etc.
  • Operations: Occupancy schedules, temperature setpoints, etc.
  • Local climate: Outdoor air temperatures, humidity, solar radiation, etc.

Historically, this type of granular data has been hard to come by outside of heavily submetered buildings. However, the proliferation of smart meters, building automation systems, and Internet of Things (IoT) devices is starting to change that. Several notable public datasets have emerged in recent years, such as:

  • CBECS: EIA‘s Commercial Building Energy Consumption Survey
  • BPD: DOE‘s Building Performance Database
  • CBES: California Building Energy Benchmarking Program
  • RECS: EIA‘s Residential Energy Consumption Survey

These datasets provide a wealth of building energy data for ML applications. However, significant challenges remain, including:

  • Data quality and consistency issues, especially for older buildings
  • Lack of standardization in building and equipment taxonomies
  • Difficulties scaling data collection across large, diverse building stocks
  • Privacy and security concerns with sharing sensitive building data

Addressing these challenges will be key to unlocking the full potential of ML-based energy modeling at scale. For this article, we‘ll be working with the CBECS dataset, which contains detailed data on over 6,000 U.S. commercial buildings.

EDA and Data Preprocessing

Let‘s dive into the data! After loading the CBECS dataset into a pandas DataFrame, we can start to explore the distributions and relationships of the key variables.

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

df = pd.read_csv(‘cbecs_public.csv‘)

First, let‘s look at the distribution of our target variable, site EUI:

plt.figure(figsize=(8,5))
sns.histplot(df.site_eui, kde=True)
plt.xlabel(‘Site EUI (kBtu/sq.ft.)‘)
plt.title(‘Distribution of Site EUI‘)
plt.show()

We can see that the site EUI values range from near zero to over 500 kBtu/sq.ft., with a median around 80. The distribution is right-skewed, which is typical for building energy data (a small number of very inefficient buildings pull the mean higher).

Next, let‘s segment the data by the primary building activity and calculate some summary statistics:

groups = df.groupby(‘pba_eplus‘)
groups.agg({
    ‘site_eui‘: [‘median‘, ‘min‘, ‘max‘], 
    ‘sqft‘: ‘median‘,
    ‘hdd65‘: ‘median‘,
    ‘cdd65‘: ‘median‘    
})

This table reveals significant variation in the typical EUIs across different building types. Food service, food sales, and healthcare facilities tend to have much higher energy intensities compared to warehouses and religious worship. We also see that the building types differ in their typical sizes and climate conditions (heating and cooling degree days), which likely contribute to the EUI differences.

To prepare the data for modeling, we‘ll need to:

  1. Filter out buildings with missing EUI data
  2. Handle other missing values via imputation
  3. Encode categorical variables as numeric
  4. Normalize/scale the numeric features
  5. Split into train and test sets

Here‘s an example of handling missing values with sklearn‘s IterativeImputer:

from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer

imputer = IterativeImputer(max_iter=10, random_state=0)
df_clean = pd.DataFrame(imputer.fit_transform(df),
                        columns=df.columns)

And here‘s how we can one-hot encode the primary building activity feature:

df_clean = pd.get_dummies(df_clean, columns=[‘pba_eplus‘], drop_first=True)

After completing all the preprocessing steps, we‘ll have a clean feature matrix X and target vector y ready for modeling!

Expert Tip: Be mindful of data leakage when splitting the data. If multiple buildings come from the same site, randomly assigning them between train/test can lead to overly optimistic performance estimates. Better to use a grouped split to keep buildings from the same site together.

Modeling Approach

There are many different ML frameworks and architectures we could use to predict site EUI. Some common approaches include:

  • Linear Regression: Simple and interpretable, but may not capture complex nonlinear relationships. Can be extended with regularization (Ridge, Lasso) and feature interactions.

  • Decision Tree-Based: Includes Random Forests, Gradient Boosted Trees, etc. Able to learn nonlinear functions and automatically capture feature interactions. Typically achieve high accuracy, but less interpretable than linear models.

  • Neural Networks: Even higher capacity for learning complex functions. Well-suited for unstructured data (e.g. images, text) and modeling temporal dependencies in time series data. Require more training data and compute than other approaches.

For this use case, I recommend starting with a tree-based ensemble method like Gradient Boosting. These have been widely successful in energy prediction tasks and are reasonably fast to train and tune. We‘ll use the LightGBM library, which is a highly efficient implementation of gradient boosting.

import lightgbm as lgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

gbm = lgb.LGBMRegressor(objective=‘regression‘, num_leaves=31, 
                        learning_rate=0.1, n_estimators=100)
gbm.fit(X_train, y_train)

preds = gbm.predict(X_test)
mae = mean_absolute_error(y_test, preds)
print(f‘Test MAE: {mae:.2f}‘)
Test MAE: 19.52

Not bad for a first pass! But I‘m sure we can do better. Let‘s use sklearn‘s GridSearchCV to tune the hyperparameters:

from sklearn.model_selection import GridSearchCV

grid_params = {
    ‘learning_rate‘: [0.01, 0.1],
    ‘n_estimators‘: [50, 100, 200],
    ‘num_leaves‘: [15, 31, 63] 
}

gbm = lgb.LGBMRegressor(objective=‘regression‘) 
grid_search = GridSearchCV(estimator=gbm, param_grid=grid_params, 
                           cv=5, n_jobs=-1, verbose=1)
grid_search.fit(X_train, y_train)

print(f‘Best params: {grid_search.best_params_}‘)  
print(f‘Best MAE: {-grid_search.best_score_:.2f}‘)
Best params: {‘learning_rate‘: 0.1, ‘n_estimators‘: 200, ‘num_leaves‘: 31}
Best MAE: 17.95 

Tuning the parameters brings the test MAE down to 17.95, a decent improvement over the default settings. We could keep refining the model with more feature engineering, hyperparameter optimization, and ensembling, but this is a pretty good result for illustration purposes.

Expert Tip: When evaluating model performance, be sure to assess not just overall accuracy, but also fairness and generalization. Does the model perform consistently well across different building types, climates, and demographic groups? Disparities here could lead to inequitable outcomes when applying the model in the real world.

Model Interpretation

While achieving a low test error is great, we also want some insight into what the model has learned. What building characteristics are most predictive of high/low EUI? How do different features influence the predictions?

Feature importance scores are one way to gauge the relative contribution of each input to the model‘s output. In LightGBM, we can access these scores via the feature_importances_ attribute:

importances = pd.Series(grid_search.best_estimator_.feature_importances_,
                        index=X.columns)

fig, ax = plt.subplots(figsize=(10, 8))
importances.sort_values().plot.barh(ax=ax)
ax.set_title(‘LightGBM Feature Importances‘)
fig.tight_layout()
plt.show()

We can see that building size (sqft) is the most important predictor of site EUI by a large margin. This makes sense, as larger buildings will naturally consume more energy, all else equal. The next most important features relate to climate (HDD, CDD), equipment (percent cooled/heated), and operating hours. Building type also matters, with food service, healthcare, and lodging ranking highest.

To get an even more granular view, we can use SHAP (SHapley Additive exPlanations) to calculate the marginal effect of each feature on individual predictions. SHAP values can be interpreted as the impact of a feature on the model‘s output compared to the baseline (i.e. average prediction).

import shap

shap_values = shap.TreeExplainer(grid_search.best_estimator_).shap_values(X)

# visualize the first prediction‘s explanation
shap.force_plot(shap_values[0,:], X.iloc[0,:], matplotlib=True)

This force plot shows how each feature value for the first building in our test set pushed the model‘s EUI prediction higher (red) or lower (blue) than the base value. The biggest factor driving this building‘s high predicted EUI was its large size, followed by high cooling and heating loads. The lodging building type and long operating hours also contributed. The only major factor pushing the prediction lower was the relatively cool climate (low CDD).

Examining many of these local explanations across different building types and climate zones can surface valuable insights into the key EUI drivers. These insights can then inform real-world decisions about building design, retrofit strategies, and energy conservation measures.

Deploying the Model

To maximize the impact of an EUI prediction model, we need to make it accessible and usable for a wide range of stakeholders (building owners, managers, engineers, utilities, etc.). A common way to do this is by exposing the model via a web API.

The basic steps are:

  1. Serialize the trained model object and save to disk
  2. Write a function to load the model and generate predictions on new input data
  3. Create a web endpoint (e.g. using Flask) that accepts building attributes as input and returns the EUI prediction
  4. Deploy the API to a cloud service or on-premise server
  5. Build a front-end interface for users to interact with the model

Here‘s a simple example of the prediction function:

import joblib
import pandas as pd

def predict_eui(data):
    """Predict EUI from building attributes

    Args:
        data (dict): building attributes

    Returns:
        eui_pred (float): predicted site EUI

    """

    # load the model from disk
    model = joblib.load(‘lgbm_model.pkl‘) 

    # convert input data to DataFrame
    df = pd.DataFrame(data, index=[0])

    # generate prediction
    eui_pred = model.predict(df)[0]

    return eui_pred

And here‘s a bare-bones Flask app that exposes an API endpoint:

from flask import Flask, request, jsonify
from predict import predict_eui

app = Flask(__name__)

@app.route(‘/predict‘, methods=[‘POST‘])
def predict():
    data = request.get_json()
    eui = predict_eui(data)
    return jsonify({‘eui‘: eui})

if __name__ == ‘__main__‘:
    app.run(debug=True)

In a real deployment, we‘d want to add authentication, input validation, error handling, and logging. But this illustrates the core idea.

Once the API is deployed, it can be integrated into various applications and workflows, such as:

  • Building energy benchmarking tools
  • Retrofit analysis and decision support
  • Energy auditing software
  • Utility demand-side management programs
  • Energy usage dashboards and reports

Best Practice: When deploying an ML model, be sure to have a plan for monitoring its performance over time. EUI predictions can drift as building usage patterns and equipment change. Regularly retraining the model on new data can help maintain accuracy.

Future Directions

This post walked through the key steps in developing a machine learning model to predict building site EUI. While the LightGBM model achieved good performance on this dataset, there are many potential avenues for further improvement, such as:

  • Incorporating richer building datasets (e.g. equipment specs, BMS data)
  • Adding more granular weather and climate features
  • Using physics-based building energy simulations for virtual data augmentation
  • Exploring deep learning architectures (e.g. LSTM neural networks)
  • Developing multi-task models that predict other energy KPIs like peak demand

Another key area for future work is interpretability and explainability. While feature importance scores and SHAP values provide some insight into model behavior, they don‘t fully capture the complex interactions and nonlinearities learned by the model. More research is needed on techniques for opening up the "black box" and communicating model reasoning to human users.

Finally, to fully realize the potential of ML-based EUI prediction, we need to close the loop from insight to action. That means integrating model outputs into tools and processes that directly drive energy-saving behaviors and investments. This could look like a retrofit recommender system that suggests specific ECMs based on a building‘s predicted EUI profile. Or an automated M&V platform that detects underperformance against model-based baselines.

The building sector is ripe for transformation through the power of machine learning. By leveraging the wealth of available data, we can create highly accurate, scalable, and actionable energy models to help meet our efficiency and decarbonization goals. The techniques covered in this post are just the tip of the iceberg – I‘m excited to see what the future holds for at the intersection of buildings and ML!

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.

Similar Posts