import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Dropout
from sklearn.metrics import mean_absolute_percentage_error
# Load the dataset
data = pd.read_excel('NR_Demand.xlsx')
# Convert 'Date' to datetime object
data['Date'] = pd.to_datetime(data['Date'])
# Separate 2023 and 2024 data
train_data = data[data['Date'].dt.year == 2023]
test_data = data[(data['Date'].dt.year == 2024) & (data['Date'].dt.month <= 3)]  # January to March 2024
# Define prediction period (April, May, June 2024)
predict_dates = pd.date_range(start='2024-04-01', end='2024-06-30', freq='H')
# Preprocess training data (2023)
#train_data['Hour'] = pd.to_datetime(train_data['Start Time'], format='%I:%M %p').dt.hour
#train_data['Hour_sin'] = np.sin(2 * np.pi * train_data['Hour'] / 24)
#train_data['Hour_cos'] = np.cos(2 * np.pi * train_data['Hour'] / 24)
# Map 'Day of the Week' to numerical values
day_of_week_mapping = {'Monday': 0, 'Tuesday': 1, 'Wednesday': 2, 'Thursday': 3, 'Friday': 4, 'Saturday': 5, 'Sunday': 6}
train_data['Day_of_week_num'] = train_data['Day of the Week'].map(day_of_week_mapping)
train_data['Day_of_week_sin'] = np.sin(2 * np.pi * train_data['Day_of_week_num'] / 7)
train_data['Day_of_week_cos'] = np.cos(2 * np.pi * train_data['Day_of_week_num'] / 7)
# Features for LSTM model
features = ['Hour_sin', 'Hour_cos', 'Day_of_week_sin', 'Day_of_week_cos', 'Hourly Demand Met (in MW)']
# Scale the training data
scaler = MinMaxScaler(feature_range=(0, 1))
train_data['Hourly Demand Met (in MW)'] = scaler.fit_transform(train_data[['Hourly Demand Met (in MW)']])
import warnings
warnings.filterwarnings("ignore")# Create sequences for LSTM
def create_sequences(data, time_steps=24):
    sequences = []
    labels = []
    for i in range(len(data) - time_steps):
        seq_data = data[i:(i + time_steps)]
        seq_label = data[i + time_steps]
        sequences.append(seq_data)
        labels.append(seq_label)
    return np.array(sequences), np.array(labels)
X_train, y_train = create_sequences(train_data[features].values, time_steps=24)
# Reshape data for LSTM
X_train = X_train.reshape((X_train.shape[0], X_train.shape[1], X_train.shape[2]))
# 2. Build the LSTM Model
model = Sequential()
model.add(LSTM(50, return_sequences=False, input_shape=(X_train.shape[1], X_train.shape[2])))
model.add(Dropout(0.2))
model.add(Dense(1))
# Compile the model
model.compile(optimizer='adam', loss='mean_squared_error')
# Train the model
model.fit(X_train, y_train, epochs=20, batch_size=32)
# 3. Predict Demand for April to June 2024
# Assuming we start with the test data from Jan to March 2024
# Prepare the test set (January to March 2024)
test_data['Hour'] = pd.to_datetime(test_data['Start Time'], format='%I:%M %p').dt.hour
test_data['Hour_sin'] = np.sin(2 * np.pi * test_data['Hour'] / 24)
test_data['Hour_cos'] = np.cos(2 * np.pi * test_data['Hour'] / 24)
test_data['Day_of_week_num'] = test_data['Day of the Week'].map(day_of_week_mapping)
test_data['Day_of_week_sin'] = np.sin(2 * np.pi * test_data['Day_of_week_num'] / 7)
test_data['Day_of_week_cos'] = np.cos(2 * np.pi * test_data['Day_of_week_num'] / 7)
X_test, y_test = create_sequences(test_data[features].values, time_steps=24)
# Reshape test data
X_test = X_test.reshape((X_test.shape[0], X_test.shape[1], X_test.shape[2]))
# Predict for Jan-Mar 2024
predictions = model.predict(X_test)
# Scale predictions back to original scale
predicted_demand = scaler.inverse_transform(np.concatenate([np.zeros((predictions.shape[0], 4)), predictions], axis=1))[:, -1]
# Compare predictions for April 2024
actual_demand = test_data['Hourly Demand Met (in MW)'].values[-predictions.shape[0]:]
# Calculate MAPE for January to March 2024
mape = mean_absolute_percentage_error(actual_demand, predicted_demand) * 100
print(f'MAPE for Jan-Mar 2024: {mape:.2f}%')
# 4. Visualize Results
plt.figure(figsize=(10,6))
plt.plot(actual_demand, label='Actual Demand')
plt.plot(predicted_demand, label='Predicted Demand', alpha=0.7)
plt.title('LSTM Demand Forecasting for Northern Region (Jan-Mar 2024)')
plt.xlabel('Time (Hourly)')
plt.ylabel('Demand (MW)')
plt.legend()
plt.show()import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import mean_absolute_percentage_error
# Load the dataset
data = pd.read_excel('NR_Demand.xlsx')
# Convert 'Date' to datetime object
data['Date'] = pd.to_datetime(data['Date'])
# Filter the data for 2023 and 2024
train_data = data[data['Date'].dt.year == 2023]
test_data = data[(data['Date'].dt.year == 2024) & (data['Date'].dt.month <= 3)]
# Apply Moving Average on training data (e.g., 7-day or 24-hour window)
window_size = 24  # Use 24-hour moving average for hourly data
train_data['MA_Demand'] = train_data['Hourly Demand Met (in MW)'].rolling(window=window_size).mean()
# Drop NaN values created by the rolling window
train_data.dropna(inplace=True)
# Predict using the last available moving average from the training set for 2024 data
last_moving_average = train_data['MA_Demand'].iloc[-1]
test_data['MA_Prediction'] = last_moving_average  # Using constant prediction
# Calculate MAPE for January-March 2024
actual_demand = test_data['Hourly Demand Met (in MW)'].values
predicted_demand = test_data['MA_Prediction'].values
mape = mean_absolute_percentage_error(actual_demand, predicted_demand) * 100
print(f'MAPE: {mape:.2f}%')
# Plot results
plt.figure(figsize=(10,6))
plt.plot(test_data['Date'], actual_demand, label='Actual Demand')
plt.plot(test_data['Date'], predicted_demand, label='Predicted Demand (Moving Average)', alpha=0.7)
plt.title('Moving Average Demand Forecasting for Northern Region (Jan-Mar 2024)')
plt.xlabel('Date')
plt.ylabel('Demand (MW)')
plt.legend()
plt.show()C:\Users\A\AppData\Local\Temp\ipykernel_4352\2793989846.py:18: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  train_data['MA_Demand'] = train_data['Hourly Demand Met (in MW)'].rolling(window=window_size).mean()
C:\Users\A\AppData\Local\Temp\ipykernel_4352\2793989846.py:21: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  train_data.dropna(inplace=True)
C:\Users\A\AppData\Local\Temp\ipykernel_4352\2793989846.py:25: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  test_data['MA_Prediction'] = last_moving_average  # Using constant predictionMAPE: 15.04%
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import pprint
%matplotlib inlinedf = pd.read_excel("NR_Demand.xlsx")
print("="*50)
print("First Five Rows", "\n")
print(df.head(2), "\n")
print("="*50)
print("Information About Dataset", "\n")
print(df.info(), "\n")
print("="*50)
print("Describe the Dataset", "\n")
print(df.describe(), "\n")
print("="*50)
print("Null Values", "\n")
print(df.isnull().sum(), "\n")==================================================
First Five Rows 
            Region       Date Day of the Week Start Time End Time  \
