Spaces:
Running
Running
import torch | |
import torch.nn as nn | |
import torch.optim as optim | |
import pandas as pd | |
import numpy as np | |
from sklearn.preprocessing import MinMaxScaler | |
from datetime import datetime | |
import json | |
class WeatherPredictor: | |
def __init__(self, data_path): | |
# Load and preprocess data | |
self.df = pd.read_csv(data_path, parse_dates=['Date'], | |
date_parser=lambda x: datetime.strptime(x, '%d/%m/%y')) | |
self.df['day'] = self.df['Date'].dt.day | |
self.df['month'] = self.df['Date'].dt.month | |
self.df['year'] = self.df['Date'].dt.year | |
self.df['day_sin'] = np.sin(2 * np.pi * self.df['day'] / 31) | |
self.df['day_cos'] = np.cos(2 * np.pi * self.df['day'] / 31) | |
self.df['month_sin'] = np.sin(2 * np.pi * self.df['month'] / 12) | |
self.df['month_cos'] = np.cos(2 * np.pi * self.df['month'] / 12) | |
features = ['day_sin', 'day_cos', 'month_sin', 'month_cos', 'year'] | |
target_columns = ['Temperature', 'Precipitation', 'Snowfall', 'Windspeed', 'Cloud Coverage', 'Sunshine Duration'] | |
# Check for NaN or infinite values | |
if self.df[features + target_columns].isnull().values.any(): | |
raise ValueError("Data contains NaN values. Please clean the data.") | |
if np.isinf(self.df[features + target_columns].values).any(): | |
raise ValueError("Data contains infinite values. Please clean the data.") | |
# Scale features and targets | |
self.feature_scaler = MinMaxScaler() | |
self.target_scaler = MinMaxScaler() | |
X = self.feature_scaler.fit_transform(self.df[features]) | |
Y = self.target_scaler.fit_transform(self.df[target_columns]) | |
self.X_tensor = torch.FloatTensor(X) | |
self.Y_tensor = torch.FloatTensor(Y) | |
# Single model for all targets | |
input_dim = len(features) | |
self.model = nn.Sequential( | |
nn.Linear(input_dim, 16), | |
nn.ReLU(), | |
nn.Linear(16, 12), | |
nn.ReLU(), | |
nn.Linear(12, 6) | |
) | |
def train(self, epochs=10000): | |
# Define loss function and optimizer | |
criterion = nn.MSELoss() | |
optimizer = optim.Adam(self.model.parameters(), lr=0.001) # Reduced learning rate | |
for epoch in range(epochs): | |
# Forward pass | |
outputs = self.model(self.X_tensor) # Multi-output predictions | |
loss = criterion(outputs, self.Y_tensor) | |
# Check for NaN loss | |
if torch.isnan(loss): | |
raise ValueError("Loss is NaN. Please check your data and model.") | |
# Backward pass and optimize | |
optimizer.zero_grad() | |
loss.backward() | |
optimizer.step() | |
if epoch % 100 == 0: | |
print(f'Epoch [{epoch}/{epochs}], Loss: {loss.item():.4f}') | |
# Save the model after training | |
self.save_model('weather_predictor.pth') | |
def predict(self, input_date): | |
# Convert input date to features | |
date = datetime.strptime(input_date, '%d/%m/%y') | |
features = [ | |
np.sin(2 * np.pi * date.day / 31), | |
np.cos(2 * np.pi * date.day / 31), | |
np.sin(2 * np.pi * date.month / 12), | |
np.cos(2 * np.pi * date.month / 12), | |
date.year | |
] | |
# Transform features to match training scale | |
scaled_features = self.feature_scaler.transform([features]) | |
input_tensor = torch.FloatTensor(scaled_features) | |
# Load the model before making predictions | |
self.load_model('weather_predictor.pth') | |
# Predict outputs | |
with torch.no_grad(): | |
scaled_predictions = self.model(input_tensor).numpy() | |
predictions = self.target_scaler.inverse_transform(scaled_predictions.reshape(1, -1)).flatten() | |
# Map predictions to target columns | |
target_columns = ['Temperature C', 'Precipitation mm', 'Snowfall cm', 'Windspeed km/h' , 'Cloud Coverage %', 'Sunshine Duration min'] | |
result_dict = dict(zip(target_columns, predictions)) | |
return result_dict | |
def save_model(self, file_path): | |
torch.save(self.model.state_dict(), file_path) | |
def load_model(self, file_path): | |
self.model.load_state_dict(torch.load(file_path)) | |
self.model.eval() | |
def main(): | |
predictor = WeatherPredictor('Basel2019-2024.csv') | |
predictor.train() | |
# Predict for a specific date | |
result = predictor.predict('01/02/23') | |
print("Predictions:", result) | |
if __name__ == '__main__': | |
main() |