/// <summary> /// Constructor. Menghitung LSE dari persamaan regresi dalam matriks /// Y = X B + E /// </summary> /// <param name="X">Matrix. Matriks berisi data variabel independen X</param> /// <param name="Y">Vector. Vektor berisi data variabel dependen Y</param> public LeastSquareEstimator(Matrix X, Vector Y) { this.x = X; this.y = Y; int n = Y.Tuples; int p = X.Cols; Matrix xtx = x.GetTranspose() * x; Vector xty = x.GetTranspose() * y; b = xtx.Solve(xty); ycap = x * b; e = y - ycap; eSquare = e.GetDataSquare(); Matrix j = new Matrix(n, n); j.InitializeAllValue(1.0); double yty =Vector.DoubleMultiply(Y.GetTranspose(), Y); Vector jy = j * y; ssto = yty - Vector.DoubleMultiply(Y.GetTranspose(), jy) / n; sse = yty - Vector.DoubleMultiply(b.GetTranspose(), xty); ssr = ssto - sse; msr = ssr / (p - 1); mse = sse / (n - p); rSquare = ssr / ssto; r = Math.Sqrt(rSquare); sbSquare = mse * xtx.GetInverse(); }
/// <summary> /// Menghitung nilai indeks musiman /// </summary> /// <param name="y">Vector. data aktual</param> /// <param name="seasonalLength">Integer. panjang musiman</param> /// <param name="isMultiplicative">Boolean. tipe model yang digunakan</param> public SeasonalIndex(Vector y, int seasonalLength, bool isMultiplicative) { this.y = y; this.includedObservation = this.y.Tuples; this.seasonalLength = seasonalLength; this.isMultiplicative = isMultiplicative; sMov1 = new double[includedObservation]; sMov2 = new double[includedObservation]; median = new double[seasonalLength]; seasonal = new double[seasonalLength]; term = new double[this.includedObservation]; for (int i = 0; i < this.includedObservation; ) { for (int j = 0; j < this.seasonalLength; ++j) { if (i + j != this.includedObservation) term[i + j] = j; else break; } i += this.seasonalLength; } this.CalcSeasonalIndex(); }
/// <summary> /// Metode dekomposisi klasik dengan rasio pada rata-rata bergerak /// </summary> /// <param name="variable">SeriesVariable. variabel yang akan dianalisis</param> /// <param name="seasonalLength">Integer. panjang satu siklus musiman</param> /// <param name="isMultiplikatif">Bool. apakah menggunakan metode multiplikatif?</param> /// <param name="initialTrend">Integer. Inisial model tren yang digunakan, 1-Linear, 2-Quadratic, 3-Cubic, 4-Exponential</param> public DecompositionClassic(SeriesVariable variable, int seasonalLength, bool isMultiplicative, int initialTrend) { this.variable = variable; Vector var = new Vector(this.variable.SeriesValuesNoNaN.ToArray()); this.y = new Vector(var.Tuples); for (int i = 0; i < y.Tuples; i++) this.y[i] = var[i]; this.n = y.Tuples; this.seasonalLength = seasonalLength; this.trend = new double[this.n]; this.detrend = new double[this.n]; this.seasonal = new double[this.n]; this.deseasonal = new double[this.n]; this.predicted = new double[this.n]; this.residual = new double[this.n]; this.isMultiplicative = isMultiplicative; this.initialTrend = initialTrend; if (this.isMultiplicative) this.Multiplicative(); else this.Additive(); this.ForecastingError(); }
/// <summary> /// Constructor. Menghitung nilai keakuratan peramalan /// </summary> /// <param name="dataY">Vector. data actual</param> /// <param name="residual">ArrayDouble. residual</param> /// <param name="startIdx">Integer. data awal mulai penghitungan</param> /// <param name="endIdx">Integer. banyaknya jumlah observasi</param> public MeasuringForecastingError(Vector dataY, double[] residual, int startIdx, int endIdx) { this.y = dataY; this.e = residual; this.startIdx = startIdx; this.endIdx = endIdx; this.n = endIdx - startIdx; this.CalcSSE(); this.CalcMSE(); this.CalcMAE(); this.CalcMPE(); this.CalcMAPE(); }
/// <summary> /// Fungsi Virtual unutk mendapatkan turunan pertama pada fungsi /// </summary> /// <param name="input">Vector. Vector parameter yang dimasukkan</param> /// <returns>double. hasil penghitungan fungsi sesuai nilai masukkannya</returns> public virtual Vector Gradient(Vector input) { Vector result = new Vector(input.Tuples); Vector vh = new Vector(input.Tuples); double h = 0.000001; for (int i = 0; i < input.Tuples; i++) { vh.InitializeAllValue(0); vh[i] = h; result[i] = (this.Function(input + vh) - this.Function(input)) / h; } return result; }
/// <summary> /// Constructor. Pemulusan dengan metode Rata-Rata Bergerak Tunggal /// </summary> /// <param name="variable">SeriesVariable. variable</param> /// <param name="maLength">Integer. MA Length</param> public SingleMovingAverage(SeriesVariable variable, int maLength) { this.variable = variable; Vector var = new Vector(this.variable.SeriesValuesNoNaN.ToArray()); this.Y = new Vector(var.Tuples); for (int i = 0; i < Y.Tuples; i++) this.Y[i] = var[i]; this.n = Y.Tuples; this.t = maLength; this.smoothing1 = new double[this.n]; this.predicted = new double[this.n]; this.residual = new double[this.n]; this.Smoothing(); this.ForecastingError(); }
/// <summary> /// Constructor. Menghitung Pemulusan Eksponensial Tripel /// </summary> /// <param name="variable">SeriesVariable. variabel</param> /// <param name="alpha">Double. Smoothing constant for data</param> /// <param name="gamma">Double. Smoothing constant for trend</param> /// <param name="beta">Double. Smoothing constant for seasonal</param> /// <param name="seasonalLength">Integer. Panjang seasonal</param> public TripleExponentialSmoothingWinter(SeriesVariable variable, double alpha, double gamma, double beta, int seasonalLength, bool isMultiplicative) { this.variable = variable; Vector var = new Vector(this.variable.SeriesValuesNoNaN.ToArray()); this.y = new Vector(var.Tuples); for (int i = 0; i < y.Tuples; i++) this.y[i] = var[i]; this.n = this.y.Tuples; this.alpha = alpha; this.gamma = gamma; this.beta = beta; this.l = seasonalLength; this.isMultiplicative = isMultiplicative; this.smoothing = new double[this.n]; this.trend = new double[this.n]; this.seasonal = new double[this.n]; this.predicted= new double[this.n]; this.residual = new double[this.n]; //term term = new int[this.n]; for (int i = 0; i < this.n; ) { for (int j = 0; j < this.l; ++j) { if (i + j != this.n) term[i + j] = j; else break; } i += this.l; } if(this.isMultiplicative) SmoothingMultiplicative(); else SmoothingAdditive(); ForecastingError(); }
/// <summary> /// Constructor. Pemulusan Eksponensial Ganda dengan metode Holt /// </summary> /// <param name="variable">SeriesVariable. variabel</param> /// <param name="alpha">Double. Smoothing constanta for data</param> /// <param name="gamma">Double. Smoothing constanta for trend</param> public DoubleExponentialSmoothingHolt(SeriesVariable variable, double alpha, double gamma) { this.variable = variable; Vector var = new Vector(this.variable.SeriesValuesNoNaN.ToArray()); this.y = new Vector(var.Tuples); for (int i = 0; i < y.Tuples; i++) this.y[i] = var[i]; this.n = this.y.Tuples; this.a = alpha; this.g = gamma; this.smoothing = new double[this.n]; this.trend = new double[this.n]; this.predicted = new double[this.n]; this.residual = new double[this.n]; this.Smoothing(); this.ForecastingError(); }
/// <summary> /// Pemulusan dengan metode Rata-Rata Bergerak ganda /// </summary> /// <param name="variable">SeriesVariable. variabel yang akan dianalisis</param> /// <param name="maLength">Integer. MA Length</param> public DoubleMovingAverage(SeriesVariable variable, int maLength) { this.variable = variable; Vector var = new Vector(this.variable.SeriesValuesNoNaN.ToArray()); this.y = new Vector(var.Tuples); for (int i = 0; i < y.Tuples; i++) y[i] = var[i]; this.n = y.Tuples; this.t = maLength; this.smoothing1 = new double[n]; this.smoothing2 = new double[n]; this.at = new double[n]; this.bt = new double[n]; this.predicted = new double[n]; this.residual = new double[n]; Smoothing(); ForecastingError(); }
/// <summary> /// Mendapatkan vektor proyeksi antara Vektor X dan Vektor Y /// </summary> /// <param name="X">Vector. Vektor X</param> /// <param name="Y">Vector. Vektor Y</param> /// <returns>Vector. Vektor proyeksi</returns> public static Vector ProjectionXonY(Vector X, Vector Y) { Vector result; if (X.Type == VectorType.ColumnVector && Y.Type == VectorType.ColumnVector) { Vector XT = X.GetTranspose(); double proj = Vector.DoubleMultiply(XT, Y)/(Math.Pow(Y.Length,2)); result = proj * Y; } else { throw new WrongVectorTypeException("Only Column Vector valid"); } return result; }
/// <summary> /// Melakukan perkalian matriks terhadap dua vektor /// </summary> /// <param name="a">Vector. vektor pertama</param> /// <param name="b">Vector. vektor kedua</param> /// <returns>Matrix. hasil perkalian matriks dua vektor</returns> public static Matrix MatrixMultiply(Vector a, Vector b) { Matrix result = new Matrix(a.Tuples, b.Tuples); if (CanMatrixMultiply(a, b)) { for (int i = 0; i < a.Tuples; i++) for (int j = 0; j < b.Tuples; j++) result[i,j] = a[i] * b[j]; } else { throw new WrongVectorSizeOrTypeException("Vector can't be matrix Multiplied"); } return result; }
/// <summary> /// Mengecek apakah dua vektor bertipe sama /// </summary> /// <param name="a">Vector. vektor pertama</param> /// <param name="b">Vector. vektor kedua</param> /// <returns>Boolean. Apakah dua vektor bertipe sama?</returns> public static bool IsSameType(Vector a, Vector b) { return (a.Type == b.Type); }
/// <summary> /// Mengecek apakah dua vektor berukuran dan bertipe sama /// </summary> /// <param name="a">Vector. vektor pertama</param> /// <param name="b">Vector. vektor kedua</param> /// <returns>Boolean. Apakah dua vektor berukuran dan bertipe sama?</returns> public static bool IsSameSizeType(Vector a, Vector b) { return IsSameSize(a,b) && IsSameType(a,b) ; }
/// <summary> /// Operator overloading. Operasi perkalian skalar /// (perkalian vektor dengan konstanta) /// </summary> /// <param name="constant">Double. konstanta</param> /// <param name="a">Vector. vektor</param> /// <returns>Vector. vektor hasil perkalian skalar</returns> public static Vector operator *(double constant, Vector a) { Vector result = new Vector(a.Tuples, a.Type); for (int i = 0; i < a.Tuples; i++) result[i] = constant * a[i]; return result; }
/// <summary> /// Fungsi Abstrak yang akan digunkakan pada setiap kelas turunannya sesuai fungsi masing-masing /// </summary> /// <param name="input">Vector. Vektor parameter yang dimasukkan</param> /// <returns>double. hasil penghitungan fungsi sesuai nilai masukkannya</returns> public abstract double Function(Vector input);
/// <summary> /// Mendapatkan vektor transpose /// </summary> /// <returns>Vector. Vektor transpose</returns> /// <remarks>Vektor transpose didapat dengan mengganti tipe vektor /// dari baris menjadi kolom atau sebaliknya</remarks> public Vector GetTranspose() { VectorType newType; if (this.type == VectorType.ColumnVector) newType = VectorType.RowVector; else newType = VectorType.ColumnVector; Vector result = new Vector(this.tuples, newType); for (int i = 0; i < this.tuples; i++) result[i] = this.data[i]; return result; }
/// <summary> /// Mengecek apakah sebuah vektor dapat dikalikan dengan sebuah matriks /// </summary> /// <param name="a">Vector. Vektor</param> /// <param name="b">Matrix. Matriks</param> /// <returns>Boolean. apakah sebuah vektor dapat dikalikan /// dengan sebuah matriks?</returns> public static bool CanMultiply(Vector a, Matrix b) { return (a.Tuples == b.Rows) && (a.Type == VectorType.RowVector); }
/// <summary> /// Mendapatkan sudut (dalam radian) antara dua vektor /// </summary> /// <param name="a">Vector. Vektor pertama</param> /// <param name="b">Vector. Vektor kedua</param> /// <returns>Double. Sudut antara dua vektor dalam radian</returns> public static double Angle(Vector a, Vector b) { double result; if (a.Type == VectorType.ColumnVector && b.Type == VectorType.ColumnVector) { Vector aT = a.GetTranspose(); result = Vector.DoubleMultiply(aT, b); result /= a.Length * b.Length; result = Math.Acos(result); } else { throw new WrongVectorTypeException("Only Column Vector valid"); } return result; }
/// <summary> /// Mengecek apakah dua vektor dapat dilakukan perkalian matriks. /// Perkalian matriks adalah perkalian vektor kolom dengan vektor baris /// dimana menghasilkan sebuah matriks persegi. /// </summary> /// <param name="a">Vector. vektor pertama</param> /// <param name="b">Vector. vektor kedua</param> /// <returns>Boolean. apakah dua vektor dapat dilakukan perkalian matriks?</returns> public static bool CanMatrixMultiply(Vector a, Vector b) { return IsSameSize(a,b) && (a.Type == VectorType.ColumnVector) && (b.Type == VectorType.RowVector); }
/// <summary> /// Operator overloading. Operasi pengurangan vektor /// </summary> /// <param name="a">Vector. Vektor pertama</param> /// <param name="b">Vector. Vektor kedua</param> /// <returns>Vector. Vektor hasil pengurangan</returns> public static Vector operator -(Vector a, Vector b) { Vector result = new Vector(a.Tuples, a.Type); if (IsSameSizeType(a, b)) { for (int i = 0; i < a.Tuples; i++) result[i] = a[i] - b[i]; } else { throw new NotSameSizeVectorException(); } return result; }
/// <summary> /// Operator overloading. Operasi perkalian vektor dengan matriks /// </summary> /// <param name="a">Vector. Vektor</param> /// <param name="b">Matrix. Matriks</param> /// <returns>Vector. vektor hasil perkalian vektor dengan matriks. /// Berupa vektor baris</returns> public static Vector operator *(Vector a, Matrix b) { Vector result = new Vector(b.Cols, VectorType.RowVector); if (CanMultiply(a, b)) { for (int i = 0; i < b.Cols; i++) { result[i] = 0.0; for (int j = 0; j < b.Rows; j++) { result[i] += a[j] * b[j, i]; } } } else { throw new WrongVectorSizeOrTypeException("Can't be multiplied"); } return result; }
/// <summary> /// Operator overloading. Operasi perkalian matriks dengan vektor /// </summary> /// <param name="a">Matrix. Matriks</param> /// <param name="b">Vector. Vektor</param> /// <returns>Vector. vektor hasil perkalian matriks dengan vektor. /// Berupa vektor kolom</returns> public static Vector operator *(Matrix a, Vector b) { Vector result = new Vector(a.Rows,VectorType.ColumnVector); if (CanMultiply(a, b)) { for (int i = 0; i < a.Rows; i++) { result[i] = 0.0; for (int j = 0; j < a.Cols; j++) { result[i] += a[i, j] * b[j]; } } } else { throw new WrongVectorSizeOrTypeException("Can't be multiplied"); } return result; }
/// <summary> /// Mendapatkan copy dari vektor /// </summary> /// <returns>Vector. Copy dari vektor</returns> public Vector Copy() { Vector result = new Vector(this.tuples, this.type); for (int i = 0; i < this.tuples; i++) result[i] = this.data[i]; return result; }
/// <summary> /// Melakukan perkalian double terhadap dua vektor /// </summary> /// <param name="a">Vector. vektor pertama</param> /// <param name="b">Vector. vektor kedua</param> /// <returns>Double. hasil perkalian double dua vektor</returns> public static double DoubleMultiply(Vector a, Vector b) { double result=0.0; if (CanDoubleMultiply(a, b)) { for (int i = 0; i < a.Tuples; i++) result += a[i] * b[i]; } else { throw new WrongVectorSizeOrTypeException("Vector can't be double Multiplied"); } return result; }
/// <summary> /// Mendapatkan vector data kuadrat vektor /// </summary> /// <returns>Vector. Vector data kuadrat</returns> public Vector GetDataSquare() { Vector result = new Vector(this.tuples); for (int i = 0; i < this.tuples; i++) { result[i] = this.data[i] * this.data[i]; ; } return result; }
/// <summary> /// Mengecek apakah dua buah vektor perpendicular. /// Dua buah vektor perpendicular jika hasil perkalian doublenya 0 /// </summary> /// <param name="a">Vector. Vektor pertama</param> /// <param name="b">Vector. Vektor kedua</param> /// <returns>Boolean. Apakah dua buah vektor perpendicular?</returns> public static bool IsPerpendicular(Vector a, Vector b) { bool result; if (a.Type == VectorType.ColumnVector && b.Type == VectorType.ColumnVector) { Vector aT = a.GetTranspose(); result = Vector.DoubleMultiply(aT, b) == 0.0; } else { throw new WrongVectorTypeException("Only Column Vector valid"); } return result; }
//r = Cov(x,y)/(StandardDeviation(x)*StandardDeviation(y)) private double computePearsonCorr(Vector x, Vector y) { int n = x.Tuples; Vector xy = new Vector(n); for (int i = 0; i < n; i++) xy[i] = x[i] * y[i]; double sumxy = xy.GetSumData(); double xbar = x.GetSumData() / (double)n; double ybar = y.GetSumData() / (double)n; double covxy = (sumxy - n * xbar * ybar) / (double)(n - 1); Vector x2 = x.GetDataSquare(); Vector y2 = y.GetDataSquare(); double varx = (n * x2.GetSumData() - Math.Pow(x.GetSumData(), 2.0)) / (double)(n * (n - 1)); double vary = (n * y2.GetSumData() - Math.Pow(y.GetSumData(), 2.0)) / (double)(n * (n - 1)); return covxy / Math.Sqrt(varx * vary); }
/// <summary> /// Mengecek apakah dua vektor berukuran sama /// </summary> /// <param name="a">Vector. vektor pertama</param> /// <param name="b">Vector. vektor kedua</param> /// <returns>Boolean. Apakah dua vektor berukuran sama?</returns> public static bool IsSameSize(Vector a, Vector b) { return (a.Tuples == b.Tuples); }
/// <summary> /// Mengecek apakah sebuah matriks dapat dikalikan dengan sebuah vektor /// </summary> /// <param name="a">Matrix. Matriks</param> /// <param name="b">Vector. Vektor</param> /// <returns>Boolean. apakah sebuah matriks dapat dikalikan /// dengan sebuah vektor?</returns> public static bool CanMultiply(Matrix a, Vector b) { return (a.Cols == b.Tuples) && (b.Type == VectorType.ColumnVector); }
/// <summary> /// Linear regression with Y and one or more independent variables /// equation: y = b0 + b1x1 + b2x2 + ... + b(p-1)x(p-1) + e /// equation in matrix form: Y = XB + E /// </summary> /// <param name="dependent">SeriesVariable. dependent variable</param> /// <param name="independents">SeriesVariables. independent variable</param> public LinearRegressionModel(SeriesVariable dependent, SeriesVariables independents) { //Vector vY = new Vector(dependent.SeriesValuesNoNaN.ToArray()); //int n = vY.Tuples; //int p = independents.Count + 1; //Matrix mX = new Matrix(n, p); //for (int i = 0; i < p; i++) //kolom //{ // for (int j = 0; j < n; j++) //baris // { // if (i == 0) // mX[j, i] = 1.0; // else // mX[j, i] = independents[i - 1][j]; // } //} // changed to deal with missing values Vector vY = new Vector(dependent.SeriesValuesNoNaN.ToArray()); int n = vY.Tuples; int p = independents.Count + 1; Matrix mX = new Matrix(n, p); for (int i = 0; i < p; i++) //kolom { for (int j = 0; j < n; j++) //baris { if (i == 0) mX[j, i] = 1.0; else mX[j, i] = independents[i - 1].SeriesValuesNoNaN[j]; } } this.lse = new LeastSquareEstimator(mX, vY); this.f = this.lse.MSR / this.lse.MSE; this.sigOfF = Distribution.F.PValue(this.f, p - 1, n - p); double sumOfEtMinusEt_1Square = 0; double sumOfESquare = this.lse.ESquare[0]; for (int i = 1; i < n; i++) { sumOfEtMinusEt_1Square += Math.Pow(this.lse.E[i] - this.lse.E[i - 1],2.0); sumOfESquare += this.lse.ESquare[i]; } this.durbinWatson = sumOfEtMinusEt_1Square / sumOfESquare; this.stdErrorOfParameters = new double[p]; this.t = new double[p]; this.sigOfT = new double[p]; this.lbOfParameters = new double[p]; this.ubOfParameters = new double[p]; for (int i = 0; i < p; i++) { this.stdErrorOfParameters[i] = Math.Sqrt(this.lse.SbSquare[i, i]); this.t[i] = this.lse.B[i] / this.stdErrorOfParameters[i]; this.sigOfT[i] = Distribution.T.PValue(this.t[i], n - p, Distribution.T.TestType.TwoSided); double error = Distribution.T.InversCDF(0.975, n - p); this.ubOfParameters[i] = this.lse.B[i] + error * this.stdErrorOfParameters[i]; this.lbOfParameters[i] = this.lse.B[i] - error * this.stdErrorOfParameters[i]; } this.vifForPredictors = new double[p - 1]; this.partialCorr = new double[p - 1]; this.corr = new double[p - 1]; for (int i = 1; i < p; i++) { Vector y = new Vector(mX.GetColData(i)); Matrix x = new Matrix(n, p - 1); int col = 0; for (int j = 0; j < p; j++) { if (j != i) { for (int k = 0; k < n; k++) { x[k, col] = mX[k, j]; } col++; } } Matrix xtx = x.GetTranspose() * x; Vector xty = x.GetTranspose() * y; Vector b = xtx.Solve(xty); Matrix mJ = new Matrix(n, n); mJ.InitializeAllValue(1.0); double yty = Vector.DoubleMultiply(y.GetTranspose(), y); Vector jy = mJ * y; double ssto = yty - Vector.DoubleMultiply(y.GetTranspose(), jy) / n; double sse = yty - Vector.DoubleMultiply(b.GetTranspose(), xty); double ssr = ssto - sse; double rSquare = ssr / ssto; this.vifForPredictors[i - 1] = 1 / (1 - rSquare); this.corr[i - 1] = computePearsonCorr(vY,y); Vector xty2 = x.GetTranspose() * vY; Vector b2 = xtx.Solve(xty2); double yty2 = Vector.DoubleMultiply(vY.GetTranspose(), vY); double sse2 = yty2 - Vector.DoubleMultiply(b2.GetTranspose(), xty2); double partDetermination = (sse2 - this.lse.SSE) / sse2; this.partialCorr[i - 1] = Math.Sqrt(partDetermination); } this.expectedResidual = new double[n]; for (int k = 1; k <= n; k++) { this.expectedResidual[k - 1] = this.lse.StandardError * Distribution.Normal.InversCDF((k - 0.375) / (n + 0.25)); } }