Recurrent Neural Networks for Electricity Price Prediction | by Carter Bouley | Towards Data Science

The final model used to predict these prices can be found (here)
(full GitHub repository)
Demand flexibility can be described as the capacity for end users of electricity (think both business and homes) to change their electricity consumption patterns in response to market signals, such as time variable electricity prices.
Electricity prices follow daily, weekly and seasonal patterns. Above we can see the daily pattern. In the morning, everyone wakes up, turns all their devices on and prices rise. As the population goes off to work, demand and prices fall (and solar generation comes online). Come around 5pm people start leaving the office and heading back home, turning on TVs and doing laundry etc, prices rise once again, until bedtime, and prices fall. This cycle then repeats.
Given the correlation of electricity prices and Carbon emissions (see my previous blog for this), if we can shift people away from peak times, to non-peak times we can make cost and carbon emission savings.
Not many companies offer this day ahead price to their customers, but Octopus Energy’s Agile tariff does exactly that.
First however, an accurate prediction of the price would be useful.
Usually when feature engineering, we need to ensure that our inputs are definitely helping (not hindering) the model. Luckily neural networks are pretty good at discerning what is helpful and what is not, so we can be pretty generous.
The inputs of the production of electricity are probably quite helpful in determining the price. Below are plots taking data from 2013 to 2019.
Each input seems to have some correlation with electricity price over time.
On top of that, it is helpful to include temperature data, to account for seasonal variation. Summer may have higher prices due to air conditioning demand.
All this data must be taken from different sources. I took Nordpools day ahead market for the price data, DarkSky API for temperatures, and Investing.com for commodity data. (This can all be found here.)
Now, after some cleaning, I have a completed data frame (here).
Because I am performing time series analysis, where the variable I am trying to predict is also used in the prediction I need to reshape the data into a supervised learning problem.
data = df.valuesn_steps = 168series_reshaped =  np.array([data[i:i + (n_steps+24)].copy() for i in range(len(data) - (n_steps+24))])series_reshaped.shape(61134, 192, 6)
Taking the values of the data frame (after scaling it for the neural network) I define that it can see 168 time steps backwards (1 week), and I want it to predict 24 hours ahead.
What this does is it creates a window over the data data frame, so that I have a matrix of 192 rows X 6 columns. This window moves down the original data frame, row my row, creating a new matrix for every hour. If midday on January 1st 2013 is the first row of the first matrix, 1pm will be the first row of the second matrix.
Adding dimensions like this will allow the neural network to understand that the order in which the hours come matter.
Now that the data is in this format, I split it so we have blocks of 168 hours (1 week) of every feature for the input data, and for every 168 block of hours, we have a 24 hour output of prices, so our model can ‘see’ the next 24 hours. This transfers the data into a supervised learning problem.
X_train = series_reshaped[:43800, :n_steps] X_valid = series_reshaped[43800:52560, :n_steps] X_test = series_reshaped[52560:, :n_steps] Y = np.empty((61134, n_steps, 24))  for step_ahead in range(1, 24 + 1):        Y[..., step_ahead - 1] =   series_reshaped[..., step_ahead:step_ahead + n_steps, 0] Y_train = Y[:43800] Y_valid = Y[43800:52560] Y_test = Y[52560:]
Now the X training data is 168 hours of the past of all commodities, and the Y training data is 24 hours of prices, into the future.
With the data formatted to feed into the neural network, it was just a matter of trying different formats.
After trying LSTM’s, GRU’s with convolutional layers, as well as classical machine learning (regression trees and ARIMA forecasting), a Recurrent Neural Network provided the best result.
np.random.seed(42)tf.random.set_seed(42)model6 = keras.models.Sequential([    keras.layers.SimpleRNN(20, return_sequences=True, input_shape=[None, 6]),    keras.layers.SimpleRNN(20, return_sequences=True),    keras.layers.TimeDistributed(keras.layers.Dense(24))])model6.compile(loss="mape", optimizer="adam")history = model6.fit(X_train, Y_train, epochs=20,                    validation_data=(X_valid, Y_valid))
There are two important things to pick up on here, for those who are into the more technical side of things, and that is return_sequences=True, and the final time distributed layer of 24. the first ensures that the data keeps the same multidimensional (time-series) format through the network, and the second is that it outputs 24 hours into the future, in that same structure, hour by hour.
For the prediction, I only care about that final 24th hour, as one hour later, there will be a new input, which will produces the next hour after that as a prediction.
Having trained the model on 2013 to 2018, I used 2019 to assess how well the model worked on unseen data. Selecting a random few days so you can actually see the effect, its quite accurate.
Given that the model now can predict the price of electricity 24 hours ahead of time, we can now adjust our consumption of electricity away from those peak times. This can mean setting our dryers, and appliances to run just when we go to sleep, or even investing in smart plugs to automate our devices that cycle (such as fridges, and air conditioning).
For simplicity, I simulated a home battery. It is loosely based on a Tesla Powerwall 2, and it has 14KW capacity and 5 KW of power. For simplicity, this means it can hold almost 3 hours of charge. It looks at the 24 hour prediction from the model, and selects the 3 cheapest hours to charge at, and 3 most expensive hours to discharge at.
It's unlikely you can sell electricity back to the grid at these day-ahead prices, however, for a valuation metric I simulated exactly that. Over the course of 2019, this battery would have spent £151.02 on charging, and ‘earned’ £280.23 from selling to the grid, leading to an 85.5% ROI. Considering this is quite a rudimentary battery model its not a bad result.
Not bad, but not much money either. The really interesting scenarios come about when we begin to consider the true potential scale of flexible demand, and the fact that there are thousands of huge, 1MW + air conditioning units that can be doing exactly this, saving both carbon emissions, and generating huge cost savings.