├── .gitignore ├── .travis.yml ├── package.json ├── src ├── data.csv └── index.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - stable 5 | 6 | install: 7 | - npm install 8 | 9 | script: 10 | - npm test -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "multivariate-linear-regression-gradient-descent-javascript", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "nodemon src/index.js --exec babel-node --presets es2015,stage-2", 8 | "test": "echo \"No test specified\" && exit 0" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "babel-cli": "^6.24.1", 15 | "babel-preset-es2015": "^6.24.1", 16 | "babel-preset-stage-2": "^6.24.1", 17 | "nodemon": "^1.11.0" 18 | }, 19 | "dependencies": { 20 | "csv-to-array-matrix": "^0.1.1", 21 | "mathjs": "^3.16.5", 22 | "mathjs-util": "^0.1.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/data.csv: -------------------------------------------------------------------------------- 1 | 2104;3;399900 2 | 1600;3;329900 3 | 2400;3;369000 4 | 1416;2;232000 5 | 3000;4;539900 6 | 1985;4;299900 7 | 1534;3;314900 8 | 1427;3;198999 9 | 1380;3;212000 10 | 1494;3;242500 11 | 1940;4;239999 12 | 2000;3;347000 13 | 1890;3;329999 14 | 4478;5;699900 15 | 1268;3;259900 16 | 2300;4;449900 17 | 1320;2;299900 18 | 1236;3;199900 19 | 2609;4;499998 20 | 3031;4;599000 21 | 1767;3;252900 22 | 1888;2;255000 23 | 1604;3;242900 24 | 1962;4;259900 25 | 3890;3;573900 26 | 1100;3;249900 27 | 1458;3;464500 28 | 2526;3;469000 29 | 2200;3;475000 30 | 2637;3;299900 31 | 1839;2;349900 32 | 1000;1;169900 33 | 2040;4;314900 34 | 3137;3;579900 35 | 1811;4;285900 36 | 1437;3;249900 37 | 1239;3;229900 38 | 2132;4;345000 39 | 4215;4;549000 40 | 2162;4;287000 41 | 1664;2;368500 42 | 2238;3;329900 43 | 2567;4;314000 44 | 1200;3;299000 45 | 852;2;179900 46 | 1852;4;299900 47 | 1203;3;239500 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Multivariate Linear Regression with Gradient Descent 2 | 3 | [![Build Status](https://travis-ci.org/javascript-machine-learning/multivariate-linear-regression-gradient-descent-javascript.svg?branch=master)](https://travis-ci.org/javascript-machine-learning/multivariate-linear-regression-gradient-descent-javascript) 4 | 5 | This example project demonstrates how the [gradient descent](http://en.wikipedia.org/wiki/Gradient_descent) algorithm may be used to solve a [multivariate linear regression](http://en.wikipedia.org/wiki/Linear_regression) problem. 6 | 7 | [Read more about it here.](https://www.robinwieruch.de/multivariate-linear-regression-gradient-descent-javascript/) 8 | 9 | ## Installation 10 | 11 | * `git clone git@github.com:javascript-machine-learning/multivariate-linear-regression-gradient-descent-javascript.git` 12 | * `cd multivariate-linear-regression-gradient-descent-javascript` 13 | * `npm install` 14 | * `npm start` 15 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import math from 'mathjs'; 2 | import csvToMatrix from 'csv-to-array-matrix'; 3 | 4 | import { 5 | getMeanAsRowVector, 6 | getStdAsRowVector, 7 | } from 'mathjs-util'; 8 | 9 | csvToMatrix('./src/data.csv', init); 10 | 11 | function init(matrix) { 12 | 13 | // Part 0: Preparation 14 | console.log('Part 0: Preparation ...\n'); 15 | 16 | let X = math.eval('matrix[:, 1:2]', { 17 | matrix, 18 | }); 19 | let y = math.eval('matrix[:, 3]', { 20 | matrix, 21 | }); 22 | 23 | let m = y.length; 24 | 25 | // Part 1: Feature Normalization 26 | console.log('Part 1: Feature Normalization ...\n'); 27 | 28 | let { XNorm, mu, sigma } = featureNormalize(X); 29 | 30 | console.log('X normalized: ', XNorm); 31 | console.log('\n'); 32 | console.log('mean: ', mu); 33 | console.log('\n'); 34 | console.log('std: ', sigma); 35 | console.log('\n'); 36 | 37 | // Part 2: Gradient Descent 38 | console.log('Part 2: Gradient Descent ...\n'); 39 | 40 | // Add Intercept Term 41 | XNorm = X = math.concat(math.ones([m, 1]).valueOf(), XNorm); 42 | 43 | const ALPHA = 0.01; 44 | const ITERATIONS = 400; 45 | 46 | let theta = [[0], [0], [0]]; 47 | theta = gradientDescentMulti(XNorm, y, theta, ALPHA, ITERATIONS); 48 | 49 | console.log('theta: ', theta); 50 | console.log('\n'); 51 | 52 | // Part 3: Predict Price of 1650 square meter and 3 bedroom house 53 | console.log('Part 3: Price Prediction ...\n'); 54 | 55 | let normalizedHouseVector = [1, ((1650 - mu[0]) / sigma[0]), ((3 - mu[1]) / sigma[1])]; 56 | let price = math.eval('normalizedHouseVector * theta', { 57 | normalizedHouseVector, 58 | theta, 59 | }); 60 | 61 | console.log('Predicted price for a 1650 square meter and 3 bedroom house: ', price); 62 | } 63 | 64 | function featureNormalize(X) { 65 | const mu = getMeanAsRowVector(X); 66 | const sigma = getStdAsRowVector(X); // alternative: range 67 | 68 | // n = features 69 | const n = X[0].length; 70 | for (let i = 0; i < n; i++) { 71 | 72 | let featureVector = math.eval(`X[:, ${i + 1}]`, { 73 | X, 74 | }); 75 | 76 | let featureMeanVector = math.eval('featureVector - mu', { 77 | featureVector, 78 | mu: mu[i] 79 | }); 80 | 81 | let normalizedVector = math.eval('featureMeanVector / sigma', { 82 | featureMeanVector, 83 | sigma: sigma[i], 84 | }); 85 | 86 | math.eval(`X[:, ${i + 1}] = normalizedVector`, { 87 | X, 88 | normalizedVector, 89 | }); 90 | } 91 | 92 | return { XNorm: X, mu, sigma }; 93 | } 94 | 95 | function gradientDescentMulti(X, y, theta, ALPHA, ITERATIONS) { 96 | const m = y.length; 97 | 98 | for (let i = 0; i < ITERATIONS; i++) { 99 | theta = math.eval(`theta - ALPHA / m * ((X * theta - y)' * X)'`, { 100 | theta, 101 | ALPHA, 102 | m, 103 | X, 104 | y, 105 | }); 106 | } 107 | 108 | return theta; 109 | } --------------------------------------------------------------------------------