





Часто используемый подход - итеративно минимизировать сумму квадратов разностей y между вашими точками и функцией подбора.
Хотя вы можете использовать итеративный подход, вы можете напрямую рассчитать наклон и точку пересечения линии с учетом набора наблюдений, используя метод наименьших квадратов. См. Раздел «Одномерный линейный случай» в статья в Википедии о линейной регрессии, чтобы узнать, как вычислить коэффициенты a и b в y = a + bx с заданными наборами точек (x,y).
Метод наименьших квадратов http://en.wikipedia.org/wiki/Least_squares. Эта книга Цифровые рецепты 3-е издание: Искусство научных вычислений (твердый переплет) имеет все необходимое для алгоритмов реализации метода наименьших квадратов и других методов.
Вы можете проверить линейная регрессия или, в более общем смысле, подгонка кривой.
Вот статья, сравнивающий два способа подгонки строки к данным. Следует остерегаться того, что существует прямое решение, правильное в теории, но может иметь числовые проблемы. В статье показано, почему этот метод может дать сбой, и предложен другой, более эффективный метод.
Реализовано со страницы вики, не тестировалось.
$sx = 0;
$sy = 0;
$sxy = 0;
$sx2 = 0;
$n = count($data);
foreach ($data as $x => $y)
{
$sx += $x;
$sy += $y;
$sxy += $x * $y;
$sx2 += $x * $x;
}
$beta = ($n*$sxy - $sx*$sy) / ($n*$sx2 - $sx*$sx);
$alpha = $sy/$n - $sx*$beta/$n;
echo "y = $alpha + $beta x";
Дополнительный интерес, вероятно, вызывает то, насколько хорошо подходит эта леска. Для этого используйте корреляцию Пирсона здесь, в функции PHP:
/**
* returns the pearson correlation coefficient (least squares best fit line)
*
* @param array $x array of all x vals
* @param array $y array of all y vals
*/
function pearson(array $x, array $y)
{
// number of values
$n = count($x);
$keys = array_keys(array_intersect_key($x, $y));
// get all needed values as we step through the common keys
$x_sum = 0;
$y_sum = 0;
$x_sum_sq = 0;
$y_sum_sq = 0;
$prod_sum = 0;
foreach($keys as $k)
{
$x_sum += $x[$k];
$y_sum += $y[$k];
$x_sum_sq += pow($x[$k], 2);
$y_sum_sq += pow($y[$k], 2);
$prod_sum += $x[$k] * $y[$k];
}
$numerator = $prod_sum - ($x_sum * $y_sum / $n);
$denominator = sqrt( ($x_sum_sq - pow($x_sum, 2) / $n) * ($y_sum_sq - pow($y_sum, 2) / $n) );
return $denominator == 0 ? 0 : $numerator / $denominator;
}
кстати, коэффициент Пирсона колеблется от 0 (нет корреляции) до 1,0 (точки лежат на прямой линии)
Чтобы добавить к ответу FryGuy, если вам нужна функция, которая также дает R ^ 2 (чтобы показать, насколько хорошо подходит):
function mathTrend($data) {
$sx = 0;
$sy = 0;
$sxy = 0;
$sx2 = 0;
$yTotal = 0;
$n = count($data);
if ($n <= 1) {
return false;
}
foreach ($data as $row)
{
$row = array_values($row);
$x = $row[0];
$y = $row[1];
$yTotal += $y;
$sx += $x;
$sy += $y;
$sxy += $x * $y;
$sx2 += $x * $x;
}
$yAvg = $yTotal / $n;
$m = ($n*$sxy - $sx*$sy) / ($n*$sx2 - $sx*$sx);
$b = $sy/$n - $sx*$m/$n;
//Go through again to determine rSquared
//Using method from https://thewikihow.com/video_w2FKXOa0HGA
$diffActual = 0;
$diffEstimated = 0;
foreach($data as $row) {
$row = array_values($row);
$x = $row[0];
$y = $row[1];
$expectedY = $m*$x+$b;
$diffActual += ($y - $yAvg)**2;
$diffEstimated += ($expectedY-$yAvg)**2;
}
$rSquared = $diffEstimated / $diffActual;
$result = ['m'=> $m, 'b' => $b, 'rSquared' => $rSquared];
return $result;
}
+1 Это, безусловно, лучший ответ, другой метод намного хуже, хотя и более популярен.