batch change
This commit is contained in:
1 parent
f73d6af1b2
commit
07d4963910
10 files changed
+36
-4865
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -1,163 +0,0 @@
|
|||||||
from sklearn.model_selection import train_test_split
|
|
||||||
import torch
|
|
||||||
|
|
||||||
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
|
||||||
|
|
||||||
from sklearn.preprocessing import MinMaxScaler
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
from load_data import load_this_data
|
|
||||||
|
|
||||||
a = load_this_data()
|
|
||||||
|
|
||||||
# time series forecasting
|
|
||||||
|
|
||||||
|
|
||||||
scaler = MinMaxScaler()
|
|
||||||
print(a.columns)
|
|
||||||
scaled_data = scaler.fit_transform(a)
|
|
||||||
|
|
||||||
|
|
||||||
def create_sequences(data, seq_length):
|
|
||||||
"see this? return[0] is the big x and return[1] is the big y. and h(x) = y. and h(x) is the model."
|
|
||||||
xs = []
|
|
||||||
ys = []
|
|
||||||
for i in range(len(data) - seq_length):
|
|
||||||
x = data[i : (i + seq_length)]
|
|
||||||
y = data[i + seq_length]
|
|
||||||
xs.append(x)
|
|
||||||
ys.append(y)
|
|
||||||
return np.array(xs), np.array(ys)
|
|
||||||
|
|
||||||
|
|
||||||
seq_length = 20
|
|
||||||
|
|
||||||
X, y = create_sequences(scaled_data, seq_length)
|
|
||||||
|
|
||||||
X_train, X_test, y_train, y_test = train_test_split(
|
|
||||||
X, y, test_size=0.2, random_state=42
|
|
||||||
)
|
|
||||||
from torch.utils.data import TensorDataset, DataLoader
|
|
||||||
|
|
||||||
X_train_tensor = torch.tensor(X_train, dtype=torch.float32)
|
|
||||||
y_train_tensor = torch.tensor(y_train, dtype=torch.float32)
|
|
||||||
|
|
||||||
train_dataset = TensorDataset(X_train_tensor, y_train_tensor)
|
|
||||||
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
|
|
||||||
|
|
||||||
|
|
||||||
import torch.nn as nn
|
|
||||||
|
|
||||||
|
|
||||||
class LSTMModel(nn.Module):
|
|
||||||
def __init__(self, input_size, hidden_size, num_layers, output_size):
|
|
||||||
super(LSTMModel, self).__init__()
|
|
||||||
self.hidden_size = hidden_size
|
|
||||||
self.num_layers = num_layers
|
|
||||||
self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
|
|
||||||
self.fc = nn.Linear(hidden_size, output_size)
|
|
||||||
|
|
||||||
def forward(self, x):
|
|
||||||
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)
|
|
||||||
c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)
|
|
||||||
|
|
||||||
out, _ = self.lstm(x, (h0, c0))
|
|
||||||
out = self.fc(out[:, -1, :]) # Take the output from the last time step
|
|
||||||
return out
|
|
||||||
|
|
||||||
|
|
||||||
model = LSTMModel(
|
|
||||||
input_size=X_train.shape[2],
|
|
||||||
hidden_size=64,
|
|
||||||
num_layers=2,
|
|
||||||
output_size=y_train.shape[1],
|
|
||||||
)
|
|
||||||
model.to(device)
|
|
||||||
criterion = nn.MSELoss()
|
|
||||||
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
|
|
||||||
|
|
||||||
train_losses = []
|
|
||||||
val_losses = []
|
|
||||||
|
|
||||||
|
|
||||||
for epoch in range(100):
|
|
||||||
model.train()
|
|
||||||
running_train_loss = 0.0
|
|
||||||
|
|
||||||
# inputs, targets
|
|
||||||
for batch_X, batch_y in train_loader:
|
|
||||||
batch_X = batch_X.to(device)
|
|
||||||
batch_y = batch_y.to(device)
|
|
||||||
|
|
||||||
outputs = model(batch_X)
|
|
||||||
loss = criterion(outputs, batch_y)
|
|
||||||
|
|
||||||
optimizer.zero_grad()
|
|
||||||
loss.backward()
|
|
||||||
optimizer.step()
|
|
||||||
|
|
||||||
running_train_loss += loss.item() * batch_X.size(0)
|
|
||||||
if (epoch + 1) % 10 == 0:
|
|
||||||
print(f"Epoch [{epoch+1}/100], Loss: {loss.item():.4f}")
|
|
||||||
|
|
||||||
epoch_train_loss = running_train_loss / len(train_loader.dataset)
|
|
||||||
train_losses.append(epoch_train_loss)
|
|
||||||
|
|
||||||
model.eval()
|
|
||||||
|
|
||||||
X_test_tensor = torch.tensor(X_test, dtype=torch.float32).to(device)
|
|
||||||
y_test_tensor = torch.tensor(y_test, dtype=torch.float32).to(device)
|
|
||||||
val_dataset = TensorDataset(X_test_tensor, y_test_tensor)
|
|
||||||
val_loader = DataLoader(val_dataset, batch_size=64, shuffle=False)
|
|
||||||
|
|
||||||
# with torch.no_grad():
|
|
||||||
# running_val_loss = 0.0
|
|
||||||
# predictions = model(X_test_tensor)
|
|
||||||
# test_loss = criterion(predictions, y_test_tensor)
|
|
||||||
# print(f"Test Loss: {test_loss.item():.4f}")
|
|
||||||
|
|
||||||
running_val_loss = 0.0
|
|
||||||
predictions = []
|
|
||||||
with torch.no_grad():
|
|
||||||
for inputs, targets in val_loader:
|
|
||||||
inputs, targets = inputs.to(device), targets.to(device)
|
|
||||||
outputs = model(inputs)
|
|
||||||
loss = criterion(outputs, targets)
|
|
||||||
running_val_loss += loss.item() * inputs.size(0)
|
|
||||||
predictions.append(outputs.cpu().numpy()) # Collect all batches
|
|
||||||
|
|
||||||
epoch_val_loss = running_val_loss / len(val_loader.dataset) # len(val_dataset)
|
|
||||||
val_losses.append(epoch_val_loss)
|
|
||||||
|
|
||||||
predictions = np.concatenate(predictions, axis=0)
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
|
|
||||||
y_test_cpu = y_test_tensor.cpu().numpy()
|
|
||||||
|
|
||||||
predictions_rescaled = scaler.inverse_transform(predictions)
|
|
||||||
y_test_rescaled = scaler.inverse_transform(y_test_cpu)
|
|
||||||
|
|
||||||
|
|
||||||
fig, (ax1, ax2) = plt.subplots(
|
|
||||||
1, 2, figsize=(14, 5), gridspec_kw={"width_ratios": [1, 3]}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Loss curve on the left
|
|
||||||
ax1.plot(train_losses, label="Train Loss")
|
|
||||||
ax1.plot(val_losses, label="Val Loss")
|
|
||||||
ax1.set_title("Loss Curve")
|
|
||||||
ax1.set_xlabel("Epoch")
|
|
||||||
ax1.set_ylabel("Loss")
|
|
||||||
ax1.legend()
|
|
||||||
ax1.grid(True)
|
|
||||||
|
|
||||||
# Prediction vs Actual on the right
|
|
||||||
ax2.plot(y_test_rescaled, label="Actual")
|
|
||||||
ax2.plot(predictions_rescaled, label="Predicted")
|
|
||||||
ax2.set_title("Actual vs. Predicted")
|
|
||||||
ax2.set_xlabel("Sample")
|
|
||||||
ax2.set_ylabel("Value")
|
|
||||||
ax2.legend()
|
|
||||||
|
|
||||||
plt.tight_layout()
|
|
||||||
plt.show()
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
DATA_FILE_NAME = "hanoi_weather_data.csv"
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
"extracting the load data step from the notebook"
|
|
||||||
|
|
||||||
import io
|
|
||||||
|
|
||||||
# from itertools import islice
|
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
def cut_headers(stream: Union[io.StringIO, io.FileIO, io.TextIOWrapper]):
|
|
||||||
headers = []
|
|
||||||
exist_startheader = False
|
|
||||||
|
|
||||||
while line := stream.readline():
|
|
||||||
if "-BEGIN HEADER-" in line and not exist_startheader:
|
|
||||||
exist_startheader = True
|
|
||||||
headers.append(str(line.strip()))
|
|
||||||
elif "-END HEADER-" in line and exist_startheader:
|
|
||||||
headers.append(str(line.strip()))
|
|
||||||
break
|
|
||||||
elif exist_startheader:
|
|
||||||
# print(f"{line = }")
|
|
||||||
headers.append(str(line.strip()))
|
|
||||||
elif not exist_startheader:
|
|
||||||
continue
|
|
||||||
if not exist_startheader:
|
|
||||||
# If no headers are found, reset the stream and return
|
|
||||||
stream.seek(0)
|
|
||||||
return "", stream
|
|
||||||
return "\n".join(headers), stream
|
|
||||||
-2100
File diff suppressed because it is too large.
Load diff
@@ -1,163 +0,0 @@
|
|||||||
from sklearn.model_selection import train_test_split
|
|
||||||
import torch
|
|
||||||
|
|
||||||
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
|
||||||
|
|
||||||
from sklearn.preprocessing import MinMaxScaler
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
from load_data import load_this_data
|
|
||||||
|
|
||||||
a = load_this_data()
|
|
||||||
|
|
||||||
# time series forecasting
|
|
||||||
|
|
||||||
|
|
||||||
scaler = MinMaxScaler()
|
|
||||||
print(a.columns)
|
|
||||||
scaled_data = scaler.fit_transform(a)
|
|
||||||
|
|
||||||
|
|
||||||
def create_sequences(data, seq_length):
|
|
||||||
"see this? return[0] is the big x and return[1] is the big y. and h(x) = y. and h(x) is the model."
|
|
||||||
xs = []
|
|
||||||
ys = []
|
|
||||||
for i in range(len(data) - seq_length):
|
|
||||||
x = data[i : (i + seq_length)]
|
|
||||||
y = data[i + seq_length]
|
|
||||||
xs.append(x)
|
|
||||||
ys.append(y)
|
|
||||||
return np.array(xs), np.array(ys)
|
|
||||||
|
|
||||||
|
|
||||||
seq_length = 20
|
|
||||||
|
|
||||||
X, y = create_sequences(scaled_data, seq_length)
|
|
||||||
|
|
||||||
X_train, X_test, y_train, y_test = train_test_split(
|
|
||||||
X, y, test_size=0.2, random_state=42
|
|
||||||
)
|
|
||||||
from torch.utils.data import TensorDataset, DataLoader
|
|
||||||
|
|
||||||
X_train_tensor = torch.tensor(X_train, dtype=torch.float32)
|
|
||||||
y_train_tensor = torch.tensor(y_train, dtype=torch.float32)
|
|
||||||
|
|
||||||
train_dataset = TensorDataset(X_train_tensor, y_train_tensor)
|
|
||||||
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
|
|
||||||
|
|
||||||
|
|
||||||
import torch.nn as nn
|
|
||||||
|
|
||||||
|
|
||||||
class LSTMModel(nn.Module):
|
|
||||||
def __init__(self, input_size, hidden_size, num_layers, output_size):
|
|
||||||
super(LSTMModel, self).__init__()
|
|
||||||
self.hidden_size = hidden_size
|
|
||||||
self.num_layers = num_layers
|
|
||||||
self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
|
|
||||||
self.fc = nn.Linear(hidden_size, output_size)
|
|
||||||
|
|
||||||
def forward(self, x):
|
|
||||||
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)
|
|
||||||
c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)
|
|
||||||
|
|
||||||
out, _ = self.lstm(x, (h0, c0))
|
|
||||||
out = self.fc(out[:, -1, :]) # Take the output from the last time step
|
|
||||||
return out
|
|
||||||
|
|
||||||
|
|
||||||
model = LSTMModel(
|
|
||||||
input_size=X_train.shape[2],
|
|
||||||
hidden_size=64,
|
|
||||||
num_layers=2,
|
|
||||||
output_size=y_train.shape[1],
|
|
||||||
)
|
|
||||||
model.to(device)
|
|
||||||
criterion = nn.MSELoss()
|
|
||||||
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
|
|
||||||
|
|
||||||
train_losses = []
|
|
||||||
val_losses = []
|
|
||||||
|
|
||||||
|
|
||||||
for epoch in range(100):
|
|
||||||
model.train()
|
|
||||||
running_train_loss = 0.0
|
|
||||||
|
|
||||||
# inputs, targets
|
|
||||||
for batch_X, batch_y in train_loader:
|
|
||||||
batch_X = batch_X.to(device)
|
|
||||||
batch_y = batch_y.to(device)
|
|
||||||
|
|
||||||
outputs = model(batch_X)
|
|
||||||
loss = criterion(outputs, batch_y)
|
|
||||||
|
|
||||||
optimizer.zero_grad()
|
|
||||||
loss.backward()
|
|
||||||
optimizer.step()
|
|
||||||
|
|
||||||
running_train_loss += loss.item() * batch_X.size(0)
|
|
||||||
if (epoch + 1) % 10 == 0:
|
|
||||||
print(f"Epoch [{epoch+1}/100], Loss: {loss.item():.4f}")
|
|
||||||
|
|
||||||
epoch_train_loss = running_train_loss / len(train_loader.dataset)
|
|
||||||
train_losses.append(epoch_train_loss)
|
|
||||||
|
|
||||||
model.eval()
|
|
||||||
|
|
||||||
X_test_tensor = torch.tensor(X_test, dtype=torch.float32).to(device)
|
|
||||||
y_test_tensor = torch.tensor(y_test, dtype=torch.float32).to(device)
|
|
||||||
val_dataset = TensorDataset(X_test_tensor, y_test_tensor)
|
|
||||||
val_loader = DataLoader(val_dataset, batch_size=64, shuffle=False)
|
|
||||||
|
|
||||||
# with torch.no_grad():
|
|
||||||
# running_val_loss = 0.0
|
|
||||||
# predictions = model(X_test_tensor)
|
|
||||||
# test_loss = criterion(predictions, y_test_tensor)
|
|
||||||
# print(f"Test Loss: {test_loss.item():.4f}")
|
|
||||||
|
|
||||||
running_val_loss = 0.0
|
|
||||||
predictions = []
|
|
||||||
with torch.no_grad():
|
|
||||||
for inputs, targets in val_loader:
|
|
||||||
inputs, targets = inputs.to(device), targets.to(device)
|
|
||||||
outputs = model(inputs)
|
|
||||||
loss = criterion(outputs, targets)
|
|
||||||
running_val_loss += loss.item() * inputs.size(0)
|
|
||||||
predictions.append(outputs.cpu().numpy()) # Collect all batches
|
|
||||||
|
|
||||||
epoch_val_loss = running_val_loss / len(val_loader.dataset) # len(val_dataset)
|
|
||||||
val_losses.append(epoch_val_loss)
|
|
||||||
|
|
||||||
predictions = np.concatenate(predictions, axis=0)
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
|
|
||||||
y_test_cpu = y_test_tensor.cpu().numpy()
|
|
||||||
|
|
||||||
predictions_rescaled = scaler.inverse_transform(predictions)
|
|
||||||
y_test_rescaled = scaler.inverse_transform(y_test_cpu)
|
|
||||||
|
|
||||||
|
|
||||||
fig, (ax1, ax2) = plt.subplots(
|
|
||||||
1, 2, figsize=(14, 5), gridspec_kw={"width_ratios": [1, 3]}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Loss curve on the left
|
|
||||||
ax1.plot(train_losses, label="Train Loss")
|
|
||||||
ax1.plot(val_losses, label="Val Loss")
|
|
||||||
ax1.set_title("Loss Curve")
|
|
||||||
ax1.set_xlabel("Epoch")
|
|
||||||
ax1.set_ylabel("Loss")
|
|
||||||
ax1.legend()
|
|
||||||
ax1.grid(True)
|
|
||||||
|
|
||||||
# Prediction vs Actual on the right
|
|
||||||
ax2.plot(y_test_rescaled, label="Actual")
|
|
||||||
ax2.plot(predictions_rescaled, label="Predicted")
|
|
||||||
ax2.set_title("Actual vs. Predicted")
|
|
||||||
ax2.set_xlabel("Sample")
|
|
||||||
ax2.set_ylabel("Value")
|
|
||||||
ax2.legend()
|
|
||||||
|
|
||||||
plt.tight_layout()
|
|
||||||
plt.show()
|
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
import sys
|
|
||||||
import numpy as np
|
|
||||||
import pandas as pd
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
import seaborn as sns
|
|
||||||
import io
|
|
||||||
from typing import Union
|
|
||||||
from sklearn.metrics import mean_squared_error, r2_score
|
|
||||||
from sklearn.preprocessing import MinMaxScaler
|
|
||||||
from sklearn.model_selection import train_test_split
|
|
||||||
from sklearn.linear_model import LinearRegression
|
|
||||||
from statsmodels.tsa.ar_model import AutoReg
|
|
||||||
|
|
||||||
# ==== LOAD & CLEAN DATA ====
|
|
||||||
DATA_FILE_NAME = "hanoi_weather_data.csv"
|
|
||||||
|
|
||||||
def cut_headers(stream: Union[io.StringIO, io.FileIO, io.TextIOWrapper]):
|
|
||||||
headers = []
|
|
||||||
exist_startheader = False
|
|
||||||
while line := stream.readline():
|
|
||||||
if "-BEGIN HEADER-" in line and not exist_startheader:
|
|
||||||
exist_startheader = True
|
|
||||||
headers.append(str(line.strip()))
|
|
||||||
elif "-END HEADER-" in line and exist_startheader:
|
|
||||||
headers.append(str(line.strip()))
|
|
||||||
break
|
|
||||||
elif exist_startheader:
|
|
||||||
headers.append(str(line.strip()))
|
|
||||||
elif not exist_startheader:
|
|
||||||
continue
|
|
||||||
if not exist_startheader:
|
|
||||||
stream.seek(0)
|
|
||||||
return "", stream
|
|
||||||
return "\n".join(headers), stream
|
|
||||||
|
|
||||||
with open(DATA_FILE_NAME, "r", encoding="utf-8") as file:
|
|
||||||
data_header, csv_file = cut_headers(file)
|
|
||||||
data = pd.read_csv(csv_file, na_values=-999)
|
|
||||||
|
|
||||||
if all(z in data.columns for z in ("YEAR", "MO", "DY")):
|
|
||||||
data["date"] = pd.to_datetime(
|
|
||||||
{k: data[v] for v, k in zip(["YEAR", "MO", "DY"], ["year", "month", "day"])}
|
|
||||||
)
|
|
||||||
data.drop(columns=["YEAR", "MO", "DY"], inplace=True)
|
|
||||||
data.set_index("date", inplace=True)
|
|
||||||
|
|
||||||
data.dropna(inplace=True)
|
|
||||||
|
|
||||||
# ==== VISUALIZE CORRELATION ====
|
|
||||||
plt.figure(figsize=(12, 8))
|
|
||||||
sns.heatmap(data.corr(), annot=True, cmap="coolwarm")
|
|
||||||
plt.title("Feature Correlation Heatmap")
|
|
||||||
plt.show()
|
|
||||||
|
|
||||||
# ==== SCALE DATA ====
|
|
||||||
scaler = MinMaxScaler()
|
|
||||||
scaled_data = scaler.fit_transform(data)
|
|
||||||
|
|
||||||
# ==== CREATE SEQUENCES ====
|
|
||||||
def create_sequences(data, seq_length):
|
|
||||||
xs, ys = [], []
|
|
||||||
for i in range(len(data) - seq_length):
|
|
||||||
x = data[i:i + seq_length].flatten()
|
|
||||||
y = data[i + seq_length]
|
|
||||||
xs.append(x)
|
|
||||||
ys.append(y)
|
|
||||||
return np.array(xs), np.array(ys)
|
|
||||||
|
|
||||||
seq_length = 50
|
|
||||||
X, y = create_sequences(scaled_data, seq_length)
|
|
||||||
|
|
||||||
# ==== SPLIT ====
|
|
||||||
date_index = data.index[seq_length:]
|
|
||||||
X_train, X_test, y_train, y_test, date_train, date_test = train_test_split(
|
|
||||||
X, y, date_index, test_size=0.02, shuffle=False
|
|
||||||
)
|
|
||||||
|
|
||||||
# ==== TRAIN LINEAR REGRESSION ====
|
|
||||||
model = LinearRegression()
|
|
||||||
model.fit(X_train, y_train)
|
|
||||||
predictions = model.predict(X_test)
|
|
||||||
|
|
||||||
# ==== EVALUATION ====
|
|
||||||
mse = mean_squared_error(y_test, predictions)
|
|
||||||
r2 = r2_score(y_test, predictions)
|
|
||||||
|
|
||||||
print(f"Test MSE: {mse:.4f}")
|
|
||||||
print(f"Test R2: {r2:.4f}")
|
|
||||||
print(f"Model Score: {model.score(X_test, y_test):.4f}")
|
|
||||||
|
|
||||||
# ==== INVERSE TRANSFORM ====
|
|
||||||
predictions_rescaled = scaler.inverse_transform(
|
|
||||||
predictions.reshape(-1, data.shape[1])
|
|
||||||
)
|
|
||||||
y_test_rescaled = scaler.inverse_transform(
|
|
||||||
y_test.reshape(-1, data.shape[1])
|
|
||||||
)
|
|
||||||
|
|
||||||
# ==== PLOTS ====
|
|
||||||
|
|
||||||
# Actual vs Predicted with Real Dates
|
|
||||||
plt.figure(figsize=(12, 6))
|
|
||||||
plt.plot(date_test, y_test_rescaled[:, 0], label="Actual")
|
|
||||||
plt.plot(date_test, predictions_rescaled[:, 0], label="Predicted")
|
|
||||||
plt.title("Actual vs Predicted (First Feature)")
|
|
||||||
plt.xlabel("Date")
|
|
||||||
plt.ylabel("Original Scale")
|
|
||||||
plt.xticks(rotation=45)
|
|
||||||
plt.legend()
|
|
||||||
plt.grid(True)
|
|
||||||
plt.tight_layout()
|
|
||||||
plt.show()
|
|
||||||
|
|
||||||
# Residual Plot
|
|
||||||
residuals = y_test[:, 0] - predictions[:, 0]
|
|
||||||
plt.figure(figsize=(10, 4))
|
|
||||||
plt.plot(date_test, residuals, label="Residuals")
|
|
||||||
plt.hlines(0, 0, len(residuals), colors="red")
|
|
||||||
plt.title("Residuals Over Time (First Feature)")
|
|
||||||
plt.xlabel("Date")
|
|
||||||
plt.ylabel("Error")
|
|
||||||
plt.xticks(rotation=45)
|
|
||||||
plt.legend()
|
|
||||||
plt.tight_layout()
|
|
||||||
plt.grid(True)
|
|
||||||
plt.show()
|
|
||||||
|
|
||||||
# Error Distribution
|
|
||||||
errors = np.abs(y_test[:, 0] - predictions[:, 0])
|
|
||||||
plt.hist(errors, bins=50)
|
|
||||||
plt.title("Error Distribution (First Feature)")
|
|
||||||
plt.xlabel("Absolute Error")
|
|
||||||
plt.ylabel("Frequency")
|
|
||||||
plt.grid(True)
|
|
||||||
plt.show()
|
|
||||||
|
|
||||||
# Scatter Plot
|
|
||||||
plt.scatter(y_test[:, 0], predictions[:, 0], alpha=0.5)
|
|
||||||
plt.plot([0, 1], [0, 1], "r--")
|
|
||||||
plt.title("Predicted vs Actual (Normalized)")
|
|
||||||
plt.xlabel("Actual")
|
|
||||||
plt.ylabel("Predicted")
|
|
||||||
plt.grid(True)
|
|
||||||
plt.show()
|
|
||||||
|
|
||||||
# ==== AUTOREGRESSION FORECAST ====
|
|
||||||
target_column = data.columns[0]
|
|
||||||
series = data[target_column]
|
|
||||||
|
|
||||||
train_size = int(len(series) * 0.98)
|
|
||||||
train_series = series[:train_size]
|
|
||||||
test_series = series[train_size:]
|
|
||||||
|
|
||||||
ar_model = AutoReg(train_series, lags=30).fit()
|
|
||||||
ar_preds = ar_model.predict(start=len(train_series), end=len(series)-1)
|
|
||||||
|
|
||||||
# Plot AR Forecast
|
|
||||||
plt.figure(figsize=(12, 5))
|
|
||||||
plt.plot(test_series.index, test_series, label="Actual")
|
|
||||||
plt.plot(test_series.index, ar_preds, label="AR Forecast", linestyle="--")
|
|
||||||
plt.title(f"AutoRegression Forecast - {target_column}")
|
|
||||||
plt.xlabel("Date")
|
|
||||||
plt.ylabel(target_column)
|
|
||||||
plt.xticks(rotation=45)
|
|
||||||
plt.legend()
|
|
||||||
plt.grid(True)
|
|
||||||
plt.tight_layout()
|
|
||||||
plt.show()
|
|
||||||
|
|
||||||
# ==== FUTURE FORECAST ====
|
|
||||||
future_steps = 30
|
|
||||||
future_index = pd.date_range(start=series.index[-1], periods=future_steps+1, freq="D")[1:]
|
|
||||||
future_forecast = ar_model.predict(start=len(series), end=len(series) + future_steps - 1)
|
|
||||||
|
|
||||||
plt.figure(figsize=(12, 5))
|
|
||||||
plt.plot(series[-100:], label="Recent Data")
|
|
||||||
plt.plot(future_index, future_forecast, label="Future Forecast", color="red")
|
|
||||||
plt.title(f"{target_column} - 30 Day Forecast (AutoRegression)")
|
|
||||||
plt.xlabel("Date")
|
|
||||||
plt.ylabel(target_column)
|
|
||||||
plt.xticks(rotation=45)
|
|
||||||
plt.legend()
|
|
||||||
plt.tight_layout()
|
|
||||||
plt.grid(True)
|
|
||||||
plt.show()
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
import sys
|
|
||||||
import numpy as np
|
|
||||||
import pandas as pd
|
|
||||||
from sklearn.metrics import r2_score
|
|
||||||
from sklearn.preprocessing import MinMaxScaler
|
|
||||||
from sklearn.model_selection import train_test_split
|
|
||||||
from sklearn.linear_model import LinearRegression
|
|
||||||
from sklearn.metrics import mean_squared_error
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
# from global_config import DATA_FILE_NAME
|
|
||||||
DATA_FILE_NAME = "hanoi_weather_data.csv"
|
|
||||||
|
|
||||||
# from load_data import cut_headers
|
|
||||||
|
|
||||||
import io
|
|
||||||
|
|
||||||
# from itertools import islice
|
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
def cut_headers(stream: Union[io.StringIO, io.FileIO, io.TextIOWrapper]):
|
|
||||||
headers = []
|
|
||||||
exist_startheader = False
|
|
||||||
|
|
||||||
while line := stream.readline():
|
|
||||||
if "-BEGIN HEADER-" in line and not exist_startheader:
|
|
||||||
exist_startheader = True
|
|
||||||
headers.append(str(line.strip()))
|
|
||||||
elif "-END HEADER-" in line and exist_startheader:
|
|
||||||
headers.append(str(line.strip()))
|
|
||||||
break
|
|
||||||
elif exist_startheader:
|
|
||||||
# print(f"{line = }")
|
|
||||||
headers.append(str(line.strip()))
|
|
||||||
elif not exist_startheader:
|
|
||||||
continue
|
|
||||||
if not exist_startheader:
|
|
||||||
# If no headers are found, reset the stream and return
|
|
||||||
stream.seek(0)
|
|
||||||
return "", stream
|
|
||||||
return "\n".join(headers), stream
|
|
||||||
|
|
||||||
# 1. Load data
|
|
||||||
|
|
||||||
with open(DATA_FILE_NAME, "r", encoding="utf-8") as file:
|
|
||||||
data_header, csv_file = cut_headers(file)
|
|
||||||
data = pd.read_csv(csv_file, na_values=-999)
|
|
||||||
|
|
||||||
if all(z in data.columns for z in ("YEAR", "MO", "DY")):
|
|
||||||
data["date"] = pd.to_datetime(
|
|
||||||
{k: data[v] for v, k in (zip(["YEAR", "MO", "DY"], ["year", "month", "day"]))}
|
|
||||||
)
|
|
||||||
data.drop(inplace=True, columns=["YEAR", "MO", "DY"])
|
|
||||||
data.set_index(["date"], inplace=True)
|
|
||||||
data.dropna(inplace=True)
|
|
||||||
|
|
||||||
# 2. Normalize data
|
|
||||||
scaler = MinMaxScaler()
|
|
||||||
print(data.columns)
|
|
||||||
scaled_data = scaler.fit_transform(data)
|
|
||||||
|
|
||||||
|
|
||||||
# 3. Create sequences for supervised learning
|
|
||||||
def create_sequences(data, seq_length):
|
|
||||||
xs, ys = [], []
|
|
||||||
for i in range(len(data) - seq_length):
|
|
||||||
x = data[i : i + seq_length].flatten()
|
|
||||||
y = data[i + seq_length]
|
|
||||||
xs.append(x)
|
|
||||||
ys.append(y)
|
|
||||||
return np.array(xs), np.array(ys)
|
|
||||||
|
|
||||||
|
|
||||||
seq_length = 50
|
|
||||||
X, y = create_sequences(scaled_data, seq_length)
|
|
||||||
|
|
||||||
# 4. Split into training and testing
|
|
||||||
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.02)
|
|
||||||
|
|
||||||
# 5. Train linear regression model
|
|
||||||
model = LinearRegression()
|
|
||||||
model.fit(X_train, y_train)
|
|
||||||
|
|
||||||
# 6. Make predictions
|
|
||||||
predictions = model.predict(X_test)
|
|
||||||
|
|
||||||
# 7. Evaluate performance
|
|
||||||
mse = mean_squared_error(y_test, predictions)
|
|
||||||
r2 = r2_score(y_test, predictions)
|
|
||||||
|
|
||||||
print(f"Test MSE: {mse:.4f}")
|
|
||||||
print(f"Test r2: {r2:.4f}")
|
|
||||||
|
|
||||||
print(f"Score: {model.score(X_test, y_test)}")
|
|
||||||
# 8. Inverse transform predictions
|
|
||||||
predictions_rescaled = scaler.inverse_transform(predictions.reshape(-1, data.shape[1]))
|
|
||||||
y_test_rescaled = scaler.inverse_transform(y_test.reshape(-1, data.shape[1]))
|
|
||||||
|
|
||||||
# 9. Plot results
|
|
||||||
|
|
||||||
# Loss bar
|
|
||||||
|
|
||||||
|
|
||||||
# Prediction vs Actual
|
|
||||||
plt.plot(y_test_rescaled, label="Actual")
|
|
||||||
plt.plot(predictions_rescaled, label="Predicted")
|
|
||||||
plt.title("Actual vs. Predicted")
|
|
||||||
plt.xlabel("Sample")
|
|
||||||
plt.ylabel("Value")
|
|
||||||
plt.legend()
|
|
||||||
plt.show()
|
|
||||||
@@ -47,7 +47,7 @@ theta, losses = train_linear_regression_gd(
|
|||||||
X_train,
|
X_train,
|
||||||
y_train,
|
y_train,
|
||||||
# lr_schedule=lr_schedule,
|
# lr_schedule=lr_schedule,
|
||||||
n_epochs=10000,
|
# n_epochs=1000,
|
||||||
)
|
)
|
||||||
|
|
||||||
predictions = predict_linear_regression(X_test, theta)
|
predictions = predict_linear_regression(X_test, theta)
|
||||||
|
|||||||
+35
-14
@@ -1,32 +1,53 @@
|
|||||||
|
from itertools import islice
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from sklearn.metrics import mean_squared_error, r2_score
|
from sklearn.metrics import mean_squared_error, r2_score
|
||||||
|
|
||||||
|
|
||||||
def train_linear_regression_gd(X_train, y_train, lr_schedule= lambda _e: 0.01, n_epochs=1000):
|
def train_linear_regression_gd(X_train, y_train, lr_schedule=lambda _e: 0.01, n_epochs=1000, batch_size=32):
|
||||||
"""
|
"""
|
||||||
Train linear regression model using batch gradient descent.
|
Train linear regression model using batch gradient descent.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
X_train: Training features.
|
||||||
|
y_train: Training labels.
|
||||||
|
lr_schedule: Learning rate schedule function.
|
||||||
|
n_epochs: Number of epochs.
|
||||||
|
batch_size: Size of each batch.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
theta: learned weights
|
theta: Learned weights.
|
||||||
losses: list of MSE loss per epoch
|
losses: List of MSE loss per epoch.
|
||||||
"""
|
"""
|
||||||
m, n = X_train.shape
|
m, n = X_train.shape
|
||||||
X_b = np.hstack([np.ones((m, 1)), X_train])
|
X_b = np.hstack([np.ones((m, 1)), X_train]) # Add bias term
|
||||||
theta = np.zeros(n + 1)
|
theta = np.zeros(n + 1)
|
||||||
losses = []
|
losses = []
|
||||||
|
|
||||||
for epoch in range(n_epochs):
|
for epoch in range(n_epochs):
|
||||||
lr = lr_schedule(epoch)
|
# Shuffle the data at the start of each epoch
|
||||||
predictions = X_b @ theta
|
indices = np.random.permutation(m)
|
||||||
errors = predictions - y_train
|
X_b_shuffled = X_b[indices]
|
||||||
gradients = (2 / m) * X_b.T @ errors
|
y_shuffled = y_train[indices]
|
||||||
gradients = np.clip(gradients, -1, 1) # gradient clipping
|
|
||||||
theta -= lr * gradients
|
|
||||||
loss = np.mean(errors ** 2)
|
|
||||||
losses.append(loss)
|
|
||||||
|
|
||||||
if epoch % 1000 == 0:
|
epoch_loss = 0.0
|
||||||
print(f"Epoch {epoch}: Loss = {loss:.6f}, LR: {lr:.6f}")
|
for i in range(0, m, batch_size):
|
||||||
|
X_batch = X_b_shuffled[i:i + batch_size]
|
||||||
|
y_batch = y_shuffled[i:i + batch_size]
|
||||||
|
|
||||||
|
lr = lr_schedule(epoch)
|
||||||
|
predictions = X_batch @ theta
|
||||||
|
errors = predictions - y_batch
|
||||||
|
gradients = (2 / batch_size) * X_batch.T @ errors
|
||||||
|
gradients = np.clip(gradients, -1, 1) # Gradient clipping
|
||||||
|
theta -= lr * gradients
|
||||||
|
|
||||||
|
batch_loss = np.mean(errors ** 2)
|
||||||
|
epoch_loss += batch_loss
|
||||||
|
|
||||||
|
losses.append(epoch_loss / (m // batch_size))
|
||||||
|
|
||||||
|
if epoch % 100 == 0:
|
||||||
|
print(f"Epoch {epoch}: Loss = {losses[-1]:.6f}, LR: {lr:.6f}")
|
||||||
|
|
||||||
print(f"Final Loss: {losses[-1]:.6f}")
|
print(f"Final Loss: {losses[-1]:.6f}")
|
||||||
return theta, losses
|
return theta, losses
|
||||||
|
|||||||
Reference in new issue
Block a user