Premchan369 commited on
Commit
99873c2
·
verified ·
1 Parent(s): d4fa2ee

Upload online_learning.py

Browse files
Files changed (1) hide show
  1. online_learning.py +88 -0
online_learning.py ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Online Learning - Adaptive model retraining with concept drift detection."""
2
+ import numpy as np
3
+ import pandas as pd
4
+ from sklearn.linear_model import SGDRegressor
5
+ from typing import Dict, Optional
6
+ import warnings
7
+ warnings.filterwarnings('ignore')
8
+
9
+
10
+ class OnlineLearner:
11
+ """Incremental learning for adaptive alpha models."""
12
+
13
+ def __init__(self, lookback_window: int = 252):
14
+ self.lookback_window = lookback_window
15
+ self.model = SGDRegressor(loss='squared_error', penalty='l2', alpha=0.0001,
16
+ learning_rate='adaptive', eta0=0.01, max_iter=1,
17
+ warm_start=True, random_state=42)
18
+ self.feature_buffer = []
19
+ self.target_buffer = []
20
+ self.is_fitted = False
21
+ self.update_count = 0
22
+ self.drift_scores = []
23
+
24
+ def partial_fit(self, X: np.ndarray, y: np.ndarray):
25
+ """Incrementally update model."""
26
+ self.feature_buffer.append(X)
27
+ self.target_buffer.append(y)
28
+
29
+ if len(self.feature_buffer) > self.lookback_window:
30
+ self.feature_buffer = self.feature_buffer[-self.lookback_window:]
31
+ self.target_buffer = self.target_buffer[-self.lookback_window:]
32
+
33
+ X_batch = np.vstack(self.feature_buffer)
34
+ y_batch = np.concatenate(self.target_buffer)
35
+
36
+ if not self.is_fitted:
37
+ self.model.fit(X_batch, y_batch); self.is_fitted = True
38
+ else:
39
+ self.model.partial_fit(X_batch, y_batch)
40
+
41
+ self.update_count += 1
42
+
43
+ def predict(self, X: np.ndarray) -> np.ndarray:
44
+ return self.model.predict(X) if self.is_fitted else np.zeros(len(X))
45
+
46
+ def get_drift_score(self, recent_X: np.ndarray, recent_y: np.ndarray) -> float:
47
+ """Detect concept drift."""
48
+ if not self.is_fitted: return 0.0
49
+ pred = self.predict(recent_X)
50
+ recent_mse = np.mean((pred - recent_y) ** 2)
51
+ all_pred = self.predict(np.vstack(self.feature_buffer))
52
+ all_y = np.concatenate(self.target_buffer)
53
+ historical_mse = np.mean((all_pred - all_y) ** 2)
54
+ drift = recent_mse / (historical_mse + 1e-8) - 1.0
55
+ self.drift_scores.append(drift)
56
+ return drift
57
+
58
+
59
+ class AdaptiveEnsemble:
60
+ """Ensemble adapting weights based on recent IC."""
61
+
62
+ def __init__(self, models: Dict[str, object], adaptation_rate: float = 0.1):
63
+ self.models = models
64
+ self.weights = {name: 1.0 / len(models) for name in models}
65
+ self.adaptation_rate = adaptation_rate
66
+
67
+ def predict(self, X: np.ndarray) -> np.ndarray:
68
+ final = np.zeros(len(X))
69
+ for name, model in self.models.items():
70
+ try: final += self.weights[name] * model.predict(X)
71
+ except: pass
72
+ return final
73
+
74
+ def update_weights(self, predictions: Dict[str, np.ndarray], actual: np.ndarray):
75
+ from scipy.stats import spearmanr
76
+ ics = {}
77
+ for name, pred in predictions.items():
78
+ ic, _ = spearmanr(pred, actual)
79
+ ics[name] = abs(ic) if not np.isnan(ic) else 0.0
80
+
81
+ total = sum(ics.values()) + 1e-8
82
+ target = {name: ic / total for name, ic in ics.items()}
83
+
84
+ for name in self.weights:
85
+ self.weights[name] = (1 - self.adaptation_rate) * self.weights[name] + self.adaptation_rate * target[name]
86
+
87
+ total_w = sum(self.weights.values())
88
+ self.weights = {k: v / total_w for k, v in self.weights.items()}