0  Northern Region 2023-01-01          Sunday   12:00 AM  1:00 AM   
1  Northern Region 2023-01-01          Sunday    1:00 AM  2:00 AM   
   Hourly Demand Met (in MW)  
0                   38793.37  
1                   36485.33   
==================================================
Information About Dataset 
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 11664 entries, 0 to 11663
Data columns (total 6 columns):
 #   Column                     Non-Null Count  Dtype         
---  ------                     --------------  -----         
 0   Region                     11664 non-null  object        
 1   Date                       11664 non-null  datetime64[ns]
 2   Day of the Week            11664 non-null  object        
 3   Start Time                 11664 non-null  object        
 4   End Time                   11664 non-null  object        
 5   Hourly Demand Met (in MW)  11664 non-null  float64       
dtypes: datetime64[ns](1), float64(1), object(4)
memory usage: 546.9+ KB
None 
==================================================
Describe the Dataset 
                      Date  Hourly Demand Met (in MW)
count                11664               11664.000000
mean   2023-08-31 12:00:00               51977.455921
min    2023-01-01 00:00:00               27465.880000
25%    2023-05-02 00:00:00               44210.032500
50%    2023-08-31 12:00:00               51330.625000
75%    2023-12-31 00:00:00               58970.912500
max    2024-04-30 00:00:00               80793.890000
std                    NaN               10418.895695 
==================================================
Null Values 
Region                       0
Date                         0
Day of the Week              0
Start Time                   0
End Time                     0
Hourly Demand Met (in MW)    0
dtype: int64 
import pandas as pd
import matplotlib.pyplot as plt
# Load the dataset
data = pd.read_excel('NR_Demand.xlsx')
# Convert 'Date' to datetime object
data['Date'] = pd.to_datetime(data['Date'])
# Select one day from each season (adjust dates as needed for your dataset)
winter_day = data[(data['Date'] == '2023-01-15')]  # Winter (January)
spring_day = data[(data['Date'] == '2023-04-15')]  # Spring (April)
summer_day = data[(data['Date'] == '2023-07-15')]  # Summer (July)
autumn_day = data[(data['Date'] == '2023-10-15')]  # Autumn (October)
# Plot hourly demand for each season day
plt.figure(figsize=(10,6))
plt.plot(winter_day['Start Time'], winter_day['Hourly Demand Met (in MW)'], label='Winter - 15 Jan', marker='o')
plt.plot(spring_day['Start Time'], spring_day['Hourly Demand Met (in MW)'], label='Spring - 15 April', marker='o')
plt.plot(summer_day['Start Time'], summer_day['Hourly Demand Met (in MW)'], label='Summer - 15 July', marker='o')
plt.plot(autumn_day['Start Time'], autumn_day['Hourly Demand Met (in MW)'], label='Autumn - 15 Oct', marker='o')
# Customize plot
plt.title('Hourly Demand for Four Days Representing Each Season (2023) for NR Region')
plt.xlabel('Time of Day')
plt.ylabel('Demand (MW)')
plt.xticks(rotation=45)
plt.legend()
plt.tight_layout()
# Show plot
plt.show()
# Extract all Data Like Year MOnth Day Time etc
dataset = df
dataset["Month"] = pd.to_datetime(df["Date"]).dt.month
dataset["Year"] = pd.to_datetime(df["Date"]).dt.year
dataset["Date"] = pd.to_datetime(df["Date"]).dt.date
dataset["Time"] = pd.to_datetime(df["Start Time"]).dt.time
dataset["Day"] = pd.to_datetime(df["Date"]).dt.day_name()
dataset = df.set_index("Date")
dataset.index = pd.to_datetime(dataset.index)
dataset.head(5)C:\Users\A\AppData\Local\Temp\ipykernel_4352\1607697221.py:6: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  dataset["Time"] = pd.to_datetime(df["Start Time"]).dt.time| Region | Day of the Week | Start Time | End Time | Hourly Demand Met (in MW) | Month | Year | Time | Day | |
|---|---|---|---|---|---|---|---|---|---|
| Date | |||||||||
| 1970-01-01 | Northern Region | Sunday | 12:00 AM | 1:00 AM | 38793.37 | 1 | 1970 | 00:00:00 | Thursday | 
| 1970-01-01 | Northern Region | Sunday | 1:00 AM | 2:00 AM | 36485.33 | 1 | 1970 | 01:00:00 | Thursday | 
| 1970-01-01 | Northern Region | Sunday | 2:00 AM | 3:00 AM | 35203.58 | 1 | 1970 | 02:00:00 | Thursday | 
| 1970-01-01 | Northern Region | Sunday | 3:00 AM | 4:00 AM | 35020.51 | 1 | 1970 | 03:00:00 | Thursday | 
| 1970-01-01 | Northern Region | Sunday | 4:00 AM | 5:00 AM | 36340.32 | 1 | 1970 | 04:00:00 | Thursday | 
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.holtwinters import ExponentialSmoothing
# Load the dataset
data = pd.read_excel('NR_Demand.xlsx')
# Convert 'Date' to datetime object
data['Date'] = pd.to_datetime(data['Date'])
# Aggregate data by day for 2023 and Jan-Mar 2024
data['Daily Demand'] = data.groupby('Date')['Hourly Demand Met (in MW)'].transform('sum')
daily_data = data[['Date', 'Daily Demand']].drop_duplicates()
# Separate train and test data
train_data = daily_data[daily_data['Date'].dt.year == 2023]
test_data = daily_data[(daily_data['Date'].dt.year == 2024) & (daily_data['Date'].dt.month <= 3)]
# Plot daily demand for Jan-Mar 2024
plt.figure(figsize=(10,6))
plt.plot(test_data['Date'], test_data['Daily Demand'], label='Actual Daily Demand', marker='o')
plt.title('Daily Demand for Jan-Mar 2024')
plt.xlabel('Date')
plt.ylabel('Demand (MW)')
plt.xticks(rotation=45)
plt.legend()
plt.tight_layout()
plt.show()
# Apply Exponential Smoothing (Holt-Winters) to predict the next 3 months (April-June 2024)
model = ExponentialSmoothing(train_data['Daily Demand'], seasonal='add', seasonal_periods=90).fit()
forecast = model.forecast(90)  # Forecasting for April, May, and June (90 days)
# Plot actual vs predicted values
plt.figure(figsize=(10,6))
plt.plot(train_data['Date'], train_data['Daily Demand'], label='Train Data (2023)')
plt.plot(test_data['Date'], test_data['Daily Demand'], label='Test Data (Jan-Mar 2024)')
plt.plot(pd.date_range(start='2024-04-01', periods=90, freq='D'), forecast, label='Forecast (Apr-Jun 2024)', linestyle='--', marker='o')
plt.title('Daily Demand Forecast for April-June 2024 using Exponential Smoothing')
plt.xlabel('Date')
plt.ylabel('Daily Demand (MW)')
plt.xticks(rotation=45)
plt.legend()
plt.tight_layout()
plt.show()

