zenxv

Linear Regression

Oct 4th, 2018
452
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // This may or may not help you understand what's going
  2. // on in week one of the Stanford Machine Learning course
  3. // particulary if you're coming from Javascript programming.
  4.  
  5. // The lecture deals with linear regression. You may remember
  6. // a concept called "line of best fit" from middle school.
  7. // A refresher: you have a set of points with x and y co-ordinates
  8. // and you have to draw a straight line through them. It doesn't
  9. // have to intersect all (or any) of the points, but it does need
  10. // to represent the general layout of your dataset. The idea is
  11. // that this will let you make guesses for the y position of a
  12. // new point when you only know the x or vice versa. It often
  13. // won't be 100% accurate, but it'll give you a good idea, and a
  14. // good understanding of the range of possible error it could have
  15. // made.
  16.  
  17. // A linear regression algorithm is just a way to make a computer
  18. // figure out what the line of best fit for a given dataset is.
  19. // The linear regression algorithm I describe below comes from
  20. // the Stanford Machine Learning course on Coursera. I found it
  21. // to be a bit too mathsy, so I'm writing it out in code, which
  22. // may help some people understand.
  23.  
  24. // Linear regression algorithms return a function that takes an
  25. // x and returns a guess for the corresponding y value, based on
  26. // the *specific* dataset you trained against. This function is
  27. // called a "model". There are many other kinds of models for
  28. // various other kinds of machine learning algorithms, but because
  29. // we're focusing on linear regression, this model will be the
  30. // function of a line. You may remember this as `y=mx+c` where
  31. // `m` is the slope of the line, and c is the horizontal offset of
  32. // the line, which you can think about as 'the value of the equation
  33. // when x is 0'. In the course, this is written as hθ1=θ1+θ2*x.
  34.  
  35. (()=>{
  36.  
  37. // You'll need to make lots of linear functions, so
  38. // lets make that easy.
  39. function prepareLinearFunction (theta1, theta2) {
  40. return x => theta1 + theta2 * x;
  41. }
  42.  
  43. // We're assuming in this example that your dataset contains
  44. // two columns, and therefore we have two thetas. You could
  45. // generalise the above function to take more columns into
  46. // account, but for now, lets focus on just two columns.
  47.  
  48. // Lets define a dataset to learn from. It is possible to
  49. // accurately model this dataset with a line, so we should
  50. // end up without any errors.
  51. const dataset = [
  52. [0,1],
  53. [1,3],
  54. [2,5],
  55. [3,7]
  56. ];
  57. // You'll notice that the 0th element of each inner array is
  58. // the index of that element. I could just use the index,
  59. // but I wanted to make it more obvious.
  60.  
  61. // Next you'll need a "cost function", which is just a
  62. // fancy name for a function that measures how well a
  63. // model is performing at it's task. To calculate this,
  64. // the function needs both of the current thetas, and
  65. // the dataset it's training against
  66. function costFunction(theta1, theta2, dataset) {
  67. // Here we generate our model using the function we
  68. // wrote earlier, giving it our current theta values.
  69. const model = prepareLinearFunction(theta1,theta2);
  70.  
  71. // We apply a procedure to our model for each row
  72. // in the dataset.
  73. return dataset.map((x)=>{
  74. // First we get the difference between what the
  75. // data row says about the mapping and what our
  76. // model says.
  77. const difference = model(x[0])-x[1];
  78.  
  79. // We then return the square of that difference.
  80. return Math.pow(difference,2);
  81. }) // Now we have an array of the square of the difference
  82. // between each of the examples and what we predicted for
  83. // their x value. The following line sums that array, which
  84. // we divide by the length of the dataset, and return.
  85. .reduce((x,y)=>{return x+y},0)/dataset.length*2;
  86. }
  87.  
  88. // Ok, now we have a cost function. Next up, we implement
  89. // "gradient descent", which is just a prodedure for modifying
  90. // our theta values in a way that will decrease the overall "cost"
  91. // (otherwise known as "error") of our model.
  92.  
  93. function gradientDescent(learningRate, thetaOne, thetaTwo, dataset) {
  94. // First, we calculate the error of the model that our current
  95. // values of theta creates
  96. const error = costFunction(thetaOne, thetaTwo, dataset);
  97.  
  98. // Then we use the error, the learning rate to update each theta
  99. // thetas must be updated simultaneously - don't get into a
  100. // situation where you update one and you use that new theta
  101. // to update your next theta. It would probably work, but it's
  102. // not proper gradient descent.
  103. /*const newThetas = [thetaOne, thetaTwo].map(function(theta){
  104. // Note - I don't know how to calculate derivative of the cost
  105. // function yet. It wasn't covered in this lecture. It's a
  106. // measure of how far away your thetas are from a "local minimum"
  107. // in error, it's what guides your thetas towards finding their
  108. // correct values.
  109. theta * learningRate * derivitave * error;
  110. });*/
  111. //please excuse this hackery nonsense
  112.  
  113. const model = prepareLinearFunction(thetaOne,thetaTwo);
  114.  
  115. const a = dataset.map((x) => {
  116. return model(x[0])-x[1];
  117. }).reduce((x,y) => {return x + y}, 0)/dataset.length;
  118.  
  119. const b = dataset.map((x) => {
  120. return (model(x[0])-x[1])*x[0];
  121. }).reduce((x,y) => {return x + y}, 0)/dataset.length;
  122.  
  123. const newThetas = [
  124. thetaOne - learningRate * a,
  125. thetaTwo - learningRate * b
  126. ];
  127. debugger;
  128. return { newThetas, error };
  129. }
  130.  
  131. // Lets run through the whole training process
  132. (function linearRegress(dataset){
  133. // Initialize thetas to zero. It's not important that
  134. // they're zero, they could start out as any number,
  135. // but zero works just fine.
  136. const initialThetaOne = 0;
  137. const initialThetaTwo = 0;
  138. const learningRate = 0.2;
  139.  
  140. // Create a named function so that you can recurse
  141. // through the values of theta that gradient descent gives
  142. // you until you converge.
  143. (function reg(learningRate, thetaOne, thetaTwo, dataset) {
  144. console.log(`Current thetas: ${thetaOne}, ${thetaTwo}`);
  145.  
  146. // Run gradient descent
  147. const {error,newThetas} = gradientDescent(learningRate, thetaOne, thetaTwo, dataset);
  148.  
  149. console.log(`Those thetas gave us an error of ${error}.`);
  150.  
  151. if (error < 0.00001) {
  152. // Our error is zero! That means our thetas have
  153. // "converged", or "settled" on values that make sense
  154. // for the dataset. Note that because our dataset fits
  155. // perfectly on a line, we can check that our thetas
  156. // match exactly. When your dataset is always going to
  157. // have a certain amount of error in it (i.e. when the
  158. // data doesn't exactly match any straight line), you'll
  159. // have to check tolerate some difference.
  160. console.log(`Convergeance! Line of best fit is: y = ${thetaOne} + ${thetaTwo}x.`);
  161. process.exit();
  162. }
  163.  
  164. // Recursively call this function with updated thetas until
  165. // convergeance happens and the condition above is met
  166. console.log("Running gradient descent again to reduce the error.")
  167. reg(learningRate, newThetas[0], newThetas[1], dataset);
  168. })(learningRate, initialThetaOne, initialThetaTwo, dataset);
  169. })(dataset);
  170. })();
Advertisement
Add Comment
Please, Sign In to add comment