<jupyter_start><jupyter_text>**Electricity Demand Forecasting**

Electricity Demand Forecasting based on daily data of electricity demand from the POSOCO website from Jan-2017 to Dec-2020. The data provides the daily peak hour demand met (in MegaWatt) for each region in India (North, East, West, South and North East). Installed capacity is also taken from the report to forecast based on a logistic growth.
The aim is to forecast demand and identify when the demand would reach 75% utilization to initiate capacity upgrade.<jupyter_code>import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from fbprophet import Prophet
from fbprophet.diagnostics import cross_validation, performance_metrics

import logging
logging.getLogger('fbprophet').setLevel(logging.WARNING)
demand_file = 'posoco_electricty_demand_met.csv'
capacity_file = 'posoco_installed_capacity.csv'
#demand file
demand_df = pd.read_csv(demand_file)
print(demand_df.shape)
demand_df.head(3)
sns.relplot(x='Date', y='Demand_MW', data=demand_df, hue='Region', kind='line', aspect=3, height=4);<jupyter_output><empty_output><jupyter_text>Since data is from 2017, the effect of lockdown is minimal and the model should be able to capture the trend and seasonality fairly well. Of the various regions, growth in north seems to be higher and capacity comparatively lesser. We will use fbprophet to model the timeseries and forecast demand into future to understand when capacity upgrades need to be initiated<jupyter_code>#capacity file and present capacity calculation
cap_df = pd.read_csv(capacity_file)
present_cap = cap_df[(cap_df['Month']==cap_df['Month'].max())][['Region','Total Capacity (MW)']]
present_cap.head()
#convert column names to ds and y as per fbprophet requirement and
#create a list of regions for regional forecasts 
demand_df.columns =['ds', 'y', 'Region']
demand_df['ds'] = demand_df['ds'].astype('datetime64[ns]')
regions = demand_df['Region'].unique()
def predict_demand(demand, capacity, series_label):
  '''Takes historical demand data and predicts future 
  550 days of forecast.
  Arguments: 
  demand: datframe containing historical data in the form [ds,y]
  capacity: scalar value for max capacity of the system
  series_label: a string for printing chart title
   '''
  regional_demand['cap']= capacity
  m = Prophet(growth='logistic')
  m.fit(regional_demand)
  future = m.make_future_dataframe(periods=550)
  future['cap'] = capacity
  forecast = m.predict(future)
  fig, ax = plt.subplots(figsize=(16,4))
  m.plot(forecast, xlabel='Date', ylabel='Demand (MW)', ax=ax)
  ax.set(title=series_label)
for region in regions:
  regional_demand = demand_df[demand_df['Region']==region][['ds','y']]
  regional_cap = present_cap[present_cap['Region']==region]['Total Capacity (MW)'].values[0]
  predict_demand(regional_demand, regional_cap, region)<jupyter_output><empty_output><jupyter_text>The above forecast shows except for North, no specific region requires immediate capacity upgrade. The graph also show regions like a declining electricity demand even in 2019 in South and West, maybe due to an economic slow down which started much before covid-19 impact.
The capacity build triggering threshold can be decided based on lead time for capacity build and growth rate of demand. **Model Evaluation** Evaluating the model to check error and choose between linear and logistic growth models on a sample of north region data which has significant growth.<jupyter_code>north_demand = demand_df[demand_df['Region']=='North'][['ds','y']]
north_capacity = present_cap[present_cap['Region']=='North']['Total Capacity (MW)'].values[0]
north_capacity
#linear growth
model_lin = Prophet()
model_lin.fit(north_demand)
future_lin = model_lin.make_future_dataframe(periods=550)
forecast_lin = model_lin.predict(future_lin)
fig_lin = model_lin.plot(forecast_lin,figsize=(16,4) )
#logistic growth
north_demand['cap']= north_capacity
model_log = Prophet(growth='logistic')
model_log.fit(north_demand)
future_log = model_log.make_future_dataframe(periods=550)
future_log['cap'] = north_capacity
forecast_log = model_log.predict(future_log)
fig_log = model_log.plot(forecast_log, figsize=(16,4) )
df_cv1 = cross_validation(model_lin, initial='730 days', period='180 days', horizon = '365 days')
df_p1 = performance_metrics(df_cv1)
df_cv2 = cross_validation(model_log, initial='730 days', period='180 days', horizon = '365 days')
df_p2 = performance_metrics(df_cv2)<jupyter_output><empty_output><jupyter_text>The below charts shows linear growth is too optimistic and logistic growth is much realistic for electricity demand, eventhough the rmse is better for linear growth type for certain forecasts<jupyter_code>#root mean square error evaluation
df1=df_p1[['horizon','rmse']].copy()
df1['model']='linear'
df2=df_p2[['horizon','rmse']].copy()
df2['model']='logistic'
dfc = df1.append(df2)
sns.relplot(y='rmse', x='horizon', kind='line', data=dfc, hue='model', aspect=3, height=5);
fig1 = model_lin.plot_components(forecast_lin)
fig2 = model_log.plot_components(forecast_log)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10316075237541206, 'fraction_numerical': 0.016288539848749273, 'mean_word_length': 6.574155653450807, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '407122', 'license': 'MIT', 'n_tokens_mistral': 1661, 'n_tokens_neox': 1564, 'n_words': 488, 'path': 'demand_forecast_electricity.ipynb', 'repo_name': 'ms-shyamkumar/demand-forecasting', 'size': '5157'}