12

グラフの傾向線を計算するための 2 つの関連する質問を読みましたが、まだ迷っています。

xy 座標の配列があり、PHP を使用して対数トレンド ラインを表す xy 座標の別の配列 (より少ない座標である可能性があります) を作成したいと考えています。

これらの配列を JavaScript に渡して、クライアント側でグラフをプロットします。

4

3 に答える 3

29

対数最小二乗

値をとることで対数関数を直線に変換できるので、log線形最小二乗曲線あてはめを実行できます。実際、作業は私たちのために行われ、解決策はMathWorldで提示されていますx

簡単に言えば、のような分布からの値が与え$Xられます。最小二乗法はいくつかの値を与え、パラメトリック曲線から与えられたデータポイントまでの距離を最小にします。$Yy = a + b * log(x)aFitbFit

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)、本質的にこの領域の線です。

于 2010-05-04T21:25:38.687 に答える
4

ライブラリの使用をお勧めします: http://www.drque.net/Projects/PolynomialRegression/

Composer で入手可能: https://packagist.org/packages/dr-que/polynomial-regression

于 2015-10-03T18:40:48.293 に答える
1

誰かが create_function に問題を抱えている場合に備えて、私が編集した方法を次に示します。(ログを使用していなかったので、それらを取り出しました。)

また、計算の数を減らし、R2 を追加しました。これまでのところうまくいくようです。

function lsq(){
    $X = array(1,2,3,4,5);
    $Y = array(.3,.2,.7,.9,.8);

    // Now estimate $a and $b using equations from Math World
    $n = count($X);

    $mult_elem = function($x,$y){   //anon function mult array elements 
        $output=$x*$y;              //will be called on each element
        return $output;
    };

    $sumX2 = array_sum(array_map($mult_elem, $X, $X));

    $sumXY = array_sum(array_map($mult_elem, $X, $Y));
    $sumY = array_sum($Y);
    $sumX = array_sum($X);

    $bFit = ($n * $sumXY - $sumY * $sumX) /
    ($n * $sumX2 - pow($sumX, 2));
    $aFit = ($sumY - $bFit * $sumX) / $n;
    echo ' intercept ',$aFit,'    ';
    echo ' slope ',$bFit,'   ' ;    

    //r2
    $sumY2 = array_sum(array_map($mult_elem, $Y, $Y));
    $top=($n*$sumXY-$sumY*$sumX);
    $bottom=($n*$sumX2-$sumX*$sumX)*($n*$sumY2-$sumY*$sumY);
    $r2=pow($top/sqrt($bottom),2);
    echo '  r2  ',$r2;
}
于 2020-01-12T03:40:58.357 に答える