Linear regression - simple

node v18.11.0
version: 2.0.0
endpointsharetweet
Medium article: https://medium.com/@waywardverities/linear-regression-in-javascript-an-inefficient-guide-225d95e88e67
// input data const X = [[2, 14], [5, 12], [7, 16], [11, 18], [15, 22]] const y = [55000, 60000, 75000, 90000, 120000] const extraLogging = true
// Helper functions function transpose(matrix) { const result = [] for (let i = 0; i < matrix[0].length; i++) { result[i] = [] for (let j = 0; j < matrix.length; j++) { result[i][j] = matrix[j][i] } } return result } function matrixMultiplication(X, Xt) { const exampleShape = new Array(X[0].length).fill(0).map(() => new Array(X[0].length).fill(0)) // console.log(exampleShape) // In our example this will become a 3x3 matrix let outputMatrix = [] for (XRow=0; XRow<X[0].length; XRow++) { outputMatrix.push([]) for (XtRow=0; XtRow<X[0].length; XtRow++) { // Multiply full rows with full columns let sum = 0 for (k=0; k<X.length; k++) { sum += X[k][XRow] * X[k][XtRow] } outputMatrix[XRow].push(sum) } } return outputMatrix } function matrixMultiplication2(matrixA, matrixB) { let result = [] // Get the number of rows and columns for each matrix let rowsA = matrixA.length let colsA = matrixA[0].length let rowsB = matrixB.length let colsB = matrixB[0].length // Check if the matrices can be multiplied if (colsA !== rowsB) { throw new Error("Cannot multiply matrices: Invalid dimensions") } // Create a new matrix filled with zeros for (let i = 0; i < rowsA; i++) { result[i] = [] for (let j = 0; j < colsB; j++) { result[i][j] = 0 } } // Multiply the matrices for (let i = 0; i < rowsA; i++) { for (let j = 0; j < colsB; j++) { for (let k = 0; k < colsA; k++) { result[i][j] += matrixA[i][k] * matrixB[k][j] } } } return result } function matrix_inverse(matrix) { // Calculate the determinant of the matrix const a = matrix[0][0], b = matrix[0][1], c = matrix[0][2], d = matrix[1][0], e = matrix[1][1], f = matrix[1][2], g = matrix[2][0], h = matrix[2][1], i = matrix[2][2] const det = a*e*i + b*f*g + c*d*h - c*e*g - b*d*i - a*f*h if (extraLogging) console.log(`det ${det}`) // Check if the matrix is invertible if (det === 0) { throw new Error("Matrix is not invertible"); } // Calculate the inverse of the matrix const inv_det = 1 / det if (extraLogging) console.log(`inv_det ${inv_det}`) const inv_matrix = [ [(e*i - f*h) * inv_det, (c*h - b*i) * inv_det, (b*f - c*e) * inv_det], [(f*g - d*i) * inv_det, (a*i - c*g) * inv_det, (c*d - a*f) * inv_det], [(d*h - e*g) * inv_det, (g*b - a*h) * inv_det, (a*e - b*d) * inv_det] ]; return inv_matrix; }
function manual_linear_regression(X, y) { if (extraLogging) console.log(`y: ${y}`) const XWithOnes = X.map(([first, second]) => [1, first, second]) if (extraLogging) console.log(`XWithOnes: ${XWithOnes}`) // Transpose const transposedXt = transpose(XWithOnes) if (extraLogging) console.log(`transposedXt: ${transposedXt}`) // Multiply the XWithOnes matrix with the transposed matrix const multipliedXtX = matrixMultiplication2(transposedXt, XWithOnes) if (extraLogging) console.log(`multipliedXtX: ${multipliedXtX}`) // Create the inverse matrix const inverseXtX = matrix_inverse(multipliedXtX) if (extraLogging) console.log(`Inverse matrix inverseXtX: ${inverseXtX}`) // A couple more matrix multiplications const XtX_inv_Xt = matrixMultiplication2(inverseXtX, transposedXt) if (extraLogging) console.log(`Xt multiplied inverse matrix - XtX_inv_Xt: ${XtX_inv_Xt}`) const yMap = y.map(nr => [nr]) const beta = matrixMultiplication2(XtX_inv_Xt, yMap) if (extraLogging) console.log(`beta: ${beta}`) return beta } const beta = manual_linear_regression(X, y)
// predict const x_predict = [8, 15] const y_predicted = beta[0][0] + beta[1][0] * x_predict[0] + beta[2][0] * x_predict[1] // = 76027
Loading…

no comments

    sign in to comment