df.head()| Region | Date | Day of the Week | Start Time | End Time | Hourly Demand Met (in MW) | Month | Year | Time | Day | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Northern Region | 1970-01-01 | Sunday | 12:00 AM | 1:00 AM | 38793.37 | 1 | 1970 | 00:00:00 | Thursday | 
| 1 | Northern Region | 1970-01-01 | Sunday | 1:00 AM | 2:00 AM | 36485.33 | 1 | 1970 | 01:00:00 | Thursday | 
| 2 | Northern Region | 1970-01-01 | Sunday | 2:00 AM | 3:00 AM | 35203.58 | 1 | 1970 | 02:00:00 | Thursday | 
| 3 | Northern Region | 1970-01-01 | Sunday | 3:00 AM | 4:00 AM | 35020.51 | 1 | 1970 | 03:00:00 | Thursday | 
| 4 | Northern Region | 1970-01-01 | Sunday | 4:00 AM | 5:00 AM | 36340.32 | 1 | 1970 | 04:00:00 | Thursday | 
from matplotlib import style
fig = plt.figure()
ax1 = plt.subplot2grid((1,1), (0,0))
style.use('ggplot')
# Add label argument for the line plot to enable legend
sns.lineplot(x=dataset["Start Time"], y=dataset["Hourly Demand Met (in MW)"], data=df, label='Hourly Demand',errorbar=('ci', 95), estimator=np.mean)
sns.set(rc={'figure.figsize':(15,6)})
plt.title("NR - Mean Hourly Energy Consumption in Year 2023")
plt.xlabel("Hours")
plt.ylabel("Energy in MW")
plt.grid(True)
# Now the legend will work since label is provided
plt.legend()
# Rotate the x-axis labels for better readability
for label in ax1.xaxis.get_ticklabels():
    label.set_rotation(90)
plt.show()
from matplotlib import style
fig = plt.figure()
ax1 = plt.subplot2grid((1,1), (0,0))
style.use('ggplot')
# Add label argument for the line plot to enable legend
sns.lineplot(x=dataset["Start Time"], y=dataset["Hourly Demand Met (in MW)"], data=df, label='Hourly Demand',errorbar=('ci', 95), estimator=np.median)
sns.set(rc={'figure.figsize':(15,6)})
plt.title("NR - Median Hourly Energy Consumption in Year 2023")
plt.xlabel("Hours")
plt.ylabel("Energy in MW")
plt.grid(True)
# Now the legend will work since label is provided
plt.legend()
# Rotate the x-axis labels for better readability
for label in ax1.xaxis.get_ticklabels():
    label.set_rotation(90)
plt.show()
# Extract actual April 2024 data
actual_april_data = daily_data[(daily_data['Date'].dt.year == 2024) & (daily_data['Date'].dt.month == 4)]
# Extract predicted April 2024 data (from forecast)
predicted_april_data = forecast[:30]  # First 30 days of forecast corresponds to April
# Plot comparison
plt.figure(figsize=(10,6))
plt.plot(actual_april_data['Date'], actual_april_data['Daily Demand'], label='Actual April 2024 Demand', marker='o')
plt.plot(pd.date_range(start='2024-04-01', periods=30, freq='D'), predicted_april_data, label='Predicted April 2024 Demand', linestyle='--', marker='o')
plt.title('Comparison of Actual vs Predicted Daily Demand for April 2024')
plt.xlabel('Date')
plt.ylabel('Daily Demand (MW)')
plt.xticks(rotation=45)
plt.legend()
plt.tight_layout()
plt.show()
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# Assuming the data is already loaded, and actual demand for April 2024 is present
actual_april_2024 = data[(data['Date'].dt.year == 2024) & (data['Date'].dt.month == 4)]['Hourly Demand Met (in MW)'].values
# Use MAPE from 2023 data to predict April 2024 (assume `mape` is already calculated)
train_april_2023 = data[(data['Date'].dt.year == 2023) & (data['Date'].dt.month == 4)]['Hourly Demand Met (in MW)'].values
predicted_april_2024 = train_april_2023 * (1 + mape / 100)
# Create a date range for April 2024
dates_april_2024 = pd.date_range(start='2024-04-01', periods=len(actual_april_2024), freq='H')
# Plot actual vs predicted
plt.figure(figsize=(12, 6))
# Plot actual April 2024 data
plt.plot(dates_april_2024, actual_april_2024, label='Actual April 2024', color='blue')
# Plot predicted April 2024 data
plt.plot(dates_april_2024, predicted_april_2024, label='Predicted April 2024 (MAPE)', linestyle='--', color='green')
# Add labels and title
plt.title('Actual vs Predicted Demand for April 2024 (Using MAPE)')
plt.xlabel('Date')
plt.ylabel('Hourly Demand Met (in MW)')
plt.xticks(rotation=45)
plt.legend()
plt.tight_layout()
plt.show()
# Aggregate hourly data to daily demand
daily_demand_2023 = daily_data[(daily_data['Date'].dt.year == 2023) & (daily_data['Date'].dt.month == 4)].groupby(daily_data['Date'].dt.strftime('%d-%m'))['Daily Demand'].sum()
actual_april_data = daily_data[(daily_data['Date'].dt.year == 2024) & (daily_data['Date'].dt.month == 4)]
# Calculate MAPE between 2023 data and predicted values
mape = np.mean(np.abs((daily_demand_2023 - daily_demand_2023.mean()) / daily_demand_2023)) * 100
# Use MAPE to predict April 2024 based on April 2023 data
predicted_april_data = daily_demand_2023 * (1 + (mape / 100))
# Plot comparison
plt.figure(figsize=(10,6))
# Actual April 2024
plt.plot(actual_april_data['Date'], actual_april_data['Daily Demand'], label='Actual April 2024 Demand', marker='o')
# Predicted April 2024 using MAPE
plt.plot(pd.date_range(start='2024-04-01', periods=len(predicted_april_data), freq='D'),
         predicted_april_data.values, label='Predicted April 2024 Demand (MAPE)', linestyle='--', marker='o')
# Add titles and labels
plt.title('Comparison of Actual vs Predicted Daily Demand for April 2024 (MAPE)')
plt.xlabel('Date')
plt.ylabel('Daily Demand (MW)')
plt.xticks(rotation=45)
plt.legend()
plt.tight_layout()
plt.show()
from sklearn.metrics import mean_absolute_percentage_error
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# Load the dataset
data = pd.read_excel('NR_Demand.xlsx')
# Convert 'Date' to datetime object
data['Date'] = pd.to_datetime(data['Date'])
# Aggregate daily demand
data['Daily Demand'] = data.groupby('Date')['Hourly Demand Met (in MW)'].transform('sum')
daily_data = data[['Date', 'Daily Demand']].drop_duplicates()
# Separate 2023 data for Jan-Mar
train_2023 = daily_data[(daily_data['Date'].dt.year == 2023) & (daily_data['Date'].dt.month <= 3)]
# Separate 2024 Jan-Mar data and remove Feb 29 to handle the leap year
test_2024 = daily_data[(daily_data['Date'].dt.year == 2024) & (daily_data['Date'].dt.month <= 3) & (daily_data['Date'] != '2024-02-29')]
# Calculate MAPE between Jan-Mar 2023 and Jan-Mar 2024
mape = mean_absolute_percentage_error(train_2023['Daily Demand'].values, test_2024['Daily Demand'].values) * 100
print(f'MAPE between Jan-Mar 2023 and Jan-Mar 2024: {mape:.2f}%')
# Extrapolate for April-June 2024 based on MAPE
# Get the data from 2023 for Apr-Jun and adjust by the calculated deviation (MAPE)
train_apr_jun_2023 = daily_data[(daily_data['Date'].dt.year == 2023) & (daily_data['Date'].dt.month >= 4) & (daily_data['Date'].dt.month <= 6)]
predicted_apr_jun_2024 = train_apr_jun_2023['Daily Demand'].values * (1 + (mape / 100))
# Plot actual 2023 and predicted 2024 data for Apr-Jun
plt.figure(figsize=(10,6))
plt.plot(train_apr_jun_2023['Date'], train_apr_jun_2023['Daily Demand'], label='Actual Apr-Jun 2023', marker='o')
plt.plot(pd.date_range(start='2024-04-01', periods=len(predicted_apr_jun_2024), freq='D'), predicted_apr_jun_2024, label='Predicted Apr-Jun 2024', linestyle='--', marker='o')
plt.title('Predicted Apr-Jun 2024 Demand Based on Deviation from Jan-Mar 2024 vs 2023')
plt.xlabel('Date')
plt.ylabel('Daily Demand (MW)')
plt.xticks(rotation=45)
plt.legend()
plt.tight_layout()
plt.show()MAPE between Jan-Mar 2023 and Jan-Mar 2024: 8.70%
# Combine actual Jan-Mar 2024 and predicted/extrapolated Jan-Apr 2024 data
# Extract the actual data for Jan-Mar 2024 and April 2024
actual_jan_mar_2024 = test_2024['Daily Demand'].values
actual_april_2024 = daily_data[(daily_data['Date'].dt.year == 2024) & (daily_data['Date'].dt.month == 4)]['Daily Demand'].values
# Extrapolate Jan-Apr 2024 based on deviation (MAPE)
train_jan_apr_2023 = daily_data[(daily_data['Date'].dt.year == 2023) & (daily_data['Date'].dt.month <= 4)]
predicted_jan_apr_2024 = train_jan_apr_2023['Daily Demand'].values * (1 + (mape / 100))
# Combine dates for extrapolated Jan-Apr 2024
dates_jan_apr_2024 = pd.date_range(start='2024-01-01', periods=len(predicted_jan_apr_2024), freq='D')
# Combine actual Jan-Apr 2024 data with the rest of the predicted data for May-Dec
predicted_may_dec_2024 = np.concatenate([actual_april_2024, predicted_jul_dec_2024])
# Plot actual vs predicted for Jan-Apr 2024
plt.figure(figsize=(10,6))
# Plot actual Jan-Apr 2024 data (all in one color)
plt.plot(pd.date_range(start='2024-01-01', periods=len(actual_jan_mar_2024)+len(actual_april_2024), freq='D'),
         np.concatenate([actual_jan_mar_2024, actual_april_2024]), label='Actual Jan-Apr 2024', linestyle='-', color='blue')
