{"id":482,"date":"2020-04-09T11:19:54","date_gmt":"2020-04-09T11:19:54","guid":{"rendered":"http:\/\/www.nicassio.it\/daniele\/blog\/?p=482"},"modified":"2020-04-09T12:58:50","modified_gmt":"2020-04-09T12:58:50","slug":"js-genetic-curve-fitter","status":"publish","type":"post","link":"http:\/\/www.nicassio.it\/daniele\/blog\/?p=482","title":{"rendered":"JS Genetic Curve Fitter"},"content":{"rendered":"<style>pre{font-size:0.8em;}<\/style>\n<p>While I was working on Coronamap.it, in the new section dedicated to analysis, I felt the need to do some curve fitting, that is I had a series of points and I wanted to find a curve which best fit the points, given some constraints. Of course I expected this to be a well known and well solved problem, only to discover that of course yes it is, but it&#8217;s actually something not necessarily easy to do. It&#8217;s a complex problem which requires to search in a large space of solutions, and as that not an easy task to be done in JS (which I required). Fortunately, I found an implementation in JS which used a genetic algorithm approach, so I decided to rewrite another one from scratch using my old project JSGenetic. If it does not make any sense to you, it&#8217;s because it does not have any &#8211; except that I love to make this kind of stuff.<\/p>\n<p>So enough for the story, let&#8217;s talk about the library:<\/p>\n<p><a href=\"http:\/\/www.nicassio.it\/daniele\/JSGeneticCurveFitter\/index.html\" title=\"JSGeneticCurveFitter\" rel=\"noopener\" target=\"_blank\">Example here<\/a><\/p>\n<p>Usage:<\/p>\n<pre>\r\nvar cf = GeneticCurveFitter(points, functionGenerator, 3, { \/\/3 is the number parameters you need to tune to find the fitting curve\r\n    RANGES: [\r\n        [1, 2000], \/\/one range for every parameter - if not specified, they fall back to [-1000,1000] which is kind of silly\r\n        [1580000000000, 1590000000000],\r\n        [10000000, 1000000000]\r\n    ]\r\n});\r\n<\/pre>\n<pre>functionGenerator<\/pre>\n<p> is a function which gets the generated parameters in input and returns the function which you want to optimize. Easier to explain with an example:<\/p>\n<pre>\r\n\/\/polynomial functionGenerator\r\nfunction polyGen(coeffs) {\r\n  return function(x) {\r\n    var result = 0;\r\n    for(var i=0; i&lt;coeffs.length; i++) {\r\n      result += coeffs[i]*Math.pow(x,i);\r\n    }\r\n    return result;\r\n  }\r\n}\r\n\r\n\/\/gaussian from the example\r\nvar gaussGen = function (coeff) {\r\n    return function (x) {\r\n        return coeff[0] * Math.exp(-((x - coeff[1]) * (x - coeff[1])) \/ (2 * coeff[2] * coeff[2]));\r\n    }\r\n}\r\n<\/pre>\n<p>After initializing the object, it can be easily run like this:<\/p>\n<pre>\r\nvar resultFn =   cf.fit();\r\n<\/pre>\n<p>which returns the best fit function it could find. The process takes some seconds and the time can vary by CPU power and number of coefficients to find. The returned function also has an helper method to generate a chart from it (read: to sample it) which goes like this:<\/p>\n<pre>\r\nvar samples = resultFn.toDataset(startX,endX,numberOfSamples);\r\n\/\/samples is in the form [{x:<value>,y:<value>}, ...]\r\n<\/pre>\n<p>There are also other methods to better control the evolution of the coefficients: here are the library&#8217;s returned methods:<\/p>\n<pre>\r\n{\r\n        step: step, \/\/make a single step of the genetic algoritm, or N steps if you call cf.step(N)\r\n        fit: fit, \/\/already described before\r\n        getCurrentSolution: getCurrentSolution, \/\/gets current solution\r\n        getCurrentFitness: getCurrentFitness,\/\/gets current error\r\n        getCurrentCoefficients: getCurrentCoefficients \/\/get raw coefficients as an array\r\n}\r\n<\/pre>\n<p>That&#8217;s all! Enjoy.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>While I was working on Coronamap.it, in the new section dedicated to analysis, I felt the need to do some curve fitting, that is I had a series of points and I wanted to find a curve which best fit the points, given some constraints. Of course I expected this to be a well known &hellip; <a href=\"http:\/\/www.nicassio.it\/daniele\/blog\/?p=482\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">JS Genetic Curve Fitter<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"http:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=\/wp\/v2\/posts\/482"}],"collection":[{"href":"http:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=482"}],"version-history":[{"count":7,"href":"http:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=\/wp\/v2\/posts\/482\/revisions"}],"predecessor-version":[{"id":489,"href":"http:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=\/wp\/v2\/posts\/482\/revisions\/489"}],"wp:attachment":[{"href":"http:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=482"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=482"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=482"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}