Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<h2>Logarithmic Least Squares</h2> <p>Since we can convert a logarithmic function into a line by taking the <code>log</code> of the <code>x</code> values, we can perform a <a href="http://en.wikipedia.org/wiki/Linear_least_squares" rel="nofollow noreferrer">linear least squares</a> curve fitting. In fact, the work has been done for us and a solution is presented at <a href="http://mathworld.wolfram.com/LeastSquaresFittingLogarithmic.html" rel="nofollow noreferrer">Math World</a>.</p> <p>In brief, we're given <code>$X</code> and <code>$Y</code> values that are from a distribution like <code>y = a + b * log(x)</code>. The least squares method will give some values <code>aFit</code> and <code>bFit</code> that minimize the distance from the parametric curve to the data points given.</p> <p><strong>Here is an example implementation in PHP:</strong></p> <p>First I'll generate some random data with known underlying distribution given by <code>$a</code> and <code>$b</code></p> <pre><code> // True parameter valaues $a = 10; $b = 5; // Range of x values to generate $x_min = 1; $x_max = 10; $nPoints = 50; // Generate some random points on y = a * log(x) + b $X = array(); $Y = array(); for($p = 0; $p &lt; $nPoints; $p++){ $x = $p / $nPoints * ($x_max - $x_min) + $x_min; $y = $a + $b * log($x); $X[] = $x + rand(0, 200) / ($nPoints * $x_max); $Y[] = $y + rand(0, 200) / ($nPoints * $x_max); } </code></pre> <p>Now, here's how to use the equations given to estimate <code>$a</code> and <code>$b</code>.</p> <pre><code> // Now convert to log-scale for X $logX = array_map('log', $X); // Now estimate $a and $b using equations from Math World $n = count($X); $square = create_function('$x', 'return pow($x,2);'); $x_squared = array_sum(array_map($square, $logX)); $xy = array_sum(array_map(create_function('$x,$y', 'return $x*$y;'), $logX, $Y)); $bFit = ($n * $xy - array_sum($Y) * array_sum($logX)) / ($n * $x_squared - pow(array_sum($logX), 2)); $aFit = (array_sum($Y) - $bFit * array_sum($logX)) / $n; </code></pre> <p>You may then generate points for your Javascript as densely as you like:</p> <pre><code> $Yfit = array(); foreach($X as $x) { $Yfit[] = $aFit + $bFit * log($x); } </code></pre> <p>In this case, the code estimates <code>bFit = 5.17</code> and <code>aFit = 9.7</code>, which is quite close for only <code>50</code> data points.</p> <p><img src="https://i.stack.imgur.com/U6Ily.png" alt="alt text"></p> <p>For the example data given in the comment below, a logarithmic function does not fit well.</p> <p><img src="https://i.stack.imgur.com/mMq0I.png" alt="alt text"></p> <p>The least squares solution is <code>y = -514.734835478 + 2180.51562281 * log(x)</code> which is essentially a line in this domain.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload