Upload SARIMAX.ipynb
Browse files- SARIMAX.ipynb +821 -0
SARIMAX.ipynb
ADDED
@@ -0,0 +1,821 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"cells": [
|
3 |
+
{
|
4 |
+
"cell_type": "markdown",
|
5 |
+
"id": "24884304-ab6c-462a-bf6b-2a8abf74c9cc",
|
6 |
+
"metadata": {},
|
7 |
+
"source": [
|
8 |
+
"# SARIMAX for the prediction of energy consumption data over 48 hours"
|
9 |
+
]
|
10 |
+
},
|
11 |
+
{
|
12 |
+
"cell_type": "code",
|
13 |
+
"execution_count": null,
|
14 |
+
"id": "05f2b198-d2f4-484b-8d63-5e590e3223b2",
|
15 |
+
"metadata": {},
|
16 |
+
"outputs": [],
|
17 |
+
"source": [
|
18 |
+
"#Install all required packages with 'conda install NAME' or with pip install NAME'\n",
|
19 |
+
"# pandas\n",
|
20 |
+
"# numpy\n",
|
21 |
+
"# matplotlib\n",
|
22 |
+
"# scikit-learn\n",
|
23 |
+
"# statsmodels\n",
|
24 |
+
"# pmdarima\n",
|
25 |
+
"# psutil"
|
26 |
+
]
|
27 |
+
},
|
28 |
+
{
|
29 |
+
"cell_type": "code",
|
30 |
+
"execution_count": 2,
|
31 |
+
"id": "ca3f47bb-e6ef-4a33-a60d-77c500a9c6ab",
|
32 |
+
"metadata": {},
|
33 |
+
"outputs": [],
|
34 |
+
"source": [
|
35 |
+
"#Import all required libraries\n",
|
36 |
+
"import sys # Provides access to some variables used or maintained by the interpreter\n",
|
37 |
+
"import pandas as pd # Library for data manipulation and analysis, ideal for working with structured data like tables\n",
|
38 |
+
"import numpy as np # For scientific computing, support for large, multi-dimensional arrays and matrices\n",
|
39 |
+
"import matplotlib.pyplot as plt # For creating static, interactive, and animated visualizations\n",
|
40 |
+
"import matplotlib.dates as mdates # Provides matplotlib with date-specific plotting tools\n",
|
41 |
+
"from sklearn.preprocessing import MinMaxScaler # For scaling and normalizing features, often useful in data preprocessing\n",
|
42 |
+
"from sklearn.metrics import mean_squared_error, mean_absolute_error # For calculating common statistical error metrics\n",
|
43 |
+
"import pmdarima as pm # For ARIMA modeling in Python, which simplifies the process of building ARIMA models\n",
|
44 |
+
"from pmdarima.model_selection import train_test_split # Provides model selection capabilities like train/test splits\n",
|
45 |
+
"import statsmodels.api as sm # Provides many statistical models and functions\n",
|
46 |
+
"from statsmodels.graphics.tsaplots import plot_acf, plot_pacf # For plotting autocorrelation and partial autocorrelation charts\n",
|
47 |
+
"import psutil # For accessing system details and process utilities, helpful for monitoring system performance\n",
|
48 |
+
"from pathlib import Path # Used for filesystem path manipulation in an object-oriented way"
|
49 |
+
]
|
50 |
+
},
|
51 |
+
{
|
52 |
+
"cell_type": "code",
|
53 |
+
"execution_count": 1,
|
54 |
+
"id": "88b3929e-0b04-4036-b43e-5738f74b2bc9",
|
55 |
+
"metadata": {},
|
56 |
+
"outputs": [
|
57 |
+
{
|
58 |
+
"name": "stdout",
|
59 |
+
"output_type": "stream",
|
60 |
+
"text": [
|
61 |
+
"/home/sarah/anaconda3/envs/BT2024SARIMAModel/bin/python\n"
|
62 |
+
]
|
63 |
+
}
|
64 |
+
],
|
65 |
+
"source": [
|
66 |
+
"#To display the current environment\n",
|
67 |
+
"print(sys.executable)"
|
68 |
+
]
|
69 |
+
},
|
70 |
+
{
|
71 |
+
"cell_type": "code",
|
72 |
+
"execution_count": 3,
|
73 |
+
"id": "ad3b8a68-11be-4cf0-9d33-dfcea476d122",
|
74 |
+
"metadata": {},
|
75 |
+
"outputs": [
|
76 |
+
{
|
77 |
+
"name": "stdout",
|
78 |
+
"output_type": "stream",
|
79 |
+
"text": [
|
80 |
+
"Erste und letzte Zeilen aus dfClimaAll:\n",
|
81 |
+
" dy Globalstrahlung_15Min Sonnenhöhe ExtraterrestrischeStrahlung \\\n",
|
82 |
+
"0 1 0 -65.0 0 \n",
|
83 |
+
"1 1 0 -65.0 0 \n",
|
84 |
+
"2 1 0 -65.4 0 \n",
|
85 |
+
"3 1 0 -65.5 0 \n",
|
86 |
+
"4 1 0 -65.2 0 \n",
|
87 |
+
"\n",
|
88 |
+
" StundenwertStrahlung Diffusstrahlung StrahlungGeneigteFläche \\\n",
|
89 |
+
"0 0 0 0 \n",
|
90 |
+
"1 0 0 0 \n",
|
91 |
+
"2 0 0 0 \n",
|
92 |
+
"3 0 0 0 \n",
|
93 |
+
"4 0 0 0 \n",
|
94 |
+
"\n",
|
95 |
+
" DiffusstrahlungGeneigteFläche Direktnormalstrahlung Lufttemperatur \\\n",
|
96 |
+
"0 0 0 9.2 \n",
|
97 |
+
"1 0 0 9.2 \n",
|
98 |
+
"2 0 0 9.2 \n",
|
99 |
+
"3 0 0 9.2 \n",
|
100 |
+
"4 0 0 9.1 \n",
|
101 |
+
"\n",
|
102 |
+
" Windgeschwindigkeit Schönwetterstrahlung Taupunkttemperatur TheorPVProd \\\n",
|
103 |
+
"0 1.8 0 7.9 0 \n",
|
104 |
+
"1 1.8 0 7.9 0 \n",
|
105 |
+
"2 1.8 0 7.9 0 \n",
|
106 |
+
"3 1.8 0 7.9 0 \n",
|
107 |
+
"4 1.8 0 7.8 0 \n",
|
108 |
+
"\n",
|
109 |
+
" TimestampWeather \n",
|
110 |
+
"0 2023-01-01 00:00:00 \n",
|
111 |
+
"1 2023-01-01 00:15:00 \n",
|
112 |
+
"2 2023-01-01 00:30:00 \n",
|
113 |
+
"3 2023-01-01 00:45:00 \n",
|
114 |
+
"4 2023-01-01 01:00:00 \n",
|
115 |
+
" dy Globalstrahlung_15Min Sonnenhöhe ExtraterrestrischeStrahlung \\\n",
|
116 |
+
"35035 365 0 -56.5 0 \n",
|
117 |
+
"35036 365 0 -58.5 0 \n",
|
118 |
+
"35037 365 0 -60.3 0 \n",
|
119 |
+
"35038 365 0 -61.9 0 \n",
|
120 |
+
"35039 365 0 -63.3 0 \n",
|
121 |
+
"\n",
|
122 |
+
" StundenwertStrahlung Diffusstrahlung StrahlungGeneigteFläche \\\n",
|
123 |
+
"35035 0 0 0 \n",
|
124 |
+
"35036 0 0 0 \n",
|
125 |
+
"35037 0 0 0 \n",
|
126 |
+
"35038 0 0 0 \n",
|
127 |
+
"35039 0 0 0 \n",
|
128 |
+
"\n",
|
129 |
+
" DiffusstrahlungGeneigteFläche Direktnormalstrahlung Lufttemperatur \\\n",
|
130 |
+
"35035 0 0 5.5 \n",
|
131 |
+
"35036 0 0 5.5 \n",
|
132 |
+
"35037 0 0 5.5 \n",
|
133 |
+
"35038 0 0 5.5 \n",
|
134 |
+
"35039 0 0 4.9 \n",
|
135 |
+
"\n",
|
136 |
+
" Windgeschwindigkeit Schönwetterstrahlung Taupunkttemperatur \\\n",
|
137 |
+
"35035 2.4 0 -18.2 \n",
|
138 |
+
"35036 2.4 0 -18.2 \n",
|
139 |
+
"35037 2.4 0 -18.2 \n",
|
140 |
+
"35038 2.4 0 -18.2 \n",
|
141 |
+
"35039 1.8 0 -14.0 \n",
|
142 |
+
"\n",
|
143 |
+
" TheorPVProd TimestampWeather \n",
|
144 |
+
"35035 0 2023-12-31 22:45:00 \n",
|
145 |
+
"35036 0 2023-12-31 23:00:00 \n",
|
146 |
+
"35037 0 2023-12-31 23:15:00 \n",
|
147 |
+
"35038 0 2023-12-31 23:30:00 \n",
|
148 |
+
"35039 0 2023-12-31 23:45:00 \n",
|
149 |
+
"Anzahl fehlender Werte pro Spalte:\n",
|
150 |
+
"dy 0\n",
|
151 |
+
"Globalstrahlung_15Min 0\n",
|
152 |
+
"Sonnenhöhe 0\n",
|
153 |
+
"ExtraterrestrischeStrahlung 0\n",
|
154 |
+
"StundenwertStrahlung 0\n",
|
155 |
+
"Diffusstrahlung 0\n",
|
156 |
+
"StrahlungGeneigteFläche 0\n",
|
157 |
+
"DiffusstrahlungGeneigteFläche 0\n",
|
158 |
+
"Direktnormalstrahlung 0\n",
|
159 |
+
"Lufttemperatur 0\n",
|
160 |
+
"Windgeschwindigkeit 0\n",
|
161 |
+
"Schönwetterstrahlung 0\n",
|
162 |
+
"Taupunkttemperatur 0\n",
|
163 |
+
"TheorPVProd 0\n",
|
164 |
+
"TimestampWeather 0\n",
|
165 |
+
"dtype: int64\n",
|
166 |
+
"Anzahl der Zeilen in dfClimaAll: 35040\n"
|
167 |
+
]
|
168 |
+
}
|
169 |
+
],
|
170 |
+
"source": [
|
171 |
+
"# Step 1 - Reading Data\n",
|
172 |
+
"\n",
|
173 |
+
"## dfClimaAll: Data from 2021-2023\n",
|
174 |
+
"## dfEnergyAll: All data from the transformer station from 2021-2023\n",
|
175 |
+
"\n",
|
176 |
+
"# Load data for 2021\n",
|
177 |
+
"dfClima21 = pd.read_excel('/home/sarah/Documents/BT2024/Weather_Data/2021TimeWeather.xlsx')\n",
|
178 |
+
"\n",
|
179 |
+
"# Load data for 2022\n",
|
180 |
+
"dfClima22 = pd.read_excel('/home/sarah/Documents/BT2024/Weather_Data/2022TimeWeather.xlsx')\n",
|
181 |
+
"\n",
|
182 |
+
"# Load data for 2023\n",
|
183 |
+
"dfClima23 = pd.read_excel('/home/sarah/Documents/BT2024/Weather_Data/2023TimeWeather.xlsx')\n",
|
184 |
+
"\n",
|
185 |
+
"# Merge the DataFrames\n",
|
186 |
+
"#Only DF23\n",
|
187 |
+
"dfClimaAll = dfClima23.copy()\n",
|
188 |
+
"#All DFs:\n",
|
189 |
+
"#dfClimaAll = pd.concat([dfClima21, dfClima22, dfClima23])\n",
|
190 |
+
"\n",
|
191 |
+
"# Check the resulting DataFrame\n",
|
192 |
+
"print(\"First and last rows from dfClimaAll:\")\n",
|
193 |
+
"print(dfClimaAll.head())\n",
|
194 |
+
"print(dfClimaAll.tail())\n",
|
195 |
+
"\n",
|
196 |
+
"# Check for missing values in each column\n",
|
197 |
+
"## .isnull(): Returns DF where values with NaN are replaced by True & values without NaN are replaced by False\n",
|
198 |
+
"## sum(): Sums up the number of True values\n",
|
199 |
+
"print(\"Number of missing values per column:\")\n",
|
200 |
+
"print(dfClimaAll.isnull().sum())\n",
|
201 |
+
"\n",
|
202 |
+
"# Convert 'Timestamp' into a Datetime object and set it as index, if not already set\n",
|
203 |
+
"if 'TimestampWeather' in dfClimaAll.columns:\n",
|
204 |
+
" ## pd.to_datetime: Converts values into Datetime objects —> Pandas can then treat these as timestamps\n",
|
205 |
+
" dfClimaAll['TimestampWeather'] = pd.to_datetime(dfClimaAll['TimestampWeather'])\n",
|
206 |
+
" ## set_index: Sets index for the Timestamp column to facilitate access to data based on time points\n",
|
207 |
+
" dfClimaAll = dfClimaAll.set_index('TimestampWeather')\n",
|
208 |
+
"\n",
|
209 |
+
"# Number of rows in dfClimaAll\n",
|
210 |
+
"print(\"Number of rows in dfClimaAll:\", dfClimaAll.shape[0])"
|
211 |
+
]
|
212 |
+
},
|
213 |
+
{
|
214 |
+
"cell_type": "code",
|
215 |
+
"execution_count": 4,
|
216 |
+
"id": "0a4710d5-06ed-4ab1-b396-66797786f0fa",
|
217 |
+
"metadata": {},
|
218 |
+
"outputs": [
|
219 |
+
{
|
220 |
+
"name": "stdout",
|
221 |
+
"output_type": "stream",
|
222 |
+
"text": [
|
223 |
+
"Erste und letzte Zeilen aus dfEnergyAll:\n",
|
224 |
+
" Lastgang\n",
|
225 |
+
"Timestamp \n",
|
226 |
+
"2023-01-01 00:00:00 657.35\n",
|
227 |
+
"2023-01-01 00:15:00 677.68\n",
|
228 |
+
"2023-01-01 00:30:00 644.91\n",
|
229 |
+
"2023-01-01 00:45:00 656.67\n",
|
230 |
+
"2023-01-01 01:00:00 660.77\n",
|
231 |
+
" Lastgang\n",
|
232 |
+
"Timestamp \n",
|
233 |
+
"2023-12-31 22:45:00 833.17\n",
|
234 |
+
"2023-12-31 23:00:00 767.89\n",
|
235 |
+
"2023-12-31 23:15:00 770.04\n",
|
236 |
+
"2023-12-31 23:30:00 730.45\n",
|
237 |
+
"2023-12-31 23:45:00 744.21\n",
|
238 |
+
"Anzahl der Zeilen in dfEnergyAll: 35036\n"
|
239 |
+
]
|
240 |
+
}
|
241 |
+
],
|
242 |
+
"source": [
|
243 |
+
"# Step 1 - Reading Data\n",
|
244 |
+
"\n",
|
245 |
+
"## dfClimaAll: Data from 2021-2023\n",
|
246 |
+
"## dfEnergyAll: All data from the transformer station from 2021-2023\n",
|
247 |
+
"\n",
|
248 |
+
"# Path to the directory containing the Excel files\n",
|
249 |
+
"directory_path = Path('/home/sarah/Documents/BT2024/2023')\n",
|
250 |
+
"\n",
|
251 |
+
"# Create a list of all Excel files in the directory\n",
|
252 |
+
"file_paths = list(directory_path.glob('*.xlsx'))\n",
|
253 |
+
"\n",
|
254 |
+
"# List to store the individual DataFrames\n",
|
255 |
+
"dfs = []\n",
|
256 |
+
"\n",
|
257 |
+
"# Loop over all file paths\n",
|
258 |
+
"for file_path in file_paths:\n",
|
259 |
+
" # Read the Excel file\n",
|
260 |
+
" df = pd.read_excel(file_path)\n",
|
261 |
+
" \n",
|
262 |
+
" # Convert the 'Timestamp' column into a datetime\n",
|
263 |
+
" df['Timestamp'] = pd.to_datetime(df['Timestamp'])\n",
|
264 |
+
" \n",
|
265 |
+
" # Convert the 'Lastgang' column into a numeric data type, treating errors as NaN\n",
|
266 |
+
" df['Lastgang'] = pd.to_numeric(df['Lastgang'], errors='coerce')\n",
|
267 |
+
" \n",
|
268 |
+
" # Sort the DataFrame by the 'Timestamp'\n",
|
269 |
+
" df = df.sort_values(by='Timestamp')\n",
|
270 |
+
" \n",
|
271 |
+
" # Perform linear interpolation for the 'Lastgang' on the individual DataFrame\n",
|
272 |
+
" df['Lastgang'] = df['Lastgang'].interpolate(method='linear')\n",
|
273 |
+
" \n",
|
274 |
+
" # Add the DataFrame to the list\n",
|
275 |
+
" dfs.append(df)\n",
|
276 |
+
"\n",
|
277 |
+
"# Merge all DataFrames in the list\n",
|
278 |
+
"dfEnergyAll = pd.concat(dfs).set_index('Timestamp')\n",
|
279 |
+
"\n",
|
280 |
+
"# Sum the Lastgang values for identical timestamps\n",
|
281 |
+
"dfEnergyAll = dfEnergyAll.groupby('Timestamp').sum()\n",
|
282 |
+
"\n",
|
283 |
+
"# Check the resulting DataFrame\n",
|
284 |
+
"print(\"First and last rows from dfEnergyAll:\")\n",
|
285 |
+
"print(dfEnergyAll.head())\n",
|
286 |
+
"print(dfEnergyAll.tail())\n",
|
287 |
+
"\n",
|
288 |
+
"# Display the number of rows in dfEnergyAll\n",
|
289 |
+
"print(\"Number of rows in dfEnergyAll:\", dfEnergyAll.shape[0])\n"
|
290 |
+
]
|
291 |
+
},
|
292 |
+
{
|
293 |
+
"cell_type": "code",
|
294 |
+
"execution_count": 5,
|
295 |
+
"id": "dda00bbf-4a50-45f8-8c98-c29eff6bf793",
|
296 |
+
"metadata": {},
|
297 |
+
"outputs": [
|
298 |
+
{
|
299 |
+
"name": "stdout",
|
300 |
+
"output_type": "stream",
|
301 |
+
"text": [
|
302 |
+
"Fehlende Zeitstempel in dfEnergyAll:\n",
|
303 |
+
"DatetimeIndex(['2023-03-26 02:00:00', '2023-03-26 02:15:00',\n",
|
304 |
+
" '2023-03-26 02:30:00', '2023-03-26 02:45:00'],\n",
|
305 |
+
" dtype='datetime64[ns]', name='Timestamp', freq=None)\n",
|
306 |
+
"Überprüfen nach dem Ergänzen der fehlenden Zeitstempel:\n",
|
307 |
+
" Lastgang\n",
|
308 |
+
"2023-03-26 02:00:00 520.34\n",
|
309 |
+
"2023-03-26 02:15:00 520.34\n",
|
310 |
+
"2023-03-26 02:30:00 520.34\n",
|
311 |
+
"2023-03-26 02:45:00 520.34\n",
|
312 |
+
"Anzahl der Zeilen in dfClima21: 35040\n",
|
313 |
+
"Anzahl der Zeilen in dfEnergyAll: 35040\n"
|
314 |
+
]
|
315 |
+
},
|
316 |
+
{
|
317 |
+
"name": "stderr",
|
318 |
+
"output_type": "stream",
|
319 |
+
"text": [
|
320 |
+
"/tmp/ipykernel_1561988/424088960.py:29: FutureWarning: DataFrame.fillna with 'method' is deprecated and will raise in a future version. Use obj.ffill() or obj.bfill() instead.\n",
|
321 |
+
" dfEnergyAll = dfEnergyAll.sort_index().fillna(method='ffill')\n"
|
322 |
+
]
|
323 |
+
}
|
324 |
+
],
|
325 |
+
"source": [
|
326 |
+
"# Step 2 - Preparing the Data\n",
|
327 |
+
"\n",
|
328 |
+
"# Create a complete timestamp index for the years 2023 in 15-minute intervals\n",
|
329 |
+
"all_timestamps = pd.date_range(start='2023-01-01 00:00:00', end='2023-12-31 23:45:00', freq='15T')\n",
|
330 |
+
"\n",
|
331 |
+
"# Convert this into a DataFrame\n",
|
332 |
+
"df_all_timestamps = pd.DataFrame(all_timestamps, columns=['Timestamp'])\n",
|
333 |
+
"df_all_timestamps = df_all_timestamps.set_index('Timestamp')\n",
|
334 |
+
"\n",
|
335 |
+
"# Compare the complete timestamp index with dfEnergyAll\n",
|
336 |
+
"missing_timestamps = df_all_timestamps.index.difference(dfEnergyAll.index)\n",
|
337 |
+
"\n",
|
338 |
+
"print(\"Missing timestamps in dfEnergyAll:\")\n",
|
339 |
+
"print(missing_timestamps)\n",
|
340 |
+
"\n",
|
341 |
+
"\n",
|
342 |
+
"# Missing timestamps\n",
|
343 |
+
"missing_timestamps = pd.DatetimeIndex(['2023-03-26 02:00:00', '2023-03-26 02:15:00',\n",
|
344 |
+
" '2023-03-26 02:30:00', '2023-03-26 02:45:00'])\n",
|
345 |
+
"\n",
|
346 |
+
"# Create a DataFrame with the missing timestamps\n",
|
347 |
+
"df_missing = pd.DataFrame(index=missing_timestamps)\n",
|
348 |
+
"\n",
|
349 |
+
"# Merge this DataFrame with the original DataFrame\n",
|
350 |
+
"dfEnergyAll = dfEnergyAll.combine_first(df_missing)\n",
|
351 |
+
"\n",
|
352 |
+
"# Fill the missing values. Use 'ffill' for forward fill.\n",
|
353 |
+
"dfEnergyAll = dfEnergyAll.sort_index().fillna(method='ffill')\n",
|
354 |
+
"\n",
|
355 |
+
"print(\"Check after adding the missing timestamps:\")\n",
|
356 |
+
"print(dfEnergyAll.loc[missing_timestamps])\n",
|
357 |
+
"\n",
|
358 |
+
"# Number of rows in dfClima21\n",
|
359 |
+
"# Ensure dfClima21 is already defined before executing this line.\n",
|
360 |
+
"print(\"Number of rows in dfClima21:\", dfClimaAll.shape[0])\n",
|
361 |
+
"\n",
|
362 |
+
"# Number of rows in dfEnergyAll\n",
|
363 |
+
"print(\"Number of rows in dfEnergyAll:\", dfEnergyAll.shape[0])"
|
364 |
+
]
|
365 |
+
},
|
366 |
+
{
|
367 |
+
"cell_type": "code",
|
368 |
+
"execution_count": 6,
|
369 |
+
"id": "d7e1513e-2337-45c7-92b9-82db88714c50",
|
370 |
+
"metadata": {},
|
371 |
+
"outputs": [
|
372 |
+
{
|
373 |
+
"name": "stdout",
|
374 |
+
"output_type": "stream",
|
375 |
+
"text": [
|
376 |
+
"Anzahl fehlender Werte pro Spalte:\n",
|
377 |
+
"Lastgang 0\n",
|
378 |
+
"StundenwertStrahlung 0\n",
|
379 |
+
"Globalstrahlung_15Min 0\n",
|
380 |
+
"StrahlungGeneigteFläche 0\n",
|
381 |
+
"TheorPVProd 0\n",
|
382 |
+
"Direktnormalstrahlung 0\n",
|
383 |
+
"Schönwetterstrahlung 0\n",
|
384 |
+
"Lufttemperatur 0\n",
|
385 |
+
"dtype: int64\n",
|
386 |
+
"Erste Zeilen aus dfEnergyAll-Bearbeitet:\n",
|
387 |
+
" Lastgang StundenwertStrahlung Globalstrahlung_15Min \\\n",
|
388 |
+
"2023-01-01 00:00:00 657.35 0 0 \n",
|
389 |
+
"2023-01-01 00:15:00 677.68 0 0 \n",
|
390 |
+
"2023-01-01 00:30:00 644.91 0 0 \n",
|
391 |
+
"2023-01-01 00:45:00 656.67 0 0 \n",
|
392 |
+
"2023-01-01 01:00:00 660.77 0 0 \n",
|
393 |
+
"\n",
|
394 |
+
" StrahlungGeneigteFläche TheorPVProd \\\n",
|
395 |
+
"2023-01-01 00:00:00 0 0 \n",
|
396 |
+
"2023-01-01 00:15:00 0 0 \n",
|
397 |
+
"2023-01-01 00:30:00 0 0 \n",
|
398 |
+
"2023-01-01 00:45:00 0 0 \n",
|
399 |
+
"2023-01-01 01:00:00 0 0 \n",
|
400 |
+
"\n",
|
401 |
+
" Direktnormalstrahlung Schönwetterstrahlung \\\n",
|
402 |
+
"2023-01-01 00:00:00 0 0 \n",
|
403 |
+
"2023-01-01 00:15:00 0 0 \n",
|
404 |
+
"2023-01-01 00:30:00 0 0 \n",
|
405 |
+
"2023-01-01 00:45:00 0 0 \n",
|
406 |
+
"2023-01-01 01:00:00 0 0 \n",
|
407 |
+
"\n",
|
408 |
+
" Lufttemperatur \n",
|
409 |
+
"2023-01-01 00:00:00 9.2 \n",
|
410 |
+
"2023-01-01 00:15:00 9.2 \n",
|
411 |
+
"2023-01-01 00:30:00 9.2 \n",
|
412 |
+
"2023-01-01 00:45:00 9.2 \n",
|
413 |
+
"2023-01-01 01:00:00 9.1 \n",
|
414 |
+
" Lastgang StundenwertStrahlung Globalstrahlung_15Min \\\n",
|
415 |
+
"2023-12-31 22:45:00 833.17 0 0 \n",
|
416 |
+
"2023-12-31 23:00:00 767.89 0 0 \n",
|
417 |
+
"2023-12-31 23:15:00 770.04 0 0 \n",
|
418 |
+
"2023-12-31 23:30:00 730.45 0 0 \n",
|
419 |
+
"2023-12-31 23:45:00 744.21 0 0 \n",
|
420 |
+
"\n",
|
421 |
+
" StrahlungGeneigteFläche TheorPVProd \\\n",
|
422 |
+
"2023-12-31 22:45:00 0 0 \n",
|
423 |
+
"2023-12-31 23:00:00 0 0 \n",
|
424 |
+
"2023-12-31 23:15:00 0 0 \n",
|
425 |
+
"2023-12-31 23:30:00 0 0 \n",
|
426 |
+
"2023-12-31 23:45:00 0 0 \n",
|
427 |
+
"\n",
|
428 |
+
" Direktnormalstrahlung Schönwetterstrahlung \\\n",
|
429 |
+
"2023-12-31 22:45:00 0 0 \n",
|
430 |
+
"2023-12-31 23:00:00 0 0 \n",
|
431 |
+
"2023-12-31 23:15:00 0 0 \n",
|
432 |
+
"2023-12-31 23:30:00 0 0 \n",
|
433 |
+
"2023-12-31 23:45:00 0 0 \n",
|
434 |
+
"\n",
|
435 |
+
" Lufttemperatur \n",
|
436 |
+
"2023-12-31 22:45:00 5.5 \n",
|
437 |
+
"2023-12-31 23:00:00 5.5 \n",
|
438 |
+
"2023-12-31 23:15:00 5.5 \n",
|
439 |
+
"2023-12-31 23:30:00 5.5 \n",
|
440 |
+
"2023-12-31 23:45:00 4.9 \n"
|
441 |
+
]
|
442 |
+
}
|
443 |
+
],
|
444 |
+
"source": [
|
445 |
+
"# Step 2 - Preparing the Data\n",
|
446 |
+
"\n",
|
447 |
+
"# To check if the indexes in both DataFrames are set equally\n",
|
448 |
+
"dfClimaAll.index.equals(dfEnergyAll.index)\n",
|
449 |
+
"\n",
|
450 |
+
"# Adding the columns from dfClima21 to dfEnergyAll\n",
|
451 |
+
"dfEnergyAll = dfEnergyAll.join(dfClimaAll[['StundenwertStrahlung', 'Globalstrahlung_15Min', 'StrahlungGeneigteFläche', 'TheorPVProd', 'Direktnormalstrahlung', 'Schönwetterstrahlung', 'Lufttemperatur']])\n",
|
452 |
+
"\n",
|
453 |
+
"# Checking for missing values in each column\n",
|
454 |
+
"print(\"Number of missing values per column:\")\n",
|
455 |
+
"print(dfEnergyAll.isnull().sum())\n",
|
456 |
+
"\n",
|
457 |
+
"# Printing the first and last rows from the dataframe\n",
|
458 |
+
"print(\"First and last rows from dfEnergyAll-Edited:\")\n",
|
459 |
+
"print(dfEnergyAll.head())\n",
|
460 |
+
"print(dfEnergyAll.tail())"
|
461 |
+
]
|
462 |
+
},
|
463 |
+
{
|
464 |
+
"cell_type": "code",
|
465 |
+
"execution_count": 7,
|
466 |
+
"id": "e33a35b4-0b2d-41d0-9be7-5ed46491538b",
|
467 |
+
"metadata": {},
|
468 |
+
"outputs": [
|
469 |
+
{
|
470 |
+
"name": "stdout",
|
471 |
+
"output_type": "stream",
|
472 |
+
"text": [
|
473 |
+
" Lastgang StundenwertStrahlung Globalstrahlung_15Min \\\n",
|
474 |
+
"2023-01-01 00:00:00 657.35 0 0 \n",
|
475 |
+
"2023-01-01 00:15:00 677.68 0 0 \n",
|
476 |
+
"2023-01-01 00:30:00 644.91 0 0 \n",
|
477 |
+
"2023-01-01 00:45:00 656.67 0 0 \n",
|
478 |
+
"2023-01-01 01:00:00 660.77 0 0 \n",
|
479 |
+
"\n",
|
480 |
+
" StrahlungGeneigteFläche TheorPVProd \\\n",
|
481 |
+
"2023-01-01 00:00:00 0 0 \n",
|
482 |
+
"2023-01-01 00:15:00 0 0 \n",
|
483 |
+
"2023-01-01 00:30:00 0 0 \n",
|
484 |
+
"2023-01-01 00:45:00 0 0 \n",
|
485 |
+
"2023-01-01 01:00:00 0 0 \n",
|
486 |
+
"\n",
|
487 |
+
" Direktnormalstrahlung Schönwetterstrahlung \\\n",
|
488 |
+
"2023-01-01 00:00:00 0 0 \n",
|
489 |
+
"2023-01-01 00:15:00 0 0 \n",
|
490 |
+
"2023-01-01 00:30:00 0 0 \n",
|
491 |
+
"2023-01-01 00:45:00 0 0 \n",
|
492 |
+
"2023-01-01 01:00:00 0 0 \n",
|
493 |
+
"\n",
|
494 |
+
" Lufttemperatur Lastgang_Moving_Average \\\n",
|
495 |
+
"2023-01-01 00:00:00 9.2 707.704792 \n",
|
496 |
+
"2023-01-01 00:15:00 9.2 707.704792 \n",
|
497 |
+
"2023-01-01 00:30:00 9.2 707.704792 \n",
|
498 |
+
"2023-01-01 00:45:00 9.2 707.704792 \n",
|
499 |
+
"2023-01-01 01:00:00 9.1 707.704792 \n",
|
500 |
+
"\n",
|
501 |
+
" Lastgang_First_Difference \n",
|
502 |
+
"2023-01-01 00:00:00 20.33 \n",
|
503 |
+
"2023-01-01 00:15:00 20.33 \n",
|
504 |
+
"2023-01-01 00:30:00 -32.77 \n",
|
505 |
+
"2023-01-01 00:45:00 11.76 \n",
|
506 |
+
"2023-01-01 01:00:00 4.10 \n"
|
507 |
+
]
|
508 |
+
},
|
509 |
+
{
|
510 |
+
"name": "stderr",
|
511 |
+
"output_type": "stream",
|
512 |
+
"text": [
|
513 |
+
"/tmp/ipykernel_1561988/3400565057.py:13: FutureWarning: DataFrame.fillna with 'method' is deprecated and will raise in a future version. Use obj.ffill() or obj.bfill() instead.\n",
|
514 |
+
" dfEnergyAll = dfEnergyAll.fillna(method='bfill')\n"
|
515 |
+
]
|
516 |
+
}
|
517 |
+
],
|
518 |
+
"source": [
|
519 |
+
"# Step 2 - Preparing the Data\n",
|
520 |
+
"\n",
|
521 |
+
"# Calculating the moving average for 'Lastgang'\n",
|
522 |
+
"window_size = 96 # This corresponds to 24 hours at 15-minute intervals\n",
|
523 |
+
"dfEnergyAll['Lastgang_Moving_Average'] = dfEnergyAll['Lastgang'].rolling(window=window_size).mean()\n",
|
524 |
+
"\n",
|
525 |
+
"# Calculating the first differences for 'Lastgang'\n",
|
526 |
+
"dfEnergyAll['Lastgang_First_Difference'] = dfEnergyAll['Lastgang'].diff()\n",
|
527 |
+
"\n",
|
528 |
+
"# Since the first `window_size - 1` values of the moving average will be NaN and the first value of the first difference will be NaN, fill these values.\n",
|
529 |
+
"dfEnergyAll = dfEnergyAll.fillna(method='bfill')\n",
|
530 |
+
"\n",
|
531 |
+
"# To check the first few rows to ensure the new features look as expected.\n",
|
532 |
+
"print(dfEnergyAll.head())"
|
533 |
+
]
|
534 |
+
},
|
535 |
+
{
|
536 |
+
"cell_type": "code",
|
537 |
+
"execution_count": 8,
|
538 |
+
"id": "326e34ca-5066-464d-9e84-b1da0b22f755",
|
539 |
+
"metadata": {},
|
540 |
+
"outputs": [
|
541 |
+
{
|
542 |
+
"data": {
|
543 |
+
"image/png": "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9SYiIiIq7lGPoRg/ERERUUlGJ6XWrl2rFsTcv38fx44dw7Jly4wONN58881SR2nx8fHByZMncePGDY3Xbt26BVdXV73z379/H2FhYbh06RJ2795d6pDDbdq0gZWVFc6fP68zKTVp0iSMHz9efp6RkQEvLy+9yyUiIqJH26MeQzF+IiIiopKMTkqpOussbtCgQWjevDmioqIwatQog5fl7OwMZ2fnUssFBQUhPT0df/75J9q1awcAOHToENLT09GhQwed86mCqfPnz2PPnj1wcnIq9b1Onz6N+/fvw93dXWcZhUIBhUJR6rKIiIiIVB71GIrxExEREZUkCSGEKRZ08eJF+Pv7IysryxSL0xAaGorr16/ju+++A1A0nLG3t7facMZNmzZFREQEBgwYgPz8fAwcOBBHjx7Fpk2b1H4NrFOnDqytrXHx4kWsXLkSvXr1grOzM/7++2+8++67sLW1xeHDh2FpaWlQ3TIyMqBUKpGenl7qr4hERERUdZjjHP+oxlCMn4iIiKovQ8/zFqZ4s+zsbMyfPx+enp6mWJxWK1euRMuWLRESEoKQkBD4+/tjxYoVamXOnTuH9PR0AEBiYiI2bNiAxMREPP7443B3d5cfBw4cAFA0DPOuXbvQo0cPNGnSBGPHjkVISAh27txpcEKKiIiI6GExhiIiIqJHmdEtpRwdHdX6QxBCIDMzE7a2tli5ciWeeeYZk1eysuMvfURERNWTKc/xjKHUMX4iIiKqvgw9zxvdp9ScOXPUnltYWKBu3boIDAzElStXjK4oERER0aOAMRQRERGRujL3KZWeno6VK1diyZIlOH78uFHDGVcX/KWPiIioeirPc/yjHkMxfiIiIqq+yr1Pqd27d2PYsGFwd3fH/PnzERoaivj4+IddHBEREdEjgTEUERERURGjbt9LTExEZGQkli5diqysLISFheH+/fuIjo6Gn59fedWRiIiIqEpjDEVERESkyeCWUr169YKfnx/+/vtvzJ8/H9evX8f8+fPLs25EREREVR5jKCIiIiLtDG4ptWPHDowdOxavv/46GjVqVJ51IiIiIqo2GEMRERERaWdwS6l9+/YhMzMTAQEBCAwMxDfffINbt26VZ92IiIiIqjzGUERERETaGZyUCgoKwvfff4+kpCS8+uqrWL16NerVq4fCwkLExMQgMzOzPOtJREREVCUxhiIiIiLSThJCiIed+dy5c1iyZAlWrFiBtLQ0BAcHY8OGDaasX5XAIY2JiIiqp/I6xzOGYvxERERUnRl6nje4pZQ2TZo0wcyZM5GYmIhVq1aVZVFEREREjwzGUERERERlbClFRfhLHxERUfXEc3z54bYlIiKqvszSUoqIiIiIiIiIiOhhMClFRERERERERERmx6QUERERERERERGZHZNSRERERERERERkdkxKERERERERERGR2TEpRUREREREREREZsekFBERERERERERmR2TUkREREREREREZHZMShERERERERERkdkxKUVERERERERERGbHpBQREREREREREZkdk1JERERERERERGR2TEoREREREREREZHZMSlFRERERERERERmx6QUERERERERERGZHZNSRERERERERERkdkxKERERERERERGR2VWZpFRqairCw8OhVCqhVCoRHh6OtLQ0vfOMGDECkiSpPdq3b69WJjc3F2+99RacnZ1hb2+PZ555BomJieW4JkRERETmwxiKiIiIKqsqk5R6/vnncfz4cWzbtg3btm3D8ePHER4eXup8PXv2RFJSkvzYsmWL2uvjxo3DunXrsHr1auzfvx93795Fnz59UFBQUF6rQkRERGQ2jKGIiIiosqpR0RUwxJkzZ7Bt2zYcPHgQgYGBAIDvv/8eQUFBOHfuHJo0aaJzXoVCATc3N62vpaenY8mSJVixYgW6d+8OAPjpp5/g5eWFnTt3okePHqZfGSIiIiIzYQxFRERElVmVaCkVFxcHpVIpB1MA0L59eyiVShw4cEDvvHv37oWLiwsaN26M0aNH4+bNm/JrR44cwf379xESEiJP8/DwQIsWLfQuNzc3FxkZGWoPIiIiosqmMsVQjJ+IiIiopCqRlEpOToaLi4vGdBcXFyQnJ+ucLzQ0FCtXrsTu3bvx9ddf4/Dhw3j66aeRm5srL9fa2hqOjo5q87m6uupdbkREhNwvg1KphJeX10OuGREREVH5qUwxFOMnIiIiKqlCk1JTpkzR6ESz5CM+Ph4AIEmSxvxCCK3TVYYMGYLevXujRYsW6Nu3L7Zu3Yp//vkHmzdv1luv0pY7adIkpKeny4+EhAQD15iIiIio7KpiDMX4iYiIiEqq0D6l3nzzTQwdOlRvGR8fH5w8eRI3btzQeO3WrVtwdXU1+P3c3d3h7e2N8+fPAwDc3NyQl5eH1NRUtV/6bt68iQ4dOuhcjkKhgEKhMPh9iYiIiEypKsZQjJ+IiIiopApNSjk7O8PZ2bnUckFBQUhPT8eff/6Jdu3aAQAOHTqE9PR0vcmjklJSUpCQkAB3d3cAQNu2bWFlZYWYmBiEhYUBAJKSknDq1CnMnDnzIdaIiIiIqPwxhiIiIqLqoEr0KdWsWTP07NkTo0ePxsGDB3Hw4EGMHj0affr0URs1pmnTpli3bh0A4O7du3jvvfcQFxeHy5cvY+/evejbty+cnZ0xYMAAAIBSqcSoUaPw7rvvYteuXTh27BiGDRuGli1byiPJEBEREVVVjKGIiIioMqvQllLGWLlyJcaOHSuP8vLMM8/gm2++UStz7tw5pKenAwAsLS3x119/Yfny5UhLS4O7uzu6du2KqKgo1KpVS55n9uzZqFGjBsLCwpCdnY1u3bohMjISlpaW5ls5IiIionLCGIqIiIgqK0kIISq6ElVdRkYGlEol0tPT4eDgUNHVISIiIhPhOb78cNsSERFVX4ae56vE7XtERERERERERFS9MClFRERERERERERmx6QUERERERERERGZHZNSRERERERERERkdkxKERERERERERGR2TEpRUREREREREREZsekFBERERERERERmR2TUkREREREREREZHZMShERERERERERkdkxKUVERERERERERGbHpBQREREREREREZkdk1JERERERERERGR2TEoREREREREREZHZMSlFRERERERERERmx6QUERERERERERGZHZNSRERERERERERkdkxKERERERERERGR2TEpRUREREREREREZsekFBERERERERERmR2TUkREREREREREZHZMShERERERERERkdkxKUVERERERERERGbHpBQREREREREREZkdk1JERERERERERGR2TEoREREREREREZHZMSlFRERERERERERmx6QUERERERERERGZXZVJSqWmpiI8PBxKpRJKpRLh4eFIS0vTO48kSVofX375pVymS5cuGq8PHTq0nNeGiIiIyDwYQxEREVFlVaOiK2Co559/HomJidi2bRsA4JVXXkF4eDg2btyoc56kpCS151u3bsWoUaMwcOBAtemjR4/GtGnT5Oe2trYmrDkRERFRxWEMRURERJVVlUhKnTlzBtu2bcPBgwcRGBgIAPj+++8RFBSEc+fOoUmTJlrnc3NzU3v+22+/oWvXrmjQoIHadDs7O42yRERERFUdYygiIiKqzKrE7XtxcXFQKpVyMAUA7du3h1KpxIEDBwxaxo0bN7B582aMGjVK47WVK1fC2dkZzZs3x3vvvYfMzEy9y8rNzUVGRobag4iIiKiyqUwxFOMnIiIiKqlKtJRKTk6Gi4uLxnQXFxckJycbtIxly5ahVq1aePbZZ9Wmv/DCC/D19YWbmxtOnTqFSZMm4cSJE4iJidG5rIiICEydOtW4lSAiIiIys8oUQzF+IiIiopIqtKXUlClTdHakqXrEx8cDKOpwsyQhhNbp2ixduhQvvPACbGxs1KaPHj0a3bt3R4sWLTB06FD8+uuv2LlzJ44ePapzWZMmTUJ6err8SEhIMGKtiYiIiMqmKsZQjJ+IiIiopAptKfXmm2+WOkqLj48PTp48iRs3bmi8duvWLbi6upb6Pvv27cO5c+cQFRVVatk2bdrAysoK58+fR5s2bbSWUSgUUCgUpS6LiIiIqDxUxRiK8RMRERGVVKFJKWdnZzg7O5daLigoCOnp6fjzzz/Rrl07AMChQ4eQnp6ODh06lDr/kiVL0LZtW7Rq1arUsqdPn8b9+/fh7u5e+goQERERVQDGUERERFQdVImOzps1a4aePXti9OjROHjwIA4ePIjRo0ejT58+aqPGNG3aFOvWrVObNyMjA7/88gtefvlljeVevHgR06ZNQ3x8PC5fvowtW7Zg8ODBaN26NTp27Fju60VERERUnhhDERERUWVWJZJSQNHoLi1btkRISAhCQkLg7++PFStWqJU5d+4c0tPT1aatXr0aQgg899xzGsu0trbGrl270KNHDzRp0gRjx45FSEgIdu7cCUtLy3JdHyIiIiJzYAxFRERElZUkhBAVXYmqLiMjA0qlEunp6XBwcKjo6hAREZGJ8BxffrhtiYiIqi9Dz/NVpqUUERERERERERFVH0xKERERERERERGR2TEpRUREREREREREZsekFBERERERERERmR2TUkREREREREREZHZMShERERERERERkdkxKUVERERERERERGbHpBQREREREREREZkdk1JERERERERERGR2TEoREREREREREZHZMSlFRERERERERERmx6QUERERERERERGZHZNSRERERERERERkdkxKERERERERERGR2TEpRUREREREREREZsekFBERERERERERmR2TUkREREREREREZHZMShERERERERERkdkxKUVERERERERERGbHpBQREREREREREZkdk1JERERERERERGR2TEoREREREREREZHZMSlFRERERERERERmx6QUERERERERERGZHZNSRERERERERERkdkxKERERERERERGR2TEpRUREREREREREZldlklKff/45OnToADs7O9SuXdugeYQQmDJlCjw8PGBra4suXbrg9OnTamVyc3Px1ltvwdnZGfb29njmmWeQmJhYDmtAREREZH6MoYiIiKiyqjJJqby8PAwePBivv/66wfPMnDkTs2bNwjfffIPDhw/Dzc0NwcHByMzMlMuMGzcO69atw+rVq7F//37cvXsXffr0QUFBQXmsBhEREZFZMYYiIiKiykoSQoiKroQxIiMjMW7cOKSlpektJ4SAh4cHxo0bhwkTJgAo+kXP1dUVM2bMwKuvvor09HTUrVsXK1aswJAhQwAA169fh5eXF7Zs2YIePXoYVKeMjAwolUqkp6fDwcGhTOtHRERElUd1OsdXthiqOm1bIiIiUmfoeb7KtJQy1qVLl5CcnIyQkBB5mkKhQOfOnXHgwAEAwJEjR3D//n21Mh4eHmjRooVchoiIiOhRwhiKiIiIzKVGRVegvCQnJwMAXF1d1aa7urriypUrchlra2s4OjpqlFHNr01ubi5yc3Pl5+np6QCKMoFERERUfajO7VWsYXmZlFcMxfiJiIjo0WFoDFWhSakpU6Zg6tSpesscPnwYAQEBD/0ekiSpPRdCaEwrqbQyERERWuvt5eX1cJUkIiKiSi0zMxNKpbKiqyGrijEU4yciIqJHT2kxVIUmpd58800MHTpUbxkfH5+HWrabmxuAol/y3N3d5ek3b96Uf/lzc3NDXl4eUlNT1X7pu3nzJjp06KBz2ZMmTcL48ePl54WFhbhz5w6cnJxKDdaMlZGRAS8vLyQkJLC/hXLGbW0+3Nbmw21tPtzW5mPObS2EQGZmJjw8PMr1fYxVFWMoxk/VE7e1+XBbmw+3tflwW5uPube1oTFUhSalnJ2d4ezsXC7L9vX1hZubG2JiYtC6dWsARaPPxMbGYsaMGQCAtm3bwsrKCjExMQgLCwMAJCUl4dSpU5g5c6bOZSsUCigUCrVphg6x/LAcHBy4k5oJt7X5cFubD7e1+XBb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",
|
544 |
+
"text/plain": [
|
545 |
+
"<Figure size 1200x400 with 2 Axes>"
|
546 |
+
]
|
547 |
+
},
|
548 |
+
"metadata": {},
|
549 |
+
"output_type": "display_data"
|
550 |
+
}
|
551 |
+
],
|
552 |
+
"source": [
|
553 |
+
"# Step 2 - Preparing the Data\n",
|
554 |
+
"\n",
|
555 |
+
"# Create a figure with two subplots side by side\n",
|
556 |
+
"fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4)) # 1 row, 2 columns, and an optional size specification\n",
|
557 |
+
"\n",
|
558 |
+
"# ACF plot in the first subplot\n",
|
559 |
+
"plot_acf(dfEnergyAll['Lastgang'].dropna(), lags=50, ax=ax1) # Autocorrelation plot for 'Lastgang' with 50 lags\n",
|
560 |
+
"ax1.set_title('Autocorrelation Function (ACF) of Lastgang') # Set title for the first subplot\n",
|
561 |
+
"ax1.set_xlabel('Lags') # Set x-label as 'Lags'\n",
|
562 |
+
"ax1.set_ylabel('Autocorrelation') # Set y-label as 'Autocorrelation'\n",
|
563 |
+
"\n",
|
564 |
+
"# PACF plot in the second subplot\n",
|
565 |
+
"plot_pacf(dfEnergyAll['Lastgang'].dropna(), lags=50, ax=ax2) # Partial autocorrelation plot for 'Lastgang' with 50 lags\n",
|
566 |
+
"ax2.set_title('Partial Autocorrelation Function (PACF) of Lastgang') # Set title for the second subplot\n",
|
567 |
+
"ax2.set_xlabel('Lags') # Set x-label as 'Lags'\n",
|
568 |
+
"ax2.set_ylabel('Autocorrelation') # Set y-label as 'Autocorrelation'\n",
|
569 |
+
"\n",
|
570 |
+
"# Adjust spacing between the plots\n",
|
571 |
+
"plt.tight_layout()\n",
|
572 |
+
"\n",
|
573 |
+
"# Display the plots\n",
|
574 |
+
"plt.show()"
|
575 |
+
]
|
576 |
+
},
|
577 |
+
{
|
578 |
+
"cell_type": "code",
|
579 |
+
"execution_count": 9,
|
580 |
+
"id": "a8e697f0-54a3-4854-82dd-2334582538a5",
|
581 |
+
"metadata": {},
|
582 |
+
"outputs": [],
|
583 |
+
"source": [
|
584 |
+
"# Step 3 - Data Scaling\n",
|
585 |
+
"\n",
|
586 |
+
"# Initialize the scalers\n",
|
587 |
+
"lastgang_scaler = MinMaxScaler(feature_range=(0, 1))\n",
|
588 |
+
"features_scaler = MinMaxScaler(feature_range=(0, 1))\n",
|
589 |
+
"\n",
|
590 |
+
"# Apply the scaler to the corresponding columns\n",
|
591 |
+
"dfEnergyAll['Lastgang'] = lastgang_scaler.fit_transform(dfEnergyAll['Lastgang'].values.reshape(-1, 1))\n",
|
592 |
+
"dfEnergyAll[['StundenwertStrahlung', 'Lufttemperatur', 'Globalstrahlung_15Min', 'StrahlungGeneigteFläche', 'Lastgang_Moving_Average', 'Lastgang_First_Difference']] = features_scaler.fit_transform(dfEnergyAll[['StundenwertStrahlung', 'Lufttemperatur', 'Globalstrahlung_15Min', 'StrahlungGeneigteFläche', 'Lastgang_Moving_Average', 'Lastgang_First_Difference']])"
|
593 |
+
]
|
594 |
+
},
|
595 |
+
{
|
596 |
+
"cell_type": "code",
|
597 |
+
"execution_count": null,
|
598 |
+
"id": "4a436b9a-88ca-4642-9a8f-5e4f61d69c7e",
|
599 |
+
"metadata": {},
|
600 |
+
"outputs": [],
|
601 |
+
"source": [
|
602 |
+
"# Step 3 - Check the scaled values\n",
|
603 |
+
"\n",
|
604 |
+
"print(dfEnergyAll.describe())\n",
|
605 |
+
"\n",
|
606 |
+
"print(\"Skalierparameter für Lastgang:\", lastgang_scaler.scale_, lastgang_scaler.min_)"
|
607 |
+
]
|
608 |
+
},
|
609 |
+
{
|
610 |
+
"cell_type": "code",
|
611 |
+
"execution_count": 10,
|
612 |
+
"id": "7c33eb1a-a633-499d-96cf-a5a5a6aa33b5",
|
613 |
+
"metadata": {},
|
614 |
+
"outputs": [
|
615 |
+
{
|
616 |
+
"name": "stdout",
|
617 |
+
"output_type": "stream",
|
618 |
+
"text": [
|
619 |
+
"CPU before model training:\n",
|
620 |
+
"CPU Utilization: 98.6%\n",
|
621 |
+
"RAM before model training:\n",
|
622 |
+
"Total memory: 146.88 GB\n",
|
623 |
+
"Available memory: 109.45 GB\n",
|
624 |
+
"Used memory: 35.63 GB\n",
|
625 |
+
"Memory usage: 25.5%\n"
|
626 |
+
]
|
627 |
+
}
|
628 |
+
],
|
629 |
+
"source": [
|
630 |
+
"# Step 3 - Show GPU Utilization and Memory Usage before Model Training\n",
|
631 |
+
"\n",
|
632 |
+
"#def print_gpu_utilization():\n",
|
633 |
+
" # Retrieve and print GPU utilization and memory stats\n",
|
634 |
+
" # GPUs = GPUtil.getGPUs()\n",
|
635 |
+
" # for GPU in GPUs:\n",
|
636 |
+
" # print(f\"GPU: {GPU.name}, GPU RAM Free: {GPU.memoryFree}MB, Used: {GPU.memoryUsed}MB, Utilization: {GPU.load*100}%\")\n",
|
637 |
+
"\n",
|
638 |
+
"#print(\"GPU before model training:\", datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\"))\n",
|
639 |
+
"#print_gpu_utilization()\n",
|
640 |
+
"\n",
|
641 |
+
"# Function to print CPU utilization\n",
|
642 |
+
"def print_cpu_utilization():\n",
|
643 |
+
" # Retrieve and print the percentage of CPU utilization\n",
|
644 |
+
" print(f\"CPU Utilization: {psutil.cpu_percent(interval=1)}%\")\n",
|
645 |
+
"\n",
|
646 |
+
"print(\"CPU before model training:\")\n",
|
647 |
+
"print_cpu_utilization()\n",
|
648 |
+
"\n",
|
649 |
+
"def print_memory_usage():\n",
|
650 |
+
" # Retrieve and print memory statistics\n",
|
651 |
+
" memory = psutil.virtual_memory()\n",
|
652 |
+
" print(f\"Total memory: {memory.total / (1024**3):.2f} GB\")\n",
|
653 |
+
" print(f\"Available memory: {memory.available / (1024**3):.2f} GB\")\n",
|
654 |
+
" print(f\"Used memory: {memory.used / (1024**3):.2f} GB\")\n",
|
655 |
+
" print(f\"Memory usage: {memory.percent}%\")\n",
|
656 |
+
"\n",
|
657 |
+
"print(\"RAM before model training:\")\n",
|
658 |
+
"print_memory_usage()\n"
|
659 |
+
]
|
660 |
+
},
|
661 |
+
{
|
662 |
+
"cell_type": "code",
|
663 |
+
"execution_count": null,
|
664 |
+
"id": "c181460f-7248-4672-b8a0-516e6e09fed7",
|
665 |
+
"metadata": {},
|
666 |
+
"outputs": [
|
667 |
+
{
|
668 |
+
"name": "stdout",
|
669 |
+
"output_type": "stream",
|
670 |
+
"text": [
|
671 |
+
"RUNNING THE L-BFGS-B CODE\n",
|
672 |
+
"\n",
|
673 |
+
" * * *\n",
|
674 |
+
"\n",
|
675 |
+
"Machine precision = 2.220D-16\n",
|
676 |
+
" N = 12 M = 10\n",
|
677 |
+
"\n",
|
678 |
+
"At X0 0 variables are exactly at the bounds\n",
|
679 |
+
"\n",
|
680 |
+
"At iterate 0 f= -2.08057D+00 |proj g|= 1.19631D+03\n"
|
681 |
+
]
|
682 |
+
},
|
683 |
+
{
|
684 |
+
"name": "stderr",
|
685 |
+
"output_type": "stream",
|
686 |
+
"text": [
|
687 |
+
" This problem is unconstrained.\n"
|
688 |
+
]
|
689 |
+
}
|
690 |
+
],
|
691 |
+
"source": [
|
692 |
+
"# Step 4 - Creating the SARIMAX model and generating predictions\n",
|
693 |
+
"\n",
|
694 |
+
"# Ensure the index is set as DatetimeIndex and has the correct frequency\n",
|
695 |
+
"dfEnergyAll.index = pd.to_datetime(dfEnergyAll.index) # Convert the index to datetime type\n",
|
696 |
+
"dfEnergyAll = dfEnergyAll.asfreq('15T') # Set the frequency of the DataFrame to every 15 minutes\n",
|
697 |
+
"\n",
|
698 |
+
"# Split the data into training and testing sets\n",
|
699 |
+
"# Since you want to forecast 48 hours ahead (192 fifteen-minute intervals), take this into account when splitting\n",
|
700 |
+
"train, test = train_test_split(dfEnergyAll, train_size=len(dfEnergyAll)-192)\n",
|
701 |
+
"\n",
|
702 |
+
"# Separate the target variable (Lastgang) and the exogenous variables\n",
|
703 |
+
"y_train = train['Lastgang'] # Target variable for training\n",
|
704 |
+
"X_train = train[['StundenwertStrahlung', 'Globalstrahlung_15Min', 'StrahlungGeneigteFläche', 'TheorPVProd', 'Direktnormalstrahlung', 'Schönwetterstrahlung', 'Lufttemperatur', 'Lastgang_Moving_Average', 'Lastgang_First_Difference']] # Exogenous variables for training\n",
|
705 |
+
"# Only 1 external variable: , 'Lufttemperatur'\n",
|
706 |
+
"\n",
|
707 |
+
"y_test = test['Lastgang'] # Target variable for testing, used later for evaluation\n",
|
708 |
+
"X_test = test[['StundenwertStrahlung', 'Globalstrahlung_15Min', 'StrahlungGeneigteFläche', 'TheorPVProd', 'Direktnormalstrahlung', 'Schönwetterstrahlung', 'Lufttemperatur', 'Lastgang_Moving_Average', 'Lastgang_First_Difference']] # Exogenous variables for testing, used for predictions\n",
|
709 |
+
"# Only 1 external variable: , 'Lufttemperatur'\n",
|
710 |
+
"\n",
|
711 |
+
"# Define and fit the SARIMAX model\n",
|
712 |
+
"# SARIMAX model with ARIMA(1,0,0) and seasonal order (1,0,0,96)\n",
|
713 |
+
"model = sm.tsa.SARIMAX(y_train, exog=X_train, order=(1,0,0), seasonal_order=(1,0,0,96), enforce_stationarity=False, enforce_invertibility=False)\n",
|
714 |
+
"results = model.fit()\n",
|
715 |
+
"\n",
|
716 |
+
"# Display the model summary\n",
|
717 |
+
"print(results.summary())\n",
|
718 |
+
"\n",
|
719 |
+
"# Use the model for predictions\n",
|
720 |
+
"predictions = results.get_forecast(steps=192, exog=X_test).predicted_mean # Forecasting using the model\n"
|
721 |
+
]
|
722 |
+
},
|
723 |
+
{
|
724 |
+
"cell_type": "code",
|
725 |
+
"execution_count": null,
|
726 |
+
"id": "ecc374bc-c312-4400-915d-96707c87ae49",
|
727 |
+
"metadata": {},
|
728 |
+
"outputs": [],
|
729 |
+
"source": [
|
730 |
+
"# Step 5 - Rescaling, error metrics and visualization\n",
|
731 |
+
"\n",
|
732 |
+
"# Rescale predictions and review\n",
|
733 |
+
"predictions_original_scale = lastgang_scaler.inverse_transform(predictions.to_numpy().reshape(-1, 1)) # Rescale the predictions to the original scale\n",
|
734 |
+
"print(\"After rescaling (first 5 values):\", predictions_original_scale[:5]) # Print the first 5 rescaled prediction values\n",
|
735 |
+
"\n",
|
736 |
+
"# Rescale actual values and review\n",
|
737 |
+
"y_test_original_scale = lastgang_scaler.inverse_transform(y_test.to_numpy().reshape(-1, 1)) # Rescale the actual values to the original scale\n",
|
738 |
+
"print(\"Actual values after rescaling (first 5 values):\", y_test_original_scale[:5]) # Print the first 5 rescaled actual values"
|
739 |
+
]
|
740 |
+
},
|
741 |
+
{
|
742 |
+
"cell_type": "code",
|
743 |
+
"execution_count": null,
|
744 |
+
"id": "d272a1e2-4f7e-4840-81ed-0a1f5a462d46",
|
745 |
+
"metadata": {},
|
746 |
+
"outputs": [],
|
747 |
+
"source": [
|
748 |
+
"# Step 5 - Rescaling, error metrics and visualization\n",
|
749 |
+
"\n",
|
750 |
+
"# Create a series for SARIMAX forecast results with timestamps\n",
|
751 |
+
"sarimax_forecast_series = pd.Series(predictions, index=y_test.index) # Initially store predictions in a series with the test set's timestamps\n",
|
752 |
+
"\n",
|
753 |
+
"# Create a series for SARIMAX forecast results with timestamps using rescaled predictions\n",
|
754 |
+
"sarimax_forecast_series = pd.Series(predictions_original_scale.ravel(), index=y_test.index) # Use rescaled predictions for the series\n",
|
755 |
+
"\n",
|
756 |
+
"# Calculate error metrics for SARIMAX model predictions\n",
|
757 |
+
"mse = mean_squared_error(y_test_original_scale, sarimax_forecast_series) # Calculate mean squared error\n",
|
758 |
+
"mae = mean_absolute_error(y_test_original_scale, sarimax_forecast_series) # Calculate mean absolute error\n",
|
759 |
+
"rmse = np.sqrt(mse) # Calculate root mean square error\n",
|
760 |
+
"mape = np.mean(np.abs((y_test_original_scale.ravel() - sarimax_forecast_series) / y_test_original_scale.ravel())) * 100 # Calculate mean absolute percentage error\n",
|
761 |
+
"\n",
|
762 |
+
"# Output error metrics for SARIMAX model predictions\n",
|
763 |
+
"print(f\"Mean Squared Error (MSE) for the last 2 days: {mse}\")\n",
|
764 |
+
"print(f\"Mean Absolute Error (MAE) for the last 2 days: {mae}\")\n",
|
765 |
+
"print(f\"Root Mean Square Error (RMSE) for the last 2 days: {rmse}\")\n",
|
766 |
+
"print(f\"Mean Absolute Percentage Error (MAPE) for the last 2 days: {mape}%\")\n",
|
767 |
+
"\n",
|
768 |
+
"# Visualization\n",
|
769 |
+
"plt.figure(figsize=(12, 6))\n",
|
770 |
+
"plt.plot(y_test.index, y_test_original_scale, label='Actual Values', color='#3E7A6F') # Plot actual values\n",
|
771 |
+
"plt.plot(sarimax_forecast_series.index, sarimax_forecast_series, label='Predicted Values', color='#7DFFE7') # Plot predicted values\n",
|
772 |
+
"plt.legend()\n",
|
773 |
+
"plt.title('Comparison of Actual and Predicted Values: SARIMAX over 48 Hours')\n",
|
774 |
+
"plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%m-%d %H:%M')) # Format the x-axis labels to show month-day and time\n",
|
775 |
+
"plt.gca().xaxis.set_major_locator(mdates.HourLocator(interval=3)) # Set major tick intervals on the x-axis\n",
|
776 |
+
"plt.gcf().autofmt_xdate() # Auto-format date labels for better readability\n",
|
777 |
+
"plt.show()"
|
778 |
+
]
|
779 |
+
},
|
780 |
+
{
|
781 |
+
"cell_type": "code",
|
782 |
+
"execution_count": null,
|
783 |
+
"id": "40da38a3-6473-4dc2-9690-dcfa5ae27415",
|
784 |
+
"metadata": {},
|
785 |
+
"outputs": [],
|
786 |
+
"source": [
|
787 |
+
"# Step 7 - Show GPU Utilization and Memory Usage after Model Training\n",
|
788 |
+
"\n",
|
789 |
+
"#print(\"GPU after model training:\", datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\")) # Print GPU utilization after model training\n",
|
790 |
+
"#print_gpu_utilization() # Call function to print GPU utilization\n",
|
791 |
+
"\n",
|
792 |
+
"print(\"CPU after model training:\") # Print CPU utilization after model training\n",
|
793 |
+
"print_cpu_utilization() # Call function to print CPU utilization\n",
|
794 |
+
"\n",
|
795 |
+
"print(\"RAM after model training:\") # Print RAM usage after model training\n",
|
796 |
+
"print_memory_usage() # Call function to print RAM usage"
|
797 |
+
]
|
798 |
+
}
|
799 |
+
],
|
800 |
+
"metadata": {
|
801 |
+
"kernelspec": {
|
802 |
+
"display_name": "Python 3 (ipykernel)",
|
803 |
+
"language": "python",
|
804 |
+
"name": "python3"
|
805 |
+
},
|
806 |
+
"language_info": {
|
807 |
+
"codemirror_mode": {
|
808 |
+
"name": "ipython",
|
809 |
+
"version": 3
|
810 |
+
},
|
811 |
+
"file_extension": ".py",
|
812 |
+
"mimetype": "text/x-python",
|
813 |
+
"name": "python",
|
814 |
+
"nbconvert_exporter": "python",
|
815 |
+
"pygments_lexer": "ipython3",
|
816 |
+
"version": "3.11.8"
|
817 |
+
}
|
818 |
+
},
|
819 |
+
"nbformat": 4,
|
820 |
+
"nbformat_minor": 5
|
821 |
+
}
|