Таким образом, я считал два связанных вопроса для вычисления линии тренда для графика, но я все еще потерян.
У меня есть массив координат xy, и я хочу придумать другой массив координат xy (может быть меньше координат), которые представляют логарифмическую линию тренда с помощью PHP.
Я передаю эти массивы JavaScript для построения графиков на стороне клиента.
Поскольку мы можем преобразовать логарифмическую функцию в линию, взяв log
значений x
, мы можем выполнить линейную подгонку кривой по наименьшим квадратам. Фактически, эта работа была проделана за нас, и решение представлено в Math World.
Вкратце, нам даны значения $X
и $Y
, которые находятся в распределении типа y = a + b * log(x)
. Метод наименьших квадратов даст некоторые значения aFit
и bFit
, которые минимизируют расстояние от параметрической кривой до заданных точек данных.
Вот пример реализации на PHP:
Сначала я сгенерирую некоторые случайные данные с известным распределением, заданным $a
и $b
// 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 < $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);
}
Теперь, вот как использовать приведенные уравнения для оценки $a
и $b
.
// 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;
Затем вы можете генерировать точки для вашего Javascript с такой плотностью, как вам нравится:
$Yfit = array();
foreach($X as $x) {
$Yfit[] = $aFit + $bFit * log($x);
}
В данном случае код оценивает bFit = 5.17
и aFit = 9.7
, что довольно близко для всего 50
точек данных.
Для примера данных, приведенного в комментарии ниже, логарифмическая функция подходит плохо.
Решением по методу наименьших квадратов является y = -514.734835478 + 2180.51562281 * log(x)
, что по сути является прямой в этой области.