|
| 1 | +class PolynomialRegression { |
| 2 | + public static tolerance = 1e-10; |
| 3 | + |
| 4 | + /** |
| 5 | + * Tính chuyển vị của ma trận |
| 6 | + * @param matrix Ma trận cần chuyển vị |
| 7 | + * @returns Ma trận chuyển vị |
| 8 | + */ |
| 9 | + private static transpose(matrix: number[][]): number[][] { |
| 10 | + // Khởi tạo ma trận chuyển vị với kích thước phù hợp |
| 11 | + const transposed: number[][] = []; |
| 12 | + for (let i = 0; i < matrix[0].length; i++) { |
| 13 | + transposed.push([]); |
| 14 | + } |
| 15 | + |
| 16 | + // Điền giá trị vào ma trận chuyển vị |
| 17 | + for (let i = 0; i < matrix.length; i++) { |
| 18 | + for (let j = 0; j < matrix[i].length; j++) { |
| 19 | + transposed[j][i] = matrix[i][j]; |
| 20 | + } |
| 21 | + } |
| 22 | + |
| 23 | + return transposed; |
| 24 | + } |
| 25 | + |
| 26 | + /** |
| 27 | + * Nhân hai ma trận lại với nhau |
| 28 | + * @param a Ma trận thứ nhất |
| 29 | + * @param b Ma trận thứ hai |
| 30 | + * @returns Kết quả của việc nhân hai ma trận lại với nhau |
| 31 | + */ |
| 32 | + private static multiplyMatrices(a: number[][], b: number[][]): number[][] { |
| 33 | + // Khởi tạo ma trận kết quả với kích thước phù hợp |
| 34 | + const result: number[][] = []; |
| 35 | + for (let i = 0; i < a.length; i++) { |
| 36 | + result.push([]); |
| 37 | + for (let j = 0; j < b[0].length; j++) { |
| 38 | + result[i].push(0); |
| 39 | + } |
| 40 | + } |
| 41 | + |
| 42 | + // Tính toán giá trị của ma trận kết quả |
| 43 | + for (let i = 0; i < a.length; i++) { |
| 44 | + for (let j = 0; j < b[0].length; j++) { |
| 45 | + for (let k = 0; k < a[0].length; k++) { |
| 46 | + result[i][j] += a[i][k] * b[k][j]; |
| 47 | + } |
| 48 | + } |
| 49 | + } |
| 50 | + |
| 51 | + return result; |
| 52 | + } |
| 53 | + |
| 54 | + /** |
| 55 | + * Tính nghịch đảo của ma trận vuông sử dụng phép loại Gauss |
| 56 | + * @param matrix Ma trận vuông cần tính nghịch đảo |
| 57 | + * @returns Nghịch đảo của ma trận đã cho |
| 58 | + */ |
| 59 | + private static invertMatrix(matrix: number[][]): number[][] { |
| 60 | + // Khởi tạo ma trận mở rộng với ma trận đã cho và một ma trận đơn vị cùng kích thước |
| 61 | + const augmented: number[][] = []; |
| 62 | + for (let i = 0; i < matrix.length; i++) { |
| 63 | + augmented.push([...matrix[i]]); |
| 64 | + for (let j = 0; j < matrix.length; j++) { |
| 65 | + augmented[i].push(i === j ? 1 : 0); |
| 66 | + } |
| 67 | + } |
| 68 | + |
| 69 | + // Thực hiện phép loại Gauss trên ma trận mở rộng để chuyển đổi nó thành dạng hàng bậc thang rút gọn |
| 70 | + for (let i = 0; i < augmented.length; i++) { |
| 71 | + // Tìm phần tử chốt và hoán đổi hàng nếu cần thiết |
| 72 | + let pivotRow = i; |
| 73 | + for (let j = i + 1; j < augmented.length; j++) { |
| 74 | + if (Math.abs(augmented[j][i]) > Math.abs(augmented[pivotRow][i])) { |
| 75 | + pivotRow = j; |
| 76 | + } |
| 77 | + } |
| 78 | + [augmented[pivotRow], augmented[i]] = [augmented[i], augmented[pivotRow]]; |
| 79 | + |
| 80 | + // Chia hàng chốt cho phần tử chốt để làm cho nó bằng một |
| 81 | + const pivotElement = augmented[i][i]; |
| 82 | + for (let j = i; j < augmented[i].length; j++) { |
| 83 | + augmented[i][j] /= pivotElement; |
| 84 | + } |
| 85 | + |
| 86 | + // Trừ bội số của hàng chốt từ tất cả các hàng khác để làm cho tất cả các phần tử khác trong cột hiện tại bằng không |
| 87 | + for (let j = 0; j < augmented.length; j++) { |
| 88 | + if (j !== i) { |
| 89 | + const factor = augmented[j][i]; |
| 90 | + for (let k = i; k < augmented[j].length; k++) { |
| 91 | + augmented[j][k] -= factor * augmented[i][k]; |
| 92 | + } |
| 93 | + } |
| 94 | + } |
| 95 | + } |
| 96 | + |
| 97 | + // Trích xuất ma trận nghịch đảo từ nửa bên phải của ma trận mở rộng |
| 98 | + const inverse: number[][] = []; |
| 99 | + for (let i = 0; i < augmented.length; i++) { |
| 100 | + inverse.push(augmented[i].slice(augmented.length)); |
| 101 | + } |
| 102 | + |
| 103 | + return inverse; |
| 104 | + } |
| 105 | + |
| 106 | + /** |
| 107 | + * Khớp một phương trình đa thức với một tập hợp các điểm dữ liệu bằng cách sử dụng hồi quy đa thức |
| 108 | + * @param xValues Các giá trị x của các điểm dữ liệu |
| 109 | + * @param yValues Các giá trị y của các điểm dữ liệu |
| 110 | + * @param order Bậc của đa thức để khớp |
| 111 | + * @returns Một mảng chứa các hệ số của đa thức được khớp theo thứ tự tăng dần của bậc |
| 112 | + */ |
| 113 | + public static async polynomialRegression( |
| 114 | + xValues: number[], |
| 115 | + yValues: number[], |
| 116 | + order: number |
| 117 | + ): Promise<number[]> { |
| 118 | + return new Promise((resolve) => { |
| 119 | + // Khởi tạo ma trận thiết kế với kích thước phù hợp |
| 120 | + const designMatrix: number[][] = []; |
| 121 | + for (let i = 0; i < xValues.length; i++) { |
| 122 | + designMatrix.push([]); |
| 123 | + for (let j = 0; j <= order; j++) { |
| 124 | + designMatrix[i].push(Math.pow(xValues[i], j)); |
| 125 | + } |
| 126 | + } |
| 127 | + |
| 128 | + // Tính chuyển vị của ma trận thiết kế |
| 129 | + const designMatrixTransposed = |
| 130 | + PolynomialRegression.transpose(designMatrix); |
| 131 | + |
| 132 | + // Tính tích của chuyển vị của ma trận thiết kế và ma trận thiết kế |
| 133 | + const designMatrixProduct = PolynomialRegression.multiplyMatrices( |
| 134 | + designMatrixTransposed, |
| 135 | + designMatrix |
| 136 | + ); |
| 137 | + |
| 138 | + // Đảo ngược tích của chuyển vị của ma trận thiết kế và ma trận thiết kế |
| 139 | + const designMatrixProductInverse = |
| 140 | + PolynomialRegression.invertMatrix(designMatrixProduct); |
| 141 | + |
| 142 | + // Định dạng lại các giá trị y thành một ma trận cột |
| 143 | + const yValuesColumnMatrix: number[][] = []; |
| 144 | + for (let i = 0; i < yValues.length; i++) { |
| 145 | + yValuesColumnMatrix.push([yValues[i]]); |
| 146 | + } |
| 147 | + |
| 148 | + // Tính tích của chuyển vị của ma trận thiết kế và ma trận cột giá trị y |
| 149 | + const designMatrixYValuesProduct = PolynomialRegression.multiplyMatrices( |
| 150 | + designMatrixTransposed, |
| 151 | + yValuesColumnMatrix |
| 152 | + ); |
| 153 | + |
| 154 | + // Tính các hệ số của đa thức được khớp bằng cách nhân nghịch đảo của tích của chuyển vị của ma trận thiết kế và ma trận thiết kế với tích của chuyển vị của ma trận thiết kế và ma trận cột giá trị y |
| 155 | + const coefficientsColumnMatrix = PolynomialRegression.multiplyMatrices( |
| 156 | + designMatrixProductInverse, |
| 157 | + designMatrixYValuesProduct |
| 158 | + ); |
| 159 | + |
| 160 | + // Định dạng lại ma trận cột hệ số thành một mảng |
| 161 | + const coefficients: number[] = []; |
| 162 | + for (let i = 0; i < coefficientsColumnMatrix.length; i++) { |
| 163 | + coefficients.push(coefficientsColumnMatrix[i][0]); |
| 164 | + } |
| 165 | + |
| 166 | + resolve(coefficients); |
| 167 | + }); |
| 168 | + } |
| 169 | +} |
| 170 | + |
| 171 | +// Kiểm tra |
| 172 | +(async () => { |
| 173 | + const xValues = [1, 2, 3]; |
| 174 | + const yValues = [1, 4, 9]; |
| 175 | + const order = 2; |
| 176 | + const coefficients = await PolynomialRegression.polynomialRegression( |
| 177 | + xValues, |
| 178 | + yValues, |
| 179 | + order |
| 180 | + ); |
| 181 | + |
| 182 | + // Kết quả của hồi quy đa thức |
| 183 | + console.log(coefficients); |
| 184 | + |
| 185 | + // So sánh các hệ số được tính toán với các hệ số mong đợi bằng cách sử dụng giá trị dung sai |
| 186 | + const expectedCoefficients = [0, 0, 1]; |
| 187 | + for (let i = 0; i < coefficients.length; i++) { |
| 188 | + if ( |
| 189 | + Math.abs(coefficients[i] - expectedCoefficients[i]) < |
| 190 | + PolynomialRegression.tolerance |
| 191 | + ) { |
| 192 | + console.log(`Hệ số ${i} gần đúng với giá trị mong đợi`); |
| 193 | + } else { |
| 194 | + console.log(`Hệ số ${i} không đúng với giá trị mong đợi`); |
| 195 | + } |
| 196 | + } |
| 197 | +})(); |
0 commit comments