diff --git a/DIRECTORY.md b/DIRECTORY.md index 311a7c7c9de8..53e6e0ece8ec 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -686,6 +686,7 @@ ## [Machine Learning](machine_learning) * [Apriori Algorithm](machine_learning/apriori_algorithm.py) + * [Arima](machine_learning/arima.py) * [Astar](machine_learning/astar.py) * [Automatic Differentiation](machine_learning/automatic_differentiation.py) * [Data Transformations](machine_learning/data_transformations.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) diff --git a/machine_learning/arima.py b/machine_learning/arima.py new file mode 100644 index 000000000000..907406904c89 --- /dev/null +++ b/machine_learning/arima.py @@ -0,0 +1,96 @@ +""" +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 :])