# Plot extrapolated Jan-Apr 2024 data
plt.plot(dates_jan_apr_2024, predicted_jan_apr_2024,label='Predicted Jan-Apr 2024', linestyle='--', color='green')
#label='Extrapolated Jan-Apr 2024'
# Plot predicted May-Dec 2024 data
plt.plot(pd.date_range(start='2024-05-01', periods=len(predicted_may_dec_2024), freq='D'), predicted_may_dec_2024, label='Predicted May-Dec 2024', linestyle='--', color='red')
# Plot the actual 2023 data for reference
plt.plot(train_data['Date'], train_data['Daily Demand'], label='Train Data (2023)', linestyle='-', color='orange')
plt.title('Actual and Predicted Jan-Apr 2024 vs Predicted May-Dec 2024 Demand')
plt.xlabel('Date')
plt.ylabel('Daily Demand (MW)')
plt.xticks(rotation=45)
plt.legend()
plt.tight_layout()
plt.show()--------------------------------------------------------------------------- KeyError Traceback (most recent call last) File D:\Softwares\Anaconda\Lib\site-packages\pandas\core\indexes\base.py:3805, in Index.get_loc(self, key) 3804 try: -> 3805 return self._engine.get_loc(casted_key) 3806 except KeyError as err: File index.pyx:167, in pandas._libs.index.IndexEngine.get_loc() File index.pyx:196, in pandas._libs.index.IndexEngine.get_loc() File pandas\\_libs\\hashtable_class_helper.pxi:7081, in pandas._libs.hashtable.PyObjectHashTable.get_item() File pandas\\_libs\\hashtable_class_helper.pxi:7089, in pandas._libs.hashtable.PyObjectHashTable.get_item() KeyError: 'Daily Demand' The above exception was the direct cause of the following exception: KeyError Traceback (most recent call last) Cell In[377], line 32 29 plt.plot(pd.date_range(start='2024-05-01', periods=len(predicted_may_dec_2024), freq='D'), predicted_may_dec_2024, label='Predicted May-Dec 2024', linestyle='--', color='red') 31 # Plot the actual 2023 data for reference ---> 32 plt.plot(train_data['Date'], train_data['Daily Demand'], label='Train Data (2023)', linestyle='-', color='orange') 34 plt.title('Actual and Predicted Jan-Apr 2024 vs Predicted May-Dec 2024 Demand') 35 plt.xlabel('Date') File D:\Softwares\Anaconda\Lib\site-packages\pandas\core\frame.py:4102, in DataFrame.__getitem__(self, key) 4100 if self.columns.nlevels > 1: 4101 return self._getitem_multilevel(key) -> 4102 indexer = self.columns.get_loc(key) 4103 if is_integer(indexer): 4104 indexer = [indexer] File D:\Softwares\Anaconda\Lib\site-packages\pandas\core\indexes\base.py:3812, in Index.get_loc(self, key) 3807 if isinstance(casted_key, slice) or ( 3808 isinstance(casted_key, abc.Iterable) 3809 and any(isinstance(x, slice) for x in casted_key) 3810 ): 3811 raise InvalidIndexError(key) -> 3812 raise KeyError(key) from err 3813 except TypeError: 3814 # If we have a listlike key, _check_indexing_error will raise 3815 # InvalidIndexError. Otherwise we fall through and re-raise 3816 # the TypeError. 3817 self._check_indexing_error(key) KeyError: 'Daily Demand'

# Combine actual Jan-Mar 2024 and predicted/extrapolated Jan-Apr 2024 data
# Extract the actual data for Jan-Mar 2024 and April 2024
actual_jan_mar_2024 = test_2024['Daily Demand'].values
actual_april_2024 = daily_data[(daily_data['Date'].dt.year == 2024) & (daily_data['Date'].dt.month == 4)]['Daily Demand'].values
# Extrapolate Jan-Apr 2024 based on deviation (MAPE)
train_jan_apr_2023 = daily_data[(daily_data['Date'].dt.year == 2023) & (daily_data['Date'].dt.month <= 4)]
predicted_jan_apr_2024 = train_jan_apr_2023['Daily Demand'].values * (1 + (mape / 100))
# Combine dates for extrapolated Jan-Apr 2024
dates_jan_apr_2024 = pd.date_range(start='2024-01-01', periods=len(predicted_jan_apr_2024), freq='D')
# Combine actual Jan-Apr 2024 data with the rest of the predicted data for May-Dec
predicted_may_dec_2024 = np.concatenate([actual_april_2024, predicted_jul_dec_2024])
# Plot actual vs predicted for Jan-Apr 2024
plt.figure(figsize=(10,6))
# Plot actual Jan-Apr 2024 data (all in one color)
plt.plot(pd.date_range(start='2024-01-01', periods=len(actual_jan_mar_2024)+len(actual_april_2024), freq='D'),
         np.concatenate([actual_jan_mar_2024, actual_april_2024]), label='Actual Jan-Apr 2024', linestyle='-', color='blue')
