美文网首页
最小二乘法曲线拟合

最小二乘法曲线拟合

作者: greymonster | 来源:发表于2017-05-07 16:56 被阅读0次

    除了梯度下降法去拟合曲线,最小二乘法也是另一个方法。和梯度下降不断迭代求出极值不同的是,最小二乘法是直接求导计算出参数。数学的问题还是参考数学相关的资料吧,同时可以@refer http://blog.csdn.net/jairuschan/article/details/7517773

    下面直接上代码。

    /*
     * 利用最小二乘法求拟合参数
     *
     * @auther menmei
     * @date 2017/03/27
     */
    
    /*
     * Least Square Procedure
     * @fomula w = (x'x)-1x'y
     */
    
    /*
     * 获取矩阵的转秩
     *
     * @param Array
     * @return Array
     *
     */
    function getMatrixT($origin){
        $lines = count($origin);
        if($lines <= 0) return False;
        $rowsArr = $origin[0];
        if(!is_array($rowsArr)) return False;
        $rows  = count($origin[0]);
    
        $return = [];
    
        for($i = 0; $i < $lines; $i ++){
            for($j = 0; $j < $rows; $j ++){
                $return[$j][$i] = $origin[$i][$j];
    
            }
        }
        return $return;
    }
    
    /*
     * 矩阵相乘
     *
     * @param Array $a
     * @param Array $b
     *
     * @condition rows(A) = lines(B)
     * @return Array $return
     */
    function matrixMulti($a, $b){
        $linesA = count($a);
        $rowsA  = count($a[0]);
        $linesB = count($b);
        $rowsB = count($b[0]);
        if($rowsA != $linesB) return False;
        //echo  $rows;
        //if($linesA == 0 || $rowsB == 0) return False;
        for($i = 0; $i < $linesA; $i++){
            for($j = 0; $j < $rowsB; $j ++){
                $num = 0;
                for($z = 0; $z < $rowsA; $z ++){
                    $num += $a[$i][$z] * $b[$z][$j];
                }
                $return[$i][$j] = $num;
            }
        }
        return $return;
    }
    /*
     *求矩阵的模
     * @refer http://blog.csdn.net/shanshanpt/article/details/16820325
     */
    function calculate_A( $src, $n )
    {
        $result = 0.0;
    
        if( $n == 1 )
        {
            return $src[0][0];
        }
    
        for( $i = 0; $i < $n; ++$i )
        {
            for( $j = 0; $j < $n - 1; ++$j )
            {
                for( $k = 0; $k < $n - 1; ++$k )
                {
                    $x = $j + 1;
                    $y = $k >= $i ? $k + 1 : $k;
    
                    $tmp[$j][$k] = $src[$x][$y];
                }
            }
    
            $t = calculate_A( $tmp, $n - 1 );
    
            if( $i % 2 == 0 )
            {
                $result += $src[0][$i] * $t;
            }
            else
            {
                $result -= $src[0][$i] * $t;
            }
        }
    
        return $result;
    }
    
    /*
     * 伴随矩阵
     * @refer http://blog.csdn.net/shanshanpt/article/details/16820325
     */
    
    function getAdjoint( $origin )
    {
        $n = count($origin);
    
        if( $n == 1 )
        {
            $dst[][] = 1;
            return;
                              
        }
    
        for( $i = 0; $i < $n; ++$i )
        {
            for( $j = 0; $j < $n; ++$j )
            {
                for( $k = 0; $k < $n - 1; ++$k )
                {
                    for( $t = 0; $t < $n - 1; ++$t )
                    {
                        $x = $k >= $i ? $k + 1 : $k ;
                        $y = $t >= $j ? $t + 1 : $t;
    
                        $tmp[$k][$t] = $origin[$x][$y];
                    }
                }
                $ret[$j][$i]  =  calculate_A( $tmp, $n - 1 );
    
                if( ( $i + $j ) % 2 == 1 )
                {
                    $ret[$j][$i] = -1*$ret[$j][$i];
                }
                $ret[$j][$i] = 1/260*$ret[$j][$i];
            }
        }
    
        return $ret;
    }
    
    /***************** EXAMPLE ******************/
    $a = [[1, 2], [1, 6], [1, 9], [1, 13]];
    $y = [[4],[8],[12],[21]];
    $aT = getMatrixT($a);
    $aTa = matrixMulti($aT, $a);
    $t = getAdjoint($aTa);
    $ret = matrixMulti($t, $aT);
    $ret = matrixMulti($ret, $y);
    var_dump($ret);
    //$dataset = [[1,4],[2,5],[5,1],[4,2]];
    //$dataret = [19,26, 19, 20];
    //$expect  = [10, 10];
    //$step  = 0.001;
    //$times = 1000000;
    
    

    求伴随矩阵和矩阵的模的两个函数 自己写的不太好,运行起来比代码里用的函数慢多了。。就不放出来了,这里用的是参考一篇文章的代码。原代码是C语言写的。谢谢[shanshanpt] http://blog.csdn.net/shanshanpt/article/details/16820325

    还有一些相关的函数。

    /*
     * 获得逆序数
     * @auther menmei
     * @date 2017/03/27
     */
    
    function getInversionNumber($arr){
        $Total = count($arr);
        $inversionNum = 0;
        $exist = [];
    
        for($i = 0; $i < $Total; $i ++){
            if($arr[$i] >= 1){
                $tmp = range(0, $arr[$i] - 1);
                //在tmp中有 但exist没有的。
                $diff = array_diff($tmp, $exist);
                $inversionNum += count($diff);
            }
            $exist[] = $arr[$i];
        }
        return $inversionNum;
    }
    
    

    相关文章

      网友评论

          本文标题:最小二乘法曲线拟合

          本文链接:https://www.haomeiwen.com/subject/ddautxtx.html