代码之家  ›  专栏  ›  技术社区  ›  Stephen

如何用PHP计算趋势线?

  •  11
  • Stephen  · 技术社区  · 16 年前

    所以我读了两个相关的问题来计算一个图表的趋势线,但是我还是迷路了。

    我将这些数组传递给javascript,以便在客户端绘制图形。

    2 回复  |  直到 16 年前
        1
  •  29
  •   Community Mohan Dere    6 年前

    对数最小二乘法

    因为我们可以通过取 log 的 x linear least squares 曲线拟合。事实上,这项工作已经为我们完成了,并在会议上提出了解决办法 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);
    
      }
    

    现在,这里是如何使用给出的方程来估计 一美元 和 十亿美元 .

      // 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;
    

      $Yfit = array();
      foreach($X as $x) {
        $Yfit[] = $aFit + $bFit * log($x);
      }
    

    在本例中,代码估计 bFit = 5.17 和 aFit = 9.7 50 数据点。

    alt text

    对于下面注释中给出的示例数据,对数函数并不适合。

    alt text

    最小二乘解是 y = -514.734835478 + 2180.51562281 * log(x)

        3
  •  0
  •   Dr. Pierce    6 年前

    如果有人对create\u函数有问题,下面是我如何编辑它的(虽然我没有使用日志,所以我确实把它们拿了出来。)

    我还减少了计算的次数,并添加了一个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;
    }