# Plot extrapolated Jan-Apr 2024 data
plt.plot(dates_jan_apr_2024, predicted_jan_apr_2024,label='Predicted Jan-Apr 2024', linestyle='--', color='green')
#label='Extrapolated Jan-Apr 2024'
# Plot predicted May-Dec 2024 data
plt.plot(pd.date_range(start='2024-05-01', periods=len(predicted_may_dec_2024), freq='D'), predicted_may_dec_2024, label='Predicted May-Dec 2024', linestyle='--', color='red')
# Plot the actual 2023 data for reference
plt.plot(train_data['Date'], train_data['Daily Demand'], label='Train Data (2023)', linestyle='-', color='orange')
plt.title('Actual and Predicted Jan-Apr 2024 vs Predicted May-Dec 2024 Demand')
plt.xlabel('Date')
plt.ylabel('Daily Demand (MW)')
plt.xticks(rotation=45)
plt.legend()
plt.tight_layout()
plt.show()
# Combine actual Jan-Mar 2024 and predicted/extrapolated Jan-Apr 2024 data
# Extract the actual data for Jan-Mar 2024 and April 2024
actual_jan_mar_2024 = test_2024['Daily Demand'].values
actual_april_2024 = daily_data[(daily_data['Date'].dt.year == 2024) & (daily_data['Date'].dt.month == 4)]['Daily Demand'].values
# Extrapolate Jan-Apr 2024 based on deviation (MAPE)
train_jan_apr_2023 = daily_data[(daily_data['Date'].dt.year == 2023) & (daily_data['Date'].dt.month <= 4)]
predicted_jan_apr_2024 = train_jan_apr_2023['Daily Demand'].values * (1 + (mape / 100))
# Combine dates for extrapolated Jan-Apr 2024
dates_jan_apr_2024 = pd.date_range(start='2024-01-01', periods=len(predicted_jan_apr_2024), freq='D')
# Combine actual Jan-Apr 2024 data with the rest of the predicted data for May-June
predicted_may_jun_2024 = np.concatenate([actual_april_2024, predicted_jul_dec_2024[:61]])  # Predicting up to June
# Plot actual vs predicted for Jan-Jun 2024
plt.figure(figsize=(10,6))
# Plot actual Jan-Apr 2024 data (all in one color)
plt.plot(pd.date_range(start='2024-01-01', periods=len(actual_jan_mar_2024)+len(actual_april_2024), freq='D'),
         np.concatenate([actual_jan_mar_2024, actual_april_2024]), label='Actual Jan-Apr 2024', linestyle='-', color='blue')
# Plot extrapolated Jan-Apr 2024 data
plt.plot(dates_jan_apr_2024, predicted_jan_apr_2024, label='Predicted Jan-Apr 2024', linestyle='--', color='green')
# Plot predicted May-Jun 2024 data
plt.plot(pd.date_range(start='2024-05-01', periods=len(predicted_may_jun_2024), freq='D'), predicted_may_jun_2024, label='Predicted May-Jun 2024', linestyle='--', color='red')
# Plot the actual 2023 data for reference (not zoomed in)
# You can remove this if it clutters the zoomed view
plt.plot(train_data['Date'], train_data['Daily Demand'], label='Train Data (2023)', linestyle='-', color='orange')
# Set the x-limits to zoom into Jan-Jun 2024
plt.xlim(pd.Timestamp('2024-01-01'), pd.Timestamp('2024-06-30'))
plt.title('Zoomed: Actual and Extrapolated Jan-Apr 2024 vs Predicted May-Jun 2024 Demand')
plt.xlabel('Date')
plt.ylabel('Daily Demand (MW)')
plt.xticks(rotation=45)
plt.legend()
plt.tight_layout()
plt.show()
# Combine actual Jan-Mar 2024 and predicted/extrapolated data for Jan-Jun 2024
# Extract the actual data for Jan-Mar 2024 and April 2024
actual_jan_mar_2024 = test_2024['Daily Demand'].values
actual_april_2024 = daily_data[(daily_data['Date'].dt.year == 2024) & (daily_data['Date'].dt.month == 4)]['Daily Demand'].values
# Extrapolate Jan-Apr 2024 based on deviation (MAPE)
train_jan_apr_2023 = daily_data[(daily_data['Date'].dt.year == 2023) & (daily_data['Date'].dt.month <= 4)]
predicted_jan_jun_2024 = train_jan_apr_2023['Daily Demand'].values * (1 + (mape / 100))
# Combine dates for extrapolated Jan-Jun 2024
dates_jan_jun_2024 = pd.date_range(start='2024-01-01', periods=len(predicted_jan_jun_2024), freq='D')
# Combine actual Jan-Mar 2024 with predicted data from April to June for a continuous prediction
predicted_data_2024 = np.concatenate([actual_jan_mar_2024, predicted_jan_jun_2024[len(actual_jan_mar_2024):]])
# Plot the combined actual and predicted data for Jan-Jun 2024
plt.figure(figsize=(10,6))
# Plot actual Jan-Mar 2024 data
plt.plot(pd.date_range(start='2024-01-01', periods=len(actual_jan_mar_2024), freq='D'),
         actual_jan_mar_2024, label='Actual Jan-Mar 2024', linestyle='-', color='blue')
