From caee7225fbeeeab68707bcfe8602752416a83360 Mon Sep 17 00:00:00 2001 From: Ankita Mishra Date: Mon, 6 Oct 2025 10:31:50 -0500 Subject: [PATCH 01/16] Added Adaboost algorithm --- machine_learning/adaboost.py | 71 ++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 machine_learning/adaboost.py diff --git a/machine_learning/adaboost.py b/machine_learning/adaboost.py new file mode 100644 index 000000000000..b31ede2651c9 --- /dev/null +++ b/machine_learning/adaboost.py @@ -0,0 +1,71 @@ + +import numpy as np + +# AdaBoost implementation for binary classification +# Uses decision stumps (one-level trees) as weak learners +class AdaBoost: + def __init__(self, n_estimators=50): + # Number of boosting rounds + self.n_estimators = n_estimators + self.alphas = [] # Weights for each weak learner + self.models = [] # List of weak learners (stumps) + + def fit(self, X, y): + # X: (n_samples, n_features), y: (n_samples,) with labels 0 or 1 + n_samples, n_features = X.shape + w = np.ones(n_samples) / n_samples # Initialize sample weights + self.models = [] + self.alphas = [] + y_ = np.where(y == 0, -1, 1) # Convert labels to -1, 1 + for _ in range(self.n_estimators): + # Train a decision stump with weighted samples + stump = self._build_stump(X, y_, w) + pred = stump['pred'] + err = stump['error'] + # Compute alpha (learner weight) + alpha = 0.5 * np.log((1 - err) / (err + 1e-10)) + # Update sample weights + w *= np.exp(-alpha * y_ * pred) + w /= np.sum(w) + self.models.append(stump) + self.alphas.append(alpha) + + def predict(self, X): + # Aggregate predictions from all weak learners + clf_preds = np.zeros(X.shape[0]) + for alpha, stump in zip(self.alphas, self.models): + pred = self._stump_predict(X, stump['feature'], stump['threshold'], stump['polarity']) + clf_preds += alpha * pred + # Return final prediction (majority vote) + return np.where(clf_preds >= 0, 1, 0) + + def _build_stump(self, X, y, w): + # Find the best decision stump for current weights + n_samples, n_features = X.shape + min_error = float('inf') + best_stump = {} + for feature in range(n_features): + thresholds = np.unique(X[:, feature]) + for threshold in thresholds: + for polarity in [1, -1]: + pred = self._stump_predict(X, feature, threshold, polarity) + error = np.sum(w * (pred != y)) + if error < min_error: + min_error = error + best_stump = { + 'feature': feature, + 'threshold': threshold, + 'polarity': polarity, + 'error': error, + 'pred': pred.copy() + } + return best_stump + + def _stump_predict(self, X, feature, threshold, polarity): + # Predict using a single decision stump + pred = np.ones(X.shape[0]) + if polarity == 1: + pred[X[:, feature] < threshold] = -1 + else: + pred[X[:, feature] > threshold] = -1 + return pred From 851be66222e3d7e8b1cc0d9823e2dbe0a960cd2d Mon Sep 17 00:00:00 2001 From: Ankita Mishra Date: Mon, 6 Oct 2025 10:43:54 -0500 Subject: [PATCH 02/16] Added Adaboost algorithm --- machine_learning/adaboost.py | 89 +++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 26 deletions(-) diff --git a/machine_learning/adaboost.py b/machine_learning/adaboost.py index b31ede2651c9..96369c812de3 100644 --- a/machine_learning/adaboost.py +++ b/machine_learning/adaboost.py @@ -1,17 +1,37 @@ +""" +AdaBoost implementation for binary classification using decision stumps. + +Reference: https://en.wikipedia.org/wiki/AdaBoost + +>>> import numpy as np +>>> X = np.array([[0, 0], [1, 1], [1, 0], [0, 1]]) +>>> y = np.array([0, 1, 1, 0]) +>>> clf = AdaBoost(n_estimators=5) +>>> clf.fit(X, y) +>>> clf.predict(np.array([[0, 0], [1, 1]])) +array([0, 1]) +""" import numpy as np +from typing import Any, Dict, List + -# AdaBoost implementation for binary classification -# Uses decision stumps (one-level trees) as weak learners class AdaBoost: - def __init__(self, n_estimators=50): - # Number of boosting rounds - self.n_estimators = n_estimators - self.alphas = [] # Weights for each weak learner - self.models = [] # List of weak learners (stumps) + def __init__(self, n_estimators: int = 50) -> None: + """Initialize AdaBoost classifier. + Args: + n_estimators: Number of boosting rounds. + """ + self.n_estimators: int = n_estimators + self.alphas: List[float] = [] # Weights for each weak learner + self.models: List[Dict[str, Any]] = [] # List of weak learners (stumps) - def fit(self, X, y): - # X: (n_samples, n_features), y: (n_samples,) with labels 0 or 1 + def fit(self, X: np.ndarray, y: np.ndarray) -> None: + """Fit AdaBoost model. + Args: + X: (n_samples, n_features) feature matrix + y: (n_samples,) labels (0 or 1) + """ n_samples, n_features = X.shape w = np.ones(n_samples) / n_samples # Initialize sample weights self.models = [] @@ -20,8 +40,8 @@ def fit(self, X, y): for _ in range(self.n_estimators): # Train a decision stump with weighted samples stump = self._build_stump(X, y_, w) - pred = stump['pred'] - err = stump['error'] + pred = stump["pred"] + err = stump["error"] # Compute alpha (learner weight) alpha = 0.5 * np.log((1 - err) / (err + 1e-10)) # Update sample weights @@ -30,20 +50,35 @@ def fit(self, X, y): self.models.append(stump) self.alphas.append(alpha) - def predict(self, X): - # Aggregate predictions from all weak learners + def predict(self, X: np.ndarray) -> np.ndarray: + """Predict class labels for samples in X. + Args: + X: (n_samples, n_features) feature matrix + Returns: + (n_samples,) predicted labels (0 or 1) + >>> import numpy as np + >>> X = np.array([[0, 0], [1, 1], [1, 0], [0, 1]]) + >>> y = np.array([0, 1, 1, 0]) + >>> clf = AdaBoost(n_estimators=5) + >>> clf.fit(X, y) + >>> clf.predict(np.array([[0, 0], [1, 1]])) + array([0, 1]) + """ clf_preds = np.zeros(X.shape[0]) for alpha, stump in zip(self.alphas, self.models): - pred = self._stump_predict(X, stump['feature'], stump['threshold'], stump['polarity']) + pred = self._stump_predict( + X, stump["feature"], stump["threshold"], stump["polarity"] + ) clf_preds += alpha * pred - # Return final prediction (majority vote) return np.where(clf_preds >= 0, 1, 0) - def _build_stump(self, X, y, w): - # Find the best decision stump for current weights + def _build_stump( + self, X: np.ndarray, y: np.ndarray, w: np.ndarray + ) -> Dict[str, Any]: + """Find the best decision stump for current weights.""" n_samples, n_features = X.shape - min_error = float('inf') - best_stump = {} + min_error = float("inf") + best_stump: Dict[str, Any] = {} for feature in range(n_features): thresholds = np.unique(X[:, feature]) for threshold in thresholds: @@ -53,16 +88,18 @@ def _build_stump(self, X, y, w): if error < min_error: min_error = error best_stump = { - 'feature': feature, - 'threshold': threshold, - 'polarity': polarity, - 'error': error, - 'pred': pred.copy() + "feature": feature, + "threshold": threshold, + "polarity": polarity, + "error": error, + "pred": pred.copy(), } return best_stump - def _stump_predict(self, X, feature, threshold, polarity): - # Predict using a single decision stump + def _stump_predict( + self, X: np.ndarray, feature: int, threshold: float, polarity: int + ) -> np.ndarray: + """Predict using a single decision stump.""" pred = np.ones(X.shape[0]) if polarity == 1: pred[X[:, feature] < threshold] = -1 From 6f801ac806c5501d52a13676bdd2b522e98931a2 Mon Sep 17 00:00:00 2001 From: Ankita Mishra Date: Mon, 6 Oct 2025 10:51:22 -0500 Subject: [PATCH 03/16] Added Adaboost algorithm --- machine_learning/adaboost.py | 58 ++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/machine_learning/adaboost.py b/machine_learning/adaboost.py index 96369c812de3..44cd2ea51373 100644 --- a/machine_learning/adaboost.py +++ b/machine_learning/adaboost.py @@ -4,10 +4,10 @@ Reference: https://en.wikipedia.org/wiki/AdaBoost >>> import numpy as np ->>> X = np.array([[0, 0], [1, 1], [1, 0], [0, 1]]) ->>> y = np.array([0, 1, 1, 0]) +>>> features = np.array([[0, 0], [1, 1], [1, 0], [0, 1]]) +>>> labels = np.array([0, 1, 1, 0]) >>> clf = AdaBoost(n_estimators=5) ->>> clf.fit(X, y) +>>> clf.fit(features, labels) >>> clf.predict(np.array([[0, 0], [1, 1]])) array([0, 1]) """ @@ -26,65 +26,65 @@ def __init__(self, n_estimators: int = 50) -> None: self.alphas: List[float] = [] # Weights for each weak learner self.models: List[Dict[str, Any]] = [] # List of weak learners (stumps) - def fit(self, X: np.ndarray, y: np.ndarray) -> None: + def fit(self, feature_matrix: np.ndarray, target: np.ndarray) -> None: """Fit AdaBoost model. Args: - X: (n_samples, n_features) feature matrix - y: (n_samples,) labels (0 or 1) + feature_matrix: (n_samples, n_features) feature matrix + target: (n_samples,) labels (0 or 1) """ - n_samples, n_features = X.shape - w = np.ones(n_samples) / n_samples # Initialize sample weights + n_samples, n_features = feature_matrix.shape + sample_weights = np.ones(n_samples) / n_samples # Initialize sample weights self.models = [] self.alphas = [] - y_ = np.where(y == 0, -1, 1) # Convert labels to -1, 1 + y_signed = np.where(target == 0, -1, 1) # Convert labels to -1, 1 for _ in range(self.n_estimators): # Train a decision stump with weighted samples - stump = self._build_stump(X, y_, w) + stump = self._build_stump(feature_matrix, y_signed, sample_weights) pred = stump["pred"] err = stump["error"] # Compute alpha (learner weight) alpha = 0.5 * np.log((1 - err) / (err + 1e-10)) # Update sample weights - w *= np.exp(-alpha * y_ * pred) - w /= np.sum(w) + sample_weights *= np.exp(-alpha * y_signed * pred) + sample_weights /= np.sum(sample_weights) self.models.append(stump) self.alphas.append(alpha) - def predict(self, X: np.ndarray) -> np.ndarray: - """Predict class labels for samples in X. + def predict(self, feature_matrix: np.ndarray) -> np.ndarray: + """Predict class labels for samples in feature_matrix. Args: - X: (n_samples, n_features) feature matrix + feature_matrix: (n_samples, n_features) feature matrix Returns: (n_samples,) predicted labels (0 or 1) >>> import numpy as np - >>> X = np.array([[0, 0], [1, 1], [1, 0], [0, 1]]) - >>> y = np.array([0, 1, 1, 0]) + >>> features = np.array([[0, 0], [1, 1], [1, 0], [0, 1]]) + >>> labels = np.array([0, 1, 1, 0]) >>> clf = AdaBoost(n_estimators=5) - >>> clf.fit(X, y) + >>> clf.fit(features, labels) >>> clf.predict(np.array([[0, 0], [1, 1]])) array([0, 1]) """ - clf_preds = np.zeros(X.shape[0]) + clf_preds = np.zeros(feature_matrix.shape[0]) for alpha, stump in zip(self.alphas, self.models): pred = self._stump_predict( - X, stump["feature"], stump["threshold"], stump["polarity"] + feature_matrix, stump["feature"], stump["threshold"], stump["polarity"] ) clf_preds += alpha * pred return np.where(clf_preds >= 0, 1, 0) def _build_stump( - self, X: np.ndarray, y: np.ndarray, w: np.ndarray + self, feature_matrix: np.ndarray, target_signed: np.ndarray, sample_weights: np.ndarray ) -> Dict[str, Any]: """Find the best decision stump for current weights.""" - n_samples, n_features = X.shape + n_samples, n_features = feature_matrix.shape min_error = float("inf") best_stump: Dict[str, Any] = {} for feature in range(n_features): - thresholds = np.unique(X[:, feature]) + thresholds = np.unique(feature_matrix[:, feature]) for threshold in thresholds: for polarity in [1, -1]: - pred = self._stump_predict(X, feature, threshold, polarity) - error = np.sum(w * (pred != y)) + pred = self._stump_predict(feature_matrix, feature, threshold, polarity) + error = np.sum(sample_weights * (pred != target_signed)) if error < min_error: min_error = error best_stump = { @@ -97,12 +97,12 @@ def _build_stump( return best_stump def _stump_predict( - self, X: np.ndarray, feature: int, threshold: float, polarity: int + self, feature_matrix: np.ndarray, feature: int, threshold: float, polarity: int ) -> np.ndarray: """Predict using a single decision stump.""" - pred = np.ones(X.shape[0]) + pred = np.ones(feature_matrix.shape[0]) if polarity == 1: - pred[X[:, feature] < threshold] = -1 + pred[feature_matrix[:, feature] < threshold] = -1 else: - pred[X[:, feature] > threshold] = -1 + pred[feature_matrix[:, feature] > threshold] = -1 return pred From 6c93b32df6eb07fdf343aedce856827c4d140754 Mon Sep 17 00:00:00 2001 From: Ankita Mishra Date: Mon, 6 Oct 2025 11:02:20 -0500 Subject: [PATCH 04/16] Added ARIMA time series Model --- machine_learning/arima.py | 85 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 machine_learning/arima.py diff --git a/machine_learning/arima.py b/machine_learning/arima.py new file mode 100644 index 000000000000..28c17fc9f0d2 --- /dev/null +++ b/machine_learning/arima.py @@ -0,0 +1,85 @@ +""" +ARIMA (AutoRegressive Integrated Moving Average) model for time series forecasting. + +Reference: https://en.wikipedia.org/wiki/Autoregressive_integrated_moving_average + +>>> import numpy as np +>>> series = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) +>>> model = ARIMAModel(p=2, d=1, q=0) +>>> model.fit(series) +ARIMAModel(...) +>>> model.predict(series, n_periods=2) +array([10.99999999, 12.00000001]) +""" + +import numpy as np +from typing import Optional + +class ARIMAModel: + def __init__(self, p: int = 1, d: int = 0, q: int = 0) -> None: + """Initialize ARIMA model. + Args: + p: AR order + d: Differencing order + q: MA order (not used in this implementation) + """ + self.p = p + self.d = d + self.q = q + self.coef_: Optional[np.ndarray] = None + self.resid_: Optional[np.ndarray] = None + + def difference(self, series: np.ndarray, order: int) -> np.ndarray: + """Apply differencing to make series stationary.""" + for _ in range(order): + series = np.diff(series) + return series + + def fit(self, time_series: np.ndarray) -> 'ARIMAModel': + """Fit ARIMA model to the given time series. + Args: + time_series: 1D numpy array of time series values + Returns: + self + >>> import numpy as np + >>> series = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + >>> model = ARIMAModel(p=2, d=1, q=0) + >>> model.fit(series) + ARIMAModel(...) + """ + y = np.asarray(time_series) + y_diff = self.difference(y, self.d) + # Build lagged feature matrix + feature_matrix = np.column_stack([np.roll(y_diff, i) for i in range(1, self.p + 1)]) + feature_matrix = feature_matrix[self.p:] + target = y_diff[self.p:] + # Add intercept + feature_matrix = np.hstack([np.ones((feature_matrix.shape[0], 1)), feature_matrix]) + # Solve least squares for AR coefficients + self.coef_ = np.linalg.lstsq(feature_matrix, target, rcond=None)[0] + self.resid_ = target - feature_matrix @ self.coef_ + return self + + def predict(self, time_series: np.ndarray, n_periods: int = 1) -> np.ndarray: + """Forecast n_periods ahead given observed time_series. + Args: + time_series: 1D numpy array of observed values + n_periods: Number of periods to forecast + Returns: + 1D numpy array of forecasted values + >>> import numpy as np + >>> series = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + >>> model = ARIMAModel(p=2, d=1, q=0) + >>> model.fit(series) + ARIMAModel(...) + >>> model.predict(series, n_periods=2) + array([10.99999999, 12.00000001]) + """ + y = np.asarray(time_series) + y_pred = list(y[-self.p:]) + for _ in range(n_periods): + # Build feature vector for prediction + features = [1] + y_pred[-self.p:][::-1] + next_val = np.dot(features, self.coef_) + y_pred.append(next_val) + return np.array(y_pred[self.p:]) From 6820d512b918786cc103e559c12ddd8197157415 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 16:06:33 +0000 Subject: [PATCH 05/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- machine_learning/adaboost.py | 9 +++++++-- machine_learning/arima.py | 21 +++++++++++++-------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/machine_learning/adaboost.py b/machine_learning/adaboost.py index 44cd2ea51373..d74c5a354558 100644 --- a/machine_learning/adaboost.py +++ b/machine_learning/adaboost.py @@ -73,7 +73,10 @@ def predict(self, feature_matrix: np.ndarray) -> np.ndarray: return np.where(clf_preds >= 0, 1, 0) def _build_stump( - self, feature_matrix: np.ndarray, target_signed: np.ndarray, sample_weights: np.ndarray + self, + feature_matrix: np.ndarray, + target_signed: np.ndarray, + sample_weights: np.ndarray, ) -> Dict[str, Any]: """Find the best decision stump for current weights.""" n_samples, n_features = feature_matrix.shape @@ -83,7 +86,9 @@ def _build_stump( thresholds = np.unique(feature_matrix[:, feature]) for threshold in thresholds: for polarity in [1, -1]: - pred = self._stump_predict(feature_matrix, feature, threshold, polarity) + pred = self._stump_predict( + feature_matrix, feature, threshold, polarity + ) error = np.sum(sample_weights * (pred != target_signed)) if error < min_error: min_error = error diff --git a/machine_learning/arima.py b/machine_learning/arima.py index 28c17fc9f0d2..5e6d567d7373 100644 --- a/machine_learning/arima.py +++ b/machine_learning/arima.py @@ -15,6 +15,7 @@ import numpy as np from typing import Optional + class ARIMAModel: def __init__(self, p: int = 1, d: int = 0, q: int = 0) -> None: """Initialize ARIMA model. @@ -35,7 +36,7 @@ def difference(self, series: np.ndarray, order: int) -> np.ndarray: series = np.diff(series) return series - def fit(self, time_series: np.ndarray) -> 'ARIMAModel': + def fit(self, time_series: np.ndarray) -> "ARIMAModel": """Fit ARIMA model to the given time series. Args: time_series: 1D numpy array of time series values @@ -50,11 +51,15 @@ def fit(self, time_series: np.ndarray) -> 'ARIMAModel': y = np.asarray(time_series) y_diff = self.difference(y, self.d) # Build lagged feature matrix - feature_matrix = np.column_stack([np.roll(y_diff, i) for i in range(1, self.p + 1)]) - feature_matrix = feature_matrix[self.p:] - target = y_diff[self.p:] + feature_matrix = np.column_stack( + [np.roll(y_diff, i) for i in range(1, self.p + 1)] + ) + feature_matrix = feature_matrix[self.p :] + target = y_diff[self.p :] # Add intercept - feature_matrix = np.hstack([np.ones((feature_matrix.shape[0], 1)), feature_matrix]) + feature_matrix = np.hstack( + [np.ones((feature_matrix.shape[0], 1)), feature_matrix] + ) # Solve least squares for AR coefficients self.coef_ = np.linalg.lstsq(feature_matrix, target, rcond=None)[0] self.resid_ = target - feature_matrix @ self.coef_ @@ -76,10 +81,10 @@ def predict(self, time_series: np.ndarray, n_periods: int = 1) -> np.ndarray: array([10.99999999, 12.00000001]) """ y = np.asarray(time_series) - y_pred = list(y[-self.p:]) + y_pred = list(y[-self.p :]) for _ in range(n_periods): # Build feature vector for prediction - features = [1] + y_pred[-self.p:][::-1] + features = [1] + y_pred[-self.p :][::-1] next_val = np.dot(features, self.coef_) y_pred.append(next_val) - return np.array(y_pred[self.p:]) + return np.array(y_pred[self.p :]) From a130bf811395172d4530b4ad875030ba96cfeb55 Mon Sep 17 00:00:00 2001 From: Ankita Mishra Date: Mon, 6 Oct 2025 11:09:50 -0500 Subject: [PATCH 06/16] Update ARIMA time series Model --- machine_learning/arima.py | 42 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/machine_learning/arima.py b/machine_learning/arima.py index 5e6d567d7373..83f27d1ab432 100644 --- a/machine_learning/arima.py +++ b/machine_learning/arima.py @@ -5,7 +5,7 @@ >>> import numpy as np >>> series = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) ->>> model = ARIMAModel(p=2, d=1, q=0) +>>> model = ARIMAModel(ar_order=2, diff_order=1, ma_order=0) >>> model.fit(series) ARIMAModel(...) >>> model.predict(series, n_periods=2) @@ -17,24 +17,24 @@ class ARIMAModel: - def __init__(self, p: int = 1, d: int = 0, q: int = 0) -> None: + def __init__(self, ar_order: int = 1, diff_order: int = 0, ma_order: int = 0) -> None: """Initialize ARIMA model. Args: - p: AR order - d: Differencing order - q: MA order (not used in this implementation) + ar_order: Autoregressive order (p) + diff_order: Differencing order (d) + ma_order: Moving average order (q, not used in this implementation) """ - self.p = p - self.d = d - self.q = q + self.ar_order = ar_order + self.diff_order = diff_order + self.ma_order = ma_order self.coef_: Optional[np.ndarray] = None self.resid_: Optional[np.ndarray] = None - def difference(self, series: np.ndarray, order: int) -> np.ndarray: + def difference(self, time_series: np.ndarray, order: int) -> np.ndarray: """Apply differencing to make series stationary.""" for _ in range(order): - series = np.diff(series) - return series + time_series = np.diff(time_series) + return time_series def fit(self, time_series: np.ndarray) -> "ARIMAModel": """Fit ARIMA model to the given time series. @@ -44,18 +44,16 @@ def fit(self, time_series: np.ndarray) -> "ARIMAModel": self >>> import numpy as np >>> series = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - >>> model = ARIMAModel(p=2, d=1, q=0) + >>> model = ARIMAModel(ar_order=2, diff_order=1, ma_order=0) >>> model.fit(series) ARIMAModel(...) """ y = np.asarray(time_series) - y_diff = self.difference(y, self.d) + y_diff = self.difference(y, self.diff_order) # Build lagged feature matrix - feature_matrix = np.column_stack( - [np.roll(y_diff, i) for i in range(1, self.p + 1)] - ) - feature_matrix = feature_matrix[self.p :] - target = y_diff[self.p :] + feature_matrix = np.column_stack([np.roll(y_diff, i) for i in range(1, self.ar_order + 1)]) + feature_matrix = feature_matrix[self.ar_order:] + target = y_diff[self.ar_order:] # Add intercept feature_matrix = np.hstack( [np.ones((feature_matrix.shape[0], 1)), feature_matrix] @@ -74,17 +72,17 @@ def predict(self, time_series: np.ndarray, n_periods: int = 1) -> np.ndarray: 1D numpy array of forecasted values >>> import numpy as np >>> series = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - >>> model = ARIMAModel(p=2, d=1, q=0) + >>> model = ARIMAModel(ar_order=2, diff_order=1, ma_order=0) >>> model.fit(series) ARIMAModel(...) >>> model.predict(series, n_periods=2) array([10.99999999, 12.00000001]) """ y = np.asarray(time_series) - y_pred = list(y[-self.p :]) + y_pred = list(y[-self.ar_order:]) for _ in range(n_periods): # Build feature vector for prediction - features = [1] + y_pred[-self.p :][::-1] + features = [1] + y_pred[-self.ar_order:][::-1] next_val = np.dot(features, self.coef_) y_pred.append(next_val) - return np.array(y_pred[self.p :]) + return np.array(y_pred[self.ar_order:]) From bce865401dd77cc95ece8e64ceab5c040a48533e Mon Sep 17 00:00:00 2001 From: Ankita Mishra Date: Mon, 6 Oct 2025 11:36:08 -0500 Subject: [PATCH 07/16] Update ARIMA time series Model --- machine_learning/adaboost.py | 11 ++++++----- machine_learning/arima.py | 6 +++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/machine_learning/adaboost.py b/machine_learning/adaboost.py index d74c5a354558..c1e9256f1eab 100644 --- a/machine_learning/adaboost.py +++ b/machine_learning/adaboost.py @@ -12,8 +12,9 @@ array([0, 1]) """ +from typing import Any + import numpy as np -from typing import Any, Dict, List class AdaBoost: @@ -23,8 +24,8 @@ def __init__(self, n_estimators: int = 50) -> None: n_estimators: Number of boosting rounds. """ self.n_estimators: int = n_estimators - self.alphas: List[float] = [] # Weights for each weak learner - self.models: List[Dict[str, Any]] = [] # List of weak learners (stumps) + self.alphas: list[float] = [] # Weights for each weak learner + self.models: list[dict[str, Any]] = [] # List of weak learners (stumps) def fit(self, feature_matrix: np.ndarray, target: np.ndarray) -> None: """Fit AdaBoost model. @@ -77,11 +78,11 @@ def _build_stump( feature_matrix: np.ndarray, target_signed: np.ndarray, sample_weights: np.ndarray, - ) -> Dict[str, Any]: + ) -> dict[str, Any]: """Find the best decision stump for current weights.""" n_samples, n_features = feature_matrix.shape min_error = float("inf") - best_stump: Dict[str, Any] = {} + best_stump: dict[str, Any] = {} for feature in range(n_features): thresholds = np.unique(feature_matrix[:, feature]) for threshold in thresholds: diff --git a/machine_learning/arima.py b/machine_learning/arima.py index 83f27d1ab432..b0374ef38829 100644 --- a/machine_learning/arima.py +++ b/machine_learning/arima.py @@ -12,8 +12,8 @@ array([10.99999999, 12.00000001]) """ + import numpy as np -from typing import Optional class ARIMAModel: @@ -27,8 +27,8 @@ def __init__(self, ar_order: int = 1, diff_order: int = 0, ma_order: int = 0) -> self.ar_order = ar_order self.diff_order = diff_order self.ma_order = ma_order - self.coef_: Optional[np.ndarray] = None - self.resid_: Optional[np.ndarray] = None + self.coef_: np.ndarray | None = None + self.resid_: np.ndarray | None = None def difference(self, time_series: np.ndarray, order: int) -> np.ndarray: """Apply differencing to make series stationary.""" From e318b886c68f5ec3cd7ae239fe6f1fcf22b0cc3c Mon Sep 17 00:00:00 2001 From: Ankita Mishra Date: Mon, 6 Oct 2025 11:41:58 -0500 Subject: [PATCH 08/16] Fixing Adaboost algorithm --- machine_learning/adaboost.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/machine_learning/adaboost.py b/machine_learning/adaboost.py index c1e9256f1eab..4024a6def360 100644 --- a/machine_learning/adaboost.py +++ b/machine_learning/adaboost.py @@ -12,9 +12,8 @@ array([0, 1]) """ -from typing import Any - import numpy as np +from typing import Any class AdaBoost: @@ -33,7 +32,7 @@ def fit(self, feature_matrix: np.ndarray, target: np.ndarray) -> None: feature_matrix: (n_samples, n_features) feature matrix target: (n_samples,) labels (0 or 1) """ - n_samples, n_features = feature_matrix.shape + n_samples, _n_features = feature_matrix.shape sample_weights = np.ones(n_samples) / n_samples # Initialize sample weights self.models = [] self.alphas = [] @@ -74,22 +73,17 @@ def predict(self, feature_matrix: np.ndarray) -> np.ndarray: return np.where(clf_preds >= 0, 1, 0) def _build_stump( - self, - feature_matrix: np.ndarray, - target_signed: np.ndarray, - sample_weights: np.ndarray, + self, feature_matrix: np.ndarray, target_signed: np.ndarray, sample_weights: np.ndarray ) -> dict[str, Any]: """Find the best decision stump for current weights.""" - n_samples, n_features = feature_matrix.shape + _n_samples, n_features = feature_matrix.shape min_error = float("inf") best_stump: dict[str, Any] = {} for feature in range(n_features): thresholds = np.unique(feature_matrix[:, feature]) for threshold in thresholds: for polarity in [1, -1]: - pred = self._stump_predict( - feature_matrix, feature, threshold, polarity - ) + pred = self._stump_predict(feature_matrix, feature, threshold, polarity) error = np.sum(sample_weights * (pred != target_signed)) if error < min_error: min_error = error From 7f2785758ce205e4bb34ff2d0570963d2e6a4ffe Mon Sep 17 00:00:00 2001 From: Ankita Mishra Date: Mon, 6 Oct 2025 11:52:31 -0500 Subject: [PATCH 09/16] Fixing Adaboost algorithm --- machine_learning/adaboost.py | 103 +++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 30 deletions(-) diff --git a/machine_learning/adaboost.py b/machine_learning/adaboost.py index 4024a6def360..463c69e349cd 100644 --- a/machine_learning/adaboost.py +++ b/machine_learning/adaboost.py @@ -18,73 +18,103 @@ class AdaBoost: def __init__(self, n_estimators: int = 50) -> None: - """Initialize AdaBoost classifier. + """ + Initialize AdaBoost classifier. + Args: - n_estimators: Number of boosting rounds. + n_estimators: Number of boosting rounds (weak learners). """ self.n_estimators: int = n_estimators - self.alphas: list[float] = [] # Weights for each weak learner - self.models: list[dict[str, Any]] = [] # List of weak learners (stumps) + self.alphas: list[float] = [] # Weights assigned to each weak learner + self.models: list[dict[str, Any]] = [] # Stores each decision stump def fit(self, feature_matrix: np.ndarray, target: np.ndarray) -> None: - """Fit AdaBoost model. + """ + Train AdaBoost model using decision stumps. + Args: - feature_matrix: (n_samples, n_features) feature matrix - target: (n_samples,) labels (0 or 1) + feature_matrix: 2D array of shape (n_samples, n_features) + target: 1D array of binary labels (0 or 1) """ - n_samples, _n_features = feature_matrix.shape - sample_weights = np.ones(n_samples) / n_samples # Initialize sample weights + n_samples, _ = feature_matrix.shape + + # Initialize uniform sample weights + sample_weights = np.ones(n_samples) / n_samples + + # Reset model state self.models = [] self.alphas = [] - y_signed = np.where(target == 0, -1, 1) # Convert labels to -1, 1 + + # Convert labels to {-1, 1} for boosting + y_signed = np.where(target == 0, -1, 1) + for _ in range(self.n_estimators): - # Train a decision stump with weighted samples + # Train a weighted decision stump stump = self._build_stump(feature_matrix, y_signed, sample_weights) pred = stump["pred"] err = stump["error"] - # Compute alpha (learner weight) + + # Compute alpha (learner weight) with numerical stability alpha = 0.5 * np.log((1 - err) / (err + 1e-10)) - # Update sample weights + + # Update sample weights to focus on misclassified points sample_weights *= np.exp(-alpha * y_signed * pred) sample_weights /= np.sum(sample_weights) + + # Store the stump and its weight self.models.append(stump) self.alphas.append(alpha) def predict(self, feature_matrix: np.ndarray) -> np.ndarray: - """Predict class labels for samples in feature_matrix. + """ + Predict binary class labels for input samples. + Args: - feature_matrix: (n_samples, n_features) feature matrix + feature_matrix: 2D array of shape (n_samples, n_features) + Returns: - (n_samples,) predicted labels (0 or 1) - >>> import numpy as np - >>> features = np.array([[0, 0], [1, 1], [1, 0], [0, 1]]) - >>> labels = np.array([0, 1, 1, 0]) - >>> clf = AdaBoost(n_estimators=5) - >>> clf.fit(features, labels) - >>> clf.predict(np.array([[0, 0], [1, 1]])) - array([0, 1]) + 1D array of predicted labels (0 or 1) """ clf_preds = np.zeros(feature_matrix.shape[0]) + + # Aggregate predictions from all stumps for alpha, stump in zip(self.alphas, self.models): pred = self._stump_predict( - feature_matrix, stump["feature"], stump["threshold"], stump["polarity"] + feature_matrix, + stump["feature"], + stump["threshold"], + stump["polarity"], ) clf_preds += alpha * pred + + # Final prediction: sign of weighted sum return np.where(clf_preds >= 0, 1, 0) def _build_stump( - self, feature_matrix: np.ndarray, target_signed: np.ndarray, sample_weights: np.ndarray + self, + feature_matrix: np.ndarray, + target_signed: np.ndarray, + sample_weights: np.ndarray, ) -> dict[str, Any]: - """Find the best decision stump for current weights.""" - _n_samples, n_features = feature_matrix.shape + """ + Build the best decision stump for current sample weights. + + Returns: + Dictionary containing stump parameters and predictions. + """ + _, n_features = feature_matrix.shape min_error = float("inf") best_stump: dict[str, Any] = {} + + # Iterate over all features and thresholds for feature in range(n_features): thresholds = np.unique(feature_matrix[:, feature]) for threshold in thresholds: for polarity in [1, -1]: pred = self._stump_predict(feature_matrix, feature, threshold, polarity) error = np.sum(sample_weights * (pred != target_signed)) + + # Keep stump with lowest weighted error if error < min_error: min_error = error best_stump = { @@ -94,15 +124,28 @@ def _build_stump( "error": error, "pred": pred.copy(), } + return best_stump def _stump_predict( - self, feature_matrix: np.ndarray, feature: int, threshold: float, polarity: int + self, + feature_matrix: np.ndarray, + feature: int, + threshold: float, + polarity: int, ) -> np.ndarray: - """Predict using a single decision stump.""" + """ + Predict using a single decision stump. + + Returns: + 1D array of predictions in {-1, 1} + """ pred = np.ones(feature_matrix.shape[0]) + + # Apply polarity to threshold comparison if polarity == 1: pred[feature_matrix[:, feature] < threshold] = -1 else: pred[feature_matrix[:, feature] > threshold] = -1 - return pred + + return pred \ No newline at end of file From 533758fb763c0d035abaacecc390b40ef2a6ee41 Mon Sep 17 00:00:00 2001 From: Ankita Mishra Date: Mon, 6 Oct 2025 12:19:30 -0500 Subject: [PATCH 10/16] Remove unrelated AdaBoost file from ARIMA PR --- machine_learning/adaboost.py | 151 ----------------------------------- 1 file changed, 151 deletions(-) delete mode 100644 machine_learning/adaboost.py diff --git a/machine_learning/adaboost.py b/machine_learning/adaboost.py deleted file mode 100644 index 463c69e349cd..000000000000 --- a/machine_learning/adaboost.py +++ /dev/null @@ -1,151 +0,0 @@ -""" -AdaBoost implementation for binary classification using decision stumps. - -Reference: https://en.wikipedia.org/wiki/AdaBoost - ->>> import numpy as np ->>> features = np.array([[0, 0], [1, 1], [1, 0], [0, 1]]) ->>> labels = np.array([0, 1, 1, 0]) ->>> clf = AdaBoost(n_estimators=5) ->>> clf.fit(features, labels) ->>> clf.predict(np.array([[0, 0], [1, 1]])) -array([0, 1]) -""" - -import numpy as np -from typing import Any - - -class AdaBoost: - def __init__(self, n_estimators: int = 50) -> None: - """ - Initialize AdaBoost classifier. - - Args: - n_estimators: Number of boosting rounds (weak learners). - """ - self.n_estimators: int = n_estimators - self.alphas: list[float] = [] # Weights assigned to each weak learner - self.models: list[dict[str, Any]] = [] # Stores each decision stump - - def fit(self, feature_matrix: np.ndarray, target: np.ndarray) -> None: - """ - Train AdaBoost model using decision stumps. - - Args: - feature_matrix: 2D array of shape (n_samples, n_features) - target: 1D array of binary labels (0 or 1) - """ - n_samples, _ = feature_matrix.shape - - # Initialize uniform sample weights - sample_weights = np.ones(n_samples) / n_samples - - # Reset model state - self.models = [] - self.alphas = [] - - # Convert labels to {-1, 1} for boosting - y_signed = np.where(target == 0, -1, 1) - - for _ in range(self.n_estimators): - # Train a weighted decision stump - stump = self._build_stump(feature_matrix, y_signed, sample_weights) - pred = stump["pred"] - err = stump["error"] - - # Compute alpha (learner weight) with numerical stability - alpha = 0.5 * np.log((1 - err) / (err + 1e-10)) - - # Update sample weights to focus on misclassified points - sample_weights *= np.exp(-alpha * y_signed * pred) - sample_weights /= np.sum(sample_weights) - - # Store the stump and its weight - self.models.append(stump) - self.alphas.append(alpha) - - def predict(self, feature_matrix: np.ndarray) -> np.ndarray: - """ - Predict binary class labels for input samples. - - Args: - feature_matrix: 2D array of shape (n_samples, n_features) - - Returns: - 1D array of predicted labels (0 or 1) - """ - clf_preds = np.zeros(feature_matrix.shape[0]) - - # Aggregate predictions from all stumps - for alpha, stump in zip(self.alphas, self.models): - pred = self._stump_predict( - feature_matrix, - stump["feature"], - stump["threshold"], - stump["polarity"], - ) - clf_preds += alpha * pred - - # Final prediction: sign of weighted sum - return np.where(clf_preds >= 0, 1, 0) - - def _build_stump( - self, - feature_matrix: np.ndarray, - target_signed: np.ndarray, - sample_weights: np.ndarray, - ) -> dict[str, Any]: - """ - Build the best decision stump for current sample weights. - - Returns: - Dictionary containing stump parameters and predictions. - """ - _, n_features = feature_matrix.shape - min_error = float("inf") - best_stump: dict[str, Any] = {} - - # Iterate over all features and thresholds - for feature in range(n_features): - thresholds = np.unique(feature_matrix[:, feature]) - for threshold in thresholds: - for polarity in [1, -1]: - pred = self._stump_predict(feature_matrix, feature, threshold, polarity) - error = np.sum(sample_weights * (pred != target_signed)) - - # Keep stump with lowest weighted error - if error < min_error: - min_error = error - best_stump = { - "feature": feature, - "threshold": threshold, - "polarity": polarity, - "error": error, - "pred": pred.copy(), - } - - return best_stump - - def _stump_predict( - self, - feature_matrix: np.ndarray, - feature: int, - threshold: float, - polarity: int, - ) -> np.ndarray: - """ - Predict using a single decision stump. - - Returns: - 1D array of predictions in {-1, 1} - """ - pred = np.ones(feature_matrix.shape[0]) - - # Apply polarity to threshold comparison - if polarity == 1: - pred[feature_matrix[:, feature] < threshold] = -1 - else: - pred[feature_matrix[:, feature] > threshold] = -1 - - return pred \ No newline at end of file From e26406b7d67a187ec2094d6b2c74681671f76383 Mon Sep 17 00:00:00 2001 From: Ankita Mishra Date: Mon, 6 Oct 2025 12:34:10 -0500 Subject: [PATCH 11/16] Final Ruff-compliant ARIMA implementation --- machine_learning/arima.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/machine_learning/arima.py b/machine_learning/arima.py index b0374ef38829..798627889441 100644 --- a/machine_learning/arima.py +++ b/machine_learning/arima.py @@ -12,12 +12,16 @@ array([10.99999999, 12.00000001]) """ - import numpy as np class ARIMAModel: - def __init__(self, ar_order: int = 1, diff_order: int = 0, ma_order: int = 0) -> None: + def __init__( + self, + ar_order: int = 1, + diff_order: int = 0, + ma_order: int = 0, + ) -> None: """Initialize ARIMA model. Args: ar_order: Autoregressive order (p) @@ -50,14 +54,18 @@ def fit(self, time_series: np.ndarray) -> "ARIMAModel": """ y = np.asarray(time_series) y_diff = self.difference(y, self.diff_order) + # Build lagged feature matrix - feature_matrix = np.column_stack([np.roll(y_diff, i) for i in range(1, self.ar_order + 1)]) + feature_matrix = np.column_stack( + [np.roll(y_diff, i) for i in range(1, self.ar_order + 1)] + ) feature_matrix = feature_matrix[self.ar_order:] target = y_diff[self.ar_order:] + # Add intercept - feature_matrix = np.hstack( - [np.ones((feature_matrix.shape[0], 1)), feature_matrix] - ) + intercept = np.ones((feature_matrix.shape[0], 1)) + feature_matrix = np.hstack([intercept, feature_matrix]) + # Solve least squares for AR coefficients self.coef_ = np.linalg.lstsq(feature_matrix, target, rcond=None)[0] self.resid_ = target - feature_matrix @ self.coef_ @@ -82,7 +90,7 @@ def predict(self, time_series: np.ndarray, n_periods: int = 1) -> np.ndarray: y_pred = list(y[-self.ar_order:]) for _ in range(n_periods): # Build feature vector for prediction - features = [1] + y_pred[-self.ar_order:][::-1] + features = [1, *y_pred[-self.ar_order:][::-1]] next_val = np.dot(features, self.coef_) y_pred.append(next_val) return np.array(y_pred[self.ar_order:]) From 712100c2e558b93f1c3b4b1a80f105863dad5b90 Mon Sep 17 00:00:00 2001 From: Ankita Mishra Date: Mon, 6 Oct 2025 12:42:57 -0500 Subject: [PATCH 12/16] Add CNN Algorithm --- machine_learning/cnn.py | 67 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 machine_learning/cnn.py diff --git a/machine_learning/cnn.py b/machine_learning/cnn.py new file mode 100644 index 000000000000..306c53238419 --- /dev/null +++ b/machine_learning/cnn.py @@ -0,0 +1,67 @@ +""" +Convolutional Neural Network (CNN) implementation for image classification. + +Reference: https://en.wikipedia.org/wiki/Convolutional_neural_network + +>>> import numpy as np +>>> model = SimpleCNN(input_shape=(1, 28, 28), num_classes=10) +>>> dummy_input = np.random.rand(1, 28, 28) +>>> output = model.forward(dummy_input) +>>> output.shape +(10,) +""" + +import numpy as np +from typing import Tuple + + +class SimpleCNN: + def __init__(self, input_shape: Tuple[int, int, int], num_classes: int) -> None: + """ + Initialize a simple CNN model. + + Args: + input_shape: Tuple of (channels, height, width) + num_classes: Number of output classes + """ + self.input_shape = input_shape + self.num_classes = num_classes + self.filters = np.random.randn(8, input_shape[0], 3, 3) * 0.1 # 8 filters + self.fc_weights = np.random.randn(8 * 26 * 26, num_classes) * 0.1 + + def relu(self, x: np.ndarray) -> np.ndarray: + """Apply ReLU activation.""" + return np.maximum(0, x) + + def convolve(self, x: np.ndarray, filters: np.ndarray) -> np.ndarray: + """Apply convolution operation.""" + batch, height, width = x.shape + num_filters, _, fh, fw = filters.shape + output = np.zeros((num_filters, height - fh + 1, width - fw + 1)) + + for f in range(num_filters): + for i in range(height - fh + 1): + for j in range(width - fw + 1): + region = x[:, i:i + fh, j:j + fw] + output[f, i, j] = np.sum(region * filters[f]) + return output + + def flatten(self, x: np.ndarray) -> np.ndarray: + """Flatten the feature map.""" + return x.reshape(-1) + + def forward(self, x: np.ndarray) -> np.ndarray: + """ + Forward pass through the CNN. + + Args: + x: Input image of shape (channels, height, width) + + Returns: + Output logits of shape (num_classes,) + """ + conv_out = self.convolve(x, self.filters) + activated = self.relu(conv_out) + flattened = self.flatten(activated) + logits = flattened @ self.fc_weights + return logits \ No newline at end of file From 8c950279b23dac60a17bb4f14a36692faa5d0d50 Mon Sep 17 00:00:00 2001 From: Ankita Mishra Date: Mon, 6 Oct 2025 12:44:42 -0500 Subject: [PATCH 13/16] Remove unrelated ARIMA file from CNN PR --- machine_learning/arima.py | 96 --------------------------------------- 1 file changed, 96 deletions(-) delete mode 100644 machine_learning/arima.py diff --git a/machine_learning/arima.py b/machine_learning/arima.py deleted file mode 100644 index 798627889441..000000000000 --- a/machine_learning/arima.py +++ /dev/null @@ -1,96 +0,0 @@ -""" -ARIMA (AutoRegressive Integrated Moving Average) model for time series forecasting. - -Reference: https://en.wikipedia.org/wiki/Autoregressive_integrated_moving_average - ->>> import numpy as np ->>> series = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) ->>> model = ARIMAModel(ar_order=2, diff_order=1, ma_order=0) ->>> model.fit(series) -ARIMAModel(...) ->>> model.predict(series, n_periods=2) -array([10.99999999, 12.00000001]) -""" - -import numpy as np - - -class ARIMAModel: - def __init__( - self, - ar_order: int = 1, - diff_order: int = 0, - ma_order: int = 0, - ) -> None: - """Initialize ARIMA model. - Args: - ar_order: Autoregressive order (p) - diff_order: Differencing order (d) - ma_order: Moving average order (q, not used in this implementation) - """ - self.ar_order = ar_order - self.diff_order = diff_order - self.ma_order = ma_order - self.coef_: np.ndarray | None = None - self.resid_: np.ndarray | None = None - - def difference(self, time_series: np.ndarray, order: int) -> np.ndarray: - """Apply differencing to make series stationary.""" - for _ in range(order): - time_series = np.diff(time_series) - return time_series - - def fit(self, time_series: np.ndarray) -> "ARIMAModel": - """Fit ARIMA model to the given time series. - Args: - time_series: 1D numpy array of time series values - Returns: - self - >>> import numpy as np - >>> series = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - >>> model = ARIMAModel(ar_order=2, diff_order=1, ma_order=0) - >>> model.fit(series) - ARIMAModel(...) - """ - y = np.asarray(time_series) - y_diff = self.difference(y, self.diff_order) - - # Build lagged feature matrix - feature_matrix = np.column_stack( - [np.roll(y_diff, i) for i in range(1, self.ar_order + 1)] - ) - feature_matrix = feature_matrix[self.ar_order:] - target = y_diff[self.ar_order:] - - # Add intercept - intercept = np.ones((feature_matrix.shape[0], 1)) - feature_matrix = np.hstack([intercept, feature_matrix]) - - # Solve least squares for AR coefficients - self.coef_ = np.linalg.lstsq(feature_matrix, target, rcond=None)[0] - self.resid_ = target - feature_matrix @ self.coef_ - return self - - def predict(self, time_series: np.ndarray, n_periods: int = 1) -> np.ndarray: - """Forecast n_periods ahead given observed time_series. - Args: - time_series: 1D numpy array of observed values - n_periods: Number of periods to forecast - Returns: - 1D numpy array of forecasted values - >>> import numpy as np - >>> series = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - >>> model = ARIMAModel(ar_order=2, diff_order=1, ma_order=0) - >>> model.fit(series) - ARIMAModel(...) - >>> model.predict(series, n_periods=2) - array([10.99999999, 12.00000001]) - """ - y = np.asarray(time_series) - y_pred = list(y[-self.ar_order:]) - for _ in range(n_periods): - # Build feature vector for prediction - features = [1, *y_pred[-self.ar_order:][::-1]] - next_val = np.dot(features, self.coef_) - y_pred.append(next_val) - return np.array(y_pred[self.ar_order:]) From 7538cd7cc3193656a6bbbd7e6fc173ab9f20bb7d Mon Sep 17 00:00:00 2001 From: Ankita Mishra Date: Mon, 6 Oct 2025 12:53:51 -0500 Subject: [PATCH 14/16] Fix CNN Algo --- machine_learning/cnn.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/machine_learning/cnn.py b/machine_learning/cnn.py index 306c53238419..9ae83b82954e 100644 --- a/machine_learning/cnn.py +++ b/machine_learning/cnn.py @@ -12,11 +12,10 @@ """ import numpy as np -from typing import Tuple class SimpleCNN: - def __init__(self, input_shape: Tuple[int, int, int], num_classes: int) -> None: + def __init__(self, input_shape: tuple[int, int, int], num_classes: int) -> None: """ Initialize a simple CNN model. @@ -26,42 +25,43 @@ def __init__(self, input_shape: Tuple[int, int, int], num_classes: int) -> None: """ self.input_shape = input_shape self.num_classes = num_classes - self.filters = np.random.randn(8, input_shape[0], 3, 3) * 0.1 # 8 filters - self.fc_weights = np.random.randn(8 * 26 * 26, num_classes) * 0.1 + rng = np.random.default_rng() + self.filters = rng.normal(0, 0.1, size=(8, input_shape[0], 3, 3)) # 8 filters + self.fc_weights = rng.normal(0, 0.1, size=(8 * 26 * 26, num_classes)) - def relu(self, x: np.ndarray) -> np.ndarray: - """Apply ReLU activation.""" - return np.maximum(0, x) + def relu(self, feature_map: np.ndarray) -> np.ndarray: + """Apply ReLU activation to the feature map.""" + return np.maximum(0, feature_map) - def convolve(self, x: np.ndarray, filters: np.ndarray) -> np.ndarray: - """Apply convolution operation.""" - batch, height, width = x.shape + def convolve(self, input_tensor: np.ndarray, filters: np.ndarray) -> np.ndarray: + """Apply convolution operation to the input tensor.""" + _, height, width = input_tensor.shape num_filters, _, fh, fw = filters.shape output = np.zeros((num_filters, height - fh + 1, width - fw + 1)) for f in range(num_filters): for i in range(height - fh + 1): for j in range(width - fw + 1): - region = x[:, i:i + fh, j:j + fw] + region = input_tensor[:, i:i + fh, j:j + fw] output[f, i, j] = np.sum(region * filters[f]) return output - def flatten(self, x: np.ndarray) -> np.ndarray: - """Flatten the feature map.""" - return x.reshape(-1) + def flatten(self, feature_map: np.ndarray) -> np.ndarray: + """Flatten the feature map into a 1D array.""" + return feature_map.reshape(-1) - def forward(self, x: np.ndarray) -> np.ndarray: + def forward(self, input_tensor: np.ndarray) -> np.ndarray: """ Forward pass through the CNN. Args: - x: Input image of shape (channels, height, width) + input_tensor: Input image of shape (channels, height, width) Returns: Output logits of shape (num_classes,) """ - conv_out = self.convolve(x, self.filters) + conv_out = self.convolve(input_tensor, self.filters) activated = self.relu(conv_out) flattened = self.flatten(activated) logits = flattened @ self.fc_weights - return logits \ No newline at end of file + return logits From 4aa4b2f30988ba89633e4126b7c01ebff8a6f5cf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 17:58:11 +0000 Subject: [PATCH 15/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- machine_learning/cnn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/machine_learning/cnn.py b/machine_learning/cnn.py index 9ae83b82954e..5e285236d8f4 100644 --- a/machine_learning/cnn.py +++ b/machine_learning/cnn.py @@ -42,7 +42,7 @@ def convolve(self, input_tensor: np.ndarray, filters: np.ndarray) -> np.ndarray: for f in range(num_filters): for i in range(height - fh + 1): for j in range(width - fw + 1): - region = input_tensor[:, i:i + fh, j:j + fw] + region = input_tensor[:, i : i + fh, j : j + fw] output[f, i, j] = np.sum(region * filters[f]) return output From 4caa33974a8f170324aedc305687ada849a0ba33 Mon Sep 17 00:00:00 2001 From: cclauss Date: Mon, 14 Sep 2026 05:10:37 +0000 Subject: [PATCH 16/16] updating DIRECTORY.md --- DIRECTORY.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 311a7c7c9de8..726a783ce8b0 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -688,6 +688,7 @@ * [Apriori Algorithm](machine_learning/apriori_algorithm.py) * [Astar](machine_learning/astar.py) * [Automatic Differentiation](machine_learning/automatic_differentiation.py) + * [Cnn](machine_learning/cnn.py) * [Data Transformations](machine_learning/data_transformations.py) * [Decision Tree](machine_learning/decision_tree.py) * [Dimensionality Reduction](machine_learning/dimensionality_reduction.py) @@ -712,14 +713,17 @@ * [Loss Functions](machine_learning/loss_functions.py) * Lstm * [Lstm Prediction](machine_learning/lstm/lstm_prediction.py) + * [Mean Shift](machine_learning/mean_shift.py) * [Mfcc](machine_learning/mfcc.py) * [Mini Batch Gradient Descent](machine_learning/mini_batch_gradient_descent.py) * [Multilayer Perceptron Classifier](machine_learning/multilayer_perceptron_classifier.py) + * [Naive Bayes Text Classification](machine_learning/naive_bayes_text_classification.py) * [Polynomial Regression](machine_learning/polynomial_regression.py) * [Principle Component Analysis](machine_learning/principle_component_analysis.py) * [Q Learning](machine_learning/q_learning.py) * [Random Forest Classifier](machine_learning/random_forest_classifier.py) * [Random Forest Regressor](machine_learning/random_forest_regressor.py) + * [Rmsprop](machine_learning/rmsprop.py) * [Scoring Functions](machine_learning/scoring_functions.py) * [Self Organizing Map](machine_learning/self_organizing_map.py) * [Sequential Minimum Optimization](machine_learning/sequential_minimum_optimization.py) @@ -736,6 +740,7 @@ * [Arc Length](maths/arc_length.py) * [Area](maths/area.py) * [Area Under Curve](maths/area_under_curve.py) + * [Autocorrelation](maths/autocorrelation.py) * [Average Absolute Deviation](maths/average_absolute_deviation.py) * [Average Mean](maths/average_mean.py) * [Average Median](maths/average_median.py) @@ -781,6 +786,7 @@ * [Fibonacci](maths/fibonacci.py) * [Find Max](maths/find_max.py) * [Find Min](maths/find_min.py) + * [First Fundamental Form](maths/first_fundamental_form.py) * [Floor](maths/floor.py) * [Gamma](maths/gamma.py) * [Gaussian](maths/gaussian.py) @@ -843,6 +849,7 @@ * [Square Root](maths/numerical_analysis/square_root.py) * [Weierstrass Method](maths/numerical_analysis/weierstrass_method.py) * [Odd Sieve](maths/odd_sieve.py) + * [Padovan Sequence](maths/padovan_sequence.py) * [Pell Number](maths/pell_number.py) * [Perfect Cube](maths/perfect_cube.py) * [Perfect Number](maths/perfect_number.py) @@ -872,6 +879,8 @@ * [Reverse Factorial Recursive](maths/reverse_factorial_recursive.py) * [Segmented Sieve](maths/segmented_sieve.py) * Series + * [Alternate Harmonic Series](maths/series/alternate_harmonic_series.py) + * [Alternating Harmonic Series](maths/series/alternating_harmonic_series.py) * [Arithmetic](maths/series/arithmetic.py) * [Geometric](maths/series/geometric.py) * [Geometric Series](maths/series/geometric_series.py) @@ -911,6 +920,7 @@ * [Polygonal Numbers](maths/special_numbers/polygonal_numbers.py) * [Pronic Number](maths/special_numbers/pronic_number.py) * [Proth Number](maths/special_numbers/proth_number.py) + * [Spy Number](maths/special_numbers/spy_number.py) * [Triangular Numbers](maths/special_numbers/triangular_numbers.py) * [Trimorphic Number](maths/special_numbers/trimorphic_number.py) * [Ugly Numbers](maths/special_numbers/ugly_numbers.py)