# Plot predicted Jan-Jun 2024 data
plt.plot(pd.date_range(start='2024-04-01', periods=len(predicted_data_2024), freq='D'), predicted_data_2024, label='Predicted Jan-Jun 2024', linestyle='--', color='green')
# Set the x-limits to zoom into Jan-Jun 2024
plt.xlim(pd.Timestamp('2024-01-01'), pd.Timestamp('2024-06-30'))
plt.title('Zoomed: Actual Jan-Mar 2024 vs Predicted Jan-Jun 2024 Demand')
plt.xlabel('Date')
plt.ylabel('Daily Demand (MW)')
plt.xticks(rotation=45)
plt.legend()
plt.tight_layout()
plt.show()
data.head(5)| Region | Date | Day of the Week | Start Time | End Time | Hourly Demand Met (in MW) | Daily Demand | |
|---|---|---|---|---|---|---|---|
| 0 | Northern Region | 2023-01-01 | Sunday | 12:00 AM | 1:00 AM | 38793.37 | 1123719.4 | 
| 1 | Northern Region | 2023-01-01 | Sunday | 1:00 AM | 2:00 AM | 36485.33 | 1123719.4 | 
| 2 | Northern Region | 2023-01-01 | Sunday | 2:00 AM | 3:00 AM | 35203.58 | 1123719.4 | 
| 3 | Northern Region | 2023-01-01 | Sunday | 3:00 AM | 4:00 AM | 35020.51 | 1123719.4 | 
| 4 | Northern Region | 2023-01-01 | Sunday | 4:00 AM | 5:00 AM | 36340.32 | 1123719.4 | 
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# Convert 'Start Time' and 'End Time' to proper datetime objects for sorting
df['Start Time'] = pd.to_datetime(df['Start Time'], format='%I:%M %p')
# Extract actual hourly data for Jan-Mar 2024
actual_jan_mar_2024_hourly = data['Hourly Demand Met (in MW)'].values
# Extrapolate Jan-Apr 2024 based on hourly deviation (MAPE)
train_jan_apr_2023_hourly = daily_data[(daily_data['Date'].dt.year == 2023) & (daily_data['Date'].dt.month <= 4)]
predicted_jan_jun_2024_hourly = data['Hourly Demand Met (in MW)'].values * (1 + (mape / 100))
# Combine dates for extrapolated hourly data from Jan-Jun 2024
dates_jan_jun_2024_hourly = pd.date_range(start='2024-01-01 00:00:00', periods=len(predicted_jan_jun_2024_hourly), freq='h')
# Combine actual Jan-Mar 2024 with predicted hourly data from April to June
predicted_data_2024_hourly = np.concatenate([actual_jan_mar_2024_hourly, predicted_jan_jun_2024_hourly[len(actual_jan_mar_2024_hourly):]])
# Plot the combined actual and predicted hourly data for Jan-Jun 2024
plt.figure(figsize=(12,6))
# Plot actual Jan-Mar 2024 hourly data
plt.plot(dates_jan_jun_2024_hourly[:len(actual_jan_mar_2024_hourly)],
         actual_jan_mar_2024_hourly, label='Actual Jan-Mar 2024 (Hourly)', linestyle='-', color='blue')
# Plot predicted Jan-Jun 2024 hourly data
plt.plot(dates_jan_jun_2024_hourly, predicted_data_2024_hourly, label='Predicted Jan-Jun 2024 (Hourly)', linestyle='--', color='green')
# Set title and labels
plt.title('Hourly Energy Consumption: Actual vs Predicted (Jan-Jun 2024)')
plt.xlabel('Date')
plt.ylabel('Hourly Energy Demand (MW)')
plt.xticks(rotation=45)
plt.legend()
plt.tight_layout()
plt.show()
import numpy as np
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import LSTM, Dense
import matplotlib.pyplot as plt
# Extract relevant columns for LSTM
hourly_demand = data['Hourly Demand Met (in MW)'].values.reshape(-1, 1)
# Scale the data between 0 and 1 using MinMaxScaler
scaler = MinMaxScaler(feature_range=(0, 1))
scaled_data = scaler.fit_transform(hourly_demand)
# Set the time step (how many hours to use for prediction)
time_step = 24  # Using 24 hours (1 day) as a time step for prediction
# Prepare the training data
X_train, y_train = [], []
for i in range(time_step, len(scaled_data)):
    X_train.append(scaled_data[i - time_step:i, 0])
    y_train.append(scaled_data[i, 0])
X_train, y_train = np.array(X_train), np.array(y_train)
# Reshape X_train to be in the format (samples, time_steps, features)
X_train = np.reshape(X_train, (X_train.shape[0], X_train.shape[1], 1))
# Build the LSTM Model
model = Sequential()
model.add(LSTM(units=50, return_sequences=True, input_shape=(X_train.shape[1], 1)))
model.add(LSTM(units=50))
model.add(Dense(1))
# Compile the model
model.compile(optimizer='adam', loss='mean_squared_error')
# Train the model
model.fit(X_train, y_train, epochs=20, batch_size=32)
# Predict future values
predictions = model.predict(X_train)
# Inverse transform the predictions back to the original scale
predictions = scaler.inverse_transform(predictions)
# Visualize the actual vs predicted values
plt.figure(figsize=(12,6))
plt.plot(hourly_demand[time_step:], label='Actual')
plt.plot(predictions, label='Predicted')
plt.title('Actual vs Predicted Hourly Demand (LSTM)')
plt.xlabel('Time')
plt.ylabel('Hourly Demand Met (in MW)')
plt.legend()
plt.show()D:\Softwares\Anaconda\Lib\site-packages\keras\src\layers\rnn\rnn.py:204: UserWarning: Do not pass an `input_shape`/`input_dim` argument to a layer. When using Sequential models, prefer using an `Input(shape)` object as the first layer in the model instead.
  super().__init__(**kwargs)Epoch 1/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 13s 19ms/step - loss: 0.0241
Epoch 2/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 6s 16ms/step - loss: 0.0040
Epoch 3/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 11s 19ms/step - loss: 0.0015
Epoch 4/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 6s 17ms/step - loss: 0.0010
Epoch 5/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 8s 21ms/step - loss: 9.3667e-04
Epoch 6/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 8s 21ms/step - loss: 7.6057e-04
Epoch 7/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 10s 19ms/step - loss: 7.3900e-04
Epoch 8/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 7s 18ms/step - loss: 7.0528e-04
Epoch 9/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 7s 18ms/step - loss: 6.7631e-04
Epoch 10/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 6s 17ms/step - loss: 6.6344e-04
Epoch 11/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 7s 18ms/step - loss: 6.9789e-04
Epoch 12/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 10s 18ms/step - loss: 6.6491e-04
Epoch 13/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 7s 19ms/step - loss: 6.3890e-04
Epoch 14/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 10s 18ms/step - loss: 6.2410e-04
Epoch 15/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 6s 17ms/step - loss: 6.2724e-04
Epoch 16/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 7s 19ms/step - loss: 6.2907e-04
Epoch 17/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 7s 19ms/step - loss: 6.1487e-04
Epoch 18/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 6s 18ms/step - loss: 6.3083e-04
Epoch 19/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 10s 17ms/step - loss: 5.6240e-04
Epoch 20/20
364/364 ━━━━━━━━━━━━━━━━━━━━ 6s 16ms/step - loss: 5.6765e-04
364/364 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step
import matplotlib.dates as mdates
# Create a date range for the x-axis based on your data
date_range = pd.date_range(start="2023-01-01", periods=len(hourly_demand), freq='H')
# Plot the results
plt.figure(figsize=(12, 6))
# Training data
plt.plot(date_range[:len(train_data)], train_data, label='Training Data')
# Test data
plt.plot(date_range[len(train_data):len(hourly_demand)], test_data, label='Forecasted Data', color='orange')
# Format x-axis to show dates
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
plt.gca().xaxis.set_major_locator(mdates.MonthLocator())
# Rotate x-axis labels for readability
plt.gcf().autofmt_xdate()
# Add title and labels
plt.title('SARIMA Forecast for Hourly Demand')
plt.xlabel('Date')
plt.ylabel('Hourly Demand Met (in MW)')
plt.legend()
plt.tight_layout()
plt.show()C:\Users\A\AppData\Local\Temp\ipykernel_4352\2660867132.py:4: FutureWarning: 'H' is deprecated and will be removed in a future version, please use 'h' instead.
  date_range = pd.date_range(start="2023-01-01", periods=len(hourly_demand), freq='H')
import matplotlib.dates as mdates
# Create a date range for the x-axis based on your data
date_range = pd.date_range(start="2023-01-01", periods=len(hourly_demand), freq='H')
# Plot the results
plt.figure(figsize=(12, 6))
# Training data
plt.plot(date_range[:len(train_data)], train_data, label='Training Data')
# Test data
plt.plot(date_range[len(train_data):len(hourly_demand)], test_data, label='Forecasted Data', color='orange')
# Format x-axis to show dates
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
plt.gca().xaxis.set_major_locator(mdates.MonthLocator())
# Rotate x-axis labels for readability
plt.gcf().autofmt_xdate()
# Add title and labels
plt.title('SARIMA Forecast for Hourly Demand')
plt.xlabel('Date')
plt.ylabel('Hourly Demand Met (in MW)')
plt.legend()
plt.tight_layout()
plt.show()--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[389], line 13 10 plt.plot(date_range[:len(train_data)], train_data, label='Training Data') 12 # Test data ---> 13 plt.plot(date_range[len(train_data):len(hourly_demand)], test_data, label='Forecasted Data', color='orange') 15 # Format x-axis to show dates 16 plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d')) File D:\Softwares\Anaconda\Lib\site-packages\matplotlib\pyplot.py:3590, in plot(scalex, scaley, data, *args, **kwargs) 3582 @_copy_docstring_and_deprecators(Axes.plot) 3583 def plot( 3584 *args: float | ArrayLike | str, (...) 3588 **kwargs, 3589 ) -> list[Line2D]: -> 3590 return gca().plot( 3591 *args, 3592 scalex=scalex, 3593 scaley=scaley, 3594 **({"data": data} if data is not None else {}), 3595 **kwargs, 3596 ) File D:\Softwares\Anaconda\Lib\site-packages\matplotlib\axes\_axes.py:1724, in Axes.plot(self, scalex, scaley, data, *args, **kwargs) 1481 """ 1482 Plot y versus x as lines and/or markers. 1483 (...) 1721 (``'green'``) or hex strings (``'#008000'``). 1722 """ 1723 kwargs = cbook.normalize_kwargs(kwargs, mlines.Line2D) -> 1724 lines = [*self._get_lines(self, *args, data=data, **kwargs)] 1725 for line in lines: 1726 self.add_line(line) File D:\Softwares\Anaconda\Lib\site-packages\matplotlib\axes\_base.py:303, in _process_plot_var_args.__call__(self, axes, data, *args, **kwargs) 301 this += args[0], 302 args = args[1:] --> 303 yield from self._plot_args( 304 axes, this, kwargs, ambiguous_fmt_datakey=ambiguous_fmt_datakey) File D:\Softwares\Anaconda\Lib\site-packages\matplotlib\axes\_base.py:499, in _process_plot_var_args._plot_args(self, axes, tup, kwargs, return_kwargs, ambiguous_fmt_datakey) 496 axes.yaxis.update_units(y) 498 if x.shape[0] != y.shape[0]: --> 499 raise ValueError(f"x and y must have same first dimension, but " 500 f"have shapes {x.shape} and {y.shape}") 501 if x.ndim > 2 or y.ndim > 2: 502 raise ValueError(f"x and y can be no greater than 2D, but have " 503 f"shapes {x.shape} and {y.shape}") ValueError: x and y must have same first dimension, but have shapes (11299,) and (91, 2)

# Plot the results
plt.figure(figsize=(12, 6))
# Training data
plt.plot(date_range[:len(train_data)], train_data, label='Training Data')
# Forecasted data (previously labeled as 'Test Data')
plt.plot(date_range[len(train_data):len(hourly_demand)], test_data, label='Forecasted Data', color='orange')
# Format x-axis to show dates
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
plt.gca().xaxis.set_major_locator(mdates.MonthLocator())
# Rotate x-axis labels for readability
plt.gcf().autofmt_xdate()
# Zoom into Jan 2024 to June 2024
plt.xlim(pd.Timestamp('2024-01-01'), pd.Timestamp('2024-04-30'))
# Add title and labels
plt.title('SARIMA Forecast for Hourly Demand (Jan 2024 - June 2024)')
plt.xlabel('Date')
plt.ylabel('Hourly Demand Met (in MW)')
plt.legend()
plt.tight_layout()
plt.show()