出典:http://PolynomialRegression.drque.net/
最新版は上記から取得してください。
PolynomialRegression.php のソース
class PolynomialRegression { private $xPowers; private $xyPowers; private $numberOfCoefficient; private $forcedValue; public function __construct( $numberOfCoefficient = 3 ) { $this->numberOfCoefficient = $numberOfCoefficient; $this->reset(); } // __construct public function reset() { $this->forcedValue = array(); $this->xPowers = array(); $this->xyPowers = array(); $squares = ( $this->numberOfCoefficient - 1 ) * 2; // Initialize power arrays. for ( $index = 0; $index <= $squares; ++$index ) { $this->xPowers[ $index ] = 0; $this->xyPowers[ $index ] = 0; } } // reset public function setDegree( $numberOfCoefficient ) { $this->numberOfCoefficient = $numberOfCoefficient; } // setDegree public function setNumberOfCoefficient( $numberOfCoefficient ) { $this->numberOfCoefficient = $numberOfCoefficient; } // setNumberOfCoefficient public function getNumberOfCoefficient( $numberOfCoefficient ) { return $this->numberOfCoefficient; } // getnumberOfCoefficient public function setForcedCoefficient( $coefficient, $value ) { $this->forcedValue[ $coefficient ] = $value; } // setForcedCoefficient public function getForcedCoefficient( $coefficient, $value ) { $result = null; if ( isset( $this->forcedValue[ $coefficient ] ) ) $result = $this->forcedValue[ $coefficient ]; return $result; } // getForcedCoefficient public function addData( $x, $y ) { $squares = ( $this->numberOfCoefficient - 1 ) * 2; // Remove the effect of the forced coefficient from this value. foreach ( $this->forcedValue as $coefficient => $value ) { $sub = bcpow( $x, $coefficient ); $sub = bcmul( $sub, $value ); $y = bcsub( $y, $sub ); } // Accumulate new data to power sums. for ( $index = 0; $index <= $squares; ++$index ) { $this->xPowers[ $index ] = bcadd( $this->xPowers[ $index ], bcpow( $x, $index ) ); $this->xyPowers[ $index ] = bcadd ( $this->xyPowers[ $index ], bcmul( $y, bcpow( $x, $index ) ) ); } } // addData public function getCoefficients( $numberOfCoefficient = -1 ) { // If no number of coefficients specified, use standard. if ( $numberOfCoefficient == -1 ) $numberOfCoefficient = $this->numberOfCoefficient; $matrix = array(); for ( $row = 0; $row < $numberOfCoefficient; ++$row ) { $matrix[ $row ] = array(); for ( $column = 0; $column < $numberOfCoefficient; ++$column ) $matrix[ $row ][ $column ] = $this->xPowers[ $row + $column ]; } // Create augmented matrix by adding X*Y powers. for ( $row = 0; $row < $numberOfCoefficient; ++$row ) $matrix[ $row ][ $numberOfCoefficient ] = $this->xyPowers[ $row ]; foreach ( $this->forcedValue as $coefficient => $value ) { for ( $index = 0; $index < $numberOfCoefficient; ++$index ) { $matrix[ $index ][ $coefficient ] = "0"; $matrix[ $coefficient ][ $index ] = "0"; } $matrix[ $coefficient ][ $coefficient ] = "1"; $matrix[ $coefficient ][ $numberOfCoefficient ] = $value; } // Determine number of rows in matrix. $rows = count( $matrix ); // Initialize done. $isDone = array(); for ( $column = 0; $column < $rows; ++$column ) $isDone[ $column ] = false; $order = array(); for ( $column = 0; $column < $rows; ++$column ) { // Find a row to work with. // A row that has a term in this column, and has not yet been // reduced. $activeRow = 0; while ( ( ( 0 == $matrix[ $activeRow ][ $column ] ) || ( $isDone[ $activeRow ] ) ) && ( $activeRow < $rows ) ) { ++$activeRow; } // Do we have a term in this row? if ( $activeRow < $rows ) { // Remember the order. $order[ $column ] = $activeRow; // Normalize row--results in the first term being 1. $firstTerm = $matrix[ $activeRow ][ $column ]; for ( $subColumn = $column; $subColumn <= $rows; ++$subColumn ) $matrix[ $activeRow ][ $subColumn ] = bcdiv( $matrix[ $activeRow ][ $subColumn ], $firstTerm ); // This row is finished. $isDone[ $activeRow ] = true; // Subtract the active row from all rows that are not finished. for ( $row = 0; $row < $rows; ++$row ) if ( ( ! $isDone[ $row ] ) && ( 0 != $matrix[ $row ][ $column ] ) ) { // Get first term in row. $firstTerm = $matrix[ $row ][ $column ]; for ( $subColumn = $column; $subColumn <= $rows; ++$subColumn ) { $accumulator = bcmul( $firstTerm, $matrix[ $activeRow ][ $subColumn ] ); $matrix[ $row ][ $subColumn ] = bcsub( $matrix[ $row ][ $subColumn ], $accumulator ); } } } } // Reset done. for ( $row = 0; $row < $rows; ++$row ) $isDone[ $row ] = false; $coefficients = array(); for ( $column = ( $rows - 1 ); $column >= 0; --$column ) { // The active row is based on order. $activeRow = $order[ $column ]; // The active row is now finished. $isDone[ $activeRow ] = true; // For all rows not finished... for ( $row = 0; $row < $rows; ++$row ) if ( ! $isDone[ $row ] ) { $firstTerm = $matrix[ $row ][ $column ]; // Back substitution. for ( $subColumn = $column; $subColumn <= $rows; ++$subColumn ) { $accumulator = bcmul( $firstTerm, $matrix[ $activeRow ][ $subColumn ] ); $matrix[ $row ][ $subColumn ] = bcsub( $matrix[ $row ][ $subColumn ], $accumulator ); } } // Save this coefficient for the return. $coefficients[ $column ] = $matrix[ $activeRow ][ $rows ]; } // Coefficients are stored backward, so sort them. ksort( $coefficients ); // Return the coefficients. return $coefficients; } // getCoefficients static public function interpolate( $coefficients, $x ) { $numberOfCoefficient = count( $coefficients ); $y = 0; for ( $coefficentIndex = 0; $coefficentIndex < $numberOfCoefficient; ++$coefficentIndex ) { // y += coefficients[ coefficentIndex ] * x^coefficentIndex $y = bcadd ( $y, bcmul ( $coefficients[ $coefficentIndex ], bcpow( $x, $coefficentIndex ) ) ); } return floatval( $y ); } // interpolate } // Class
テスト実行
データは、配列で指定する。 中の array(1,0),・・・が、array(Xの値,Yの値(目的変数))の順である。
require_once( 'inc_PolynomialRegression.php' ); //class読込 //テスト配列定義 $data = array ( array(1,0), array(2,4), array(3,3), array(4,2), array(5,5), array(6,3), array(7,8) ); //print_r ( $data ) ; // Precision digits in BC math. bcscale( 10 ); // Start a regression class of order 2--linear regression. $PolynomialRegression = new PolynomialRegression( 2 ); //変数の数、次数+1 // Add all the data to the regression analysis. foreach ( $data as $dataPoint ) $PolynomialRegression->addData( $dataPoint[ 0 ], $dataPoint[ 1 ] ); // Get coefficients for the polynomial. $coefficients = $PolynomialRegression->getCoefficients(); // // Get average of Y-data. // $Y_Average = 0.0; foreach ( $data as $dataPoint ) $Y_Average += $dataPoint[ 1 ]; $Y_Average /= count( $data ); // // Calculate R Squared. // $Y_MeanSum = 0.0; $Y_ErrorSum = 0.0; foreach ( $data as $dataPoint ) { $x = $dataPoint[ 0 ]; $y = $dataPoint[ 1 ]; $error = $y; $error -= $PolynomialRegression->interpolate( $coefficients, $x ); $Y_ErrorSum += $error * $error; $error = $y; $error -= $Y_Average; $Y_MeanSum += $error * $error; } $R_Squared = 1.0 - ( $Y_ErrorSum / $Y_MeanSum ); // Print slope and intercept of linear regression. // 四捨五入 4桁目 $para_a = round( $coefficients[ 1 ], 4 ); $para_b = round( $coefficients[ 0 ], 4 ); $para_R = round( $R_Squared ,4 ); //結果出力 print "$para_a,$para_b,$para_R" ;
出力結果
0.8571,0.1429,0.5455
よって
y=0.8571 x + 0.1429
重決定 R2 は 0.5455
※X,Yの入れ替えに注意
エクセルとの比較:OK
二次関数で近似するときは
$PolynomialRegression = new PolynomialRegression( 3 );//2→3にする $para_a = round( $coefficients[ 2 ], 4 );//増やす $para_b = round( $coefficients[ 1 ], 4 ); $para_c = round( $coefficients[ 0 ], 4 ); $para_R = round( $R_Squared ,4 );
出力:0.0952,0.0952,1.2857,0.5657
エクセルと比較:OK
/*=========================================================================*/ /* Name: PolynomialRegression.php */ /* Uses: Calculates and returns coefficients for polynomial regression. */ /* Date: 06/01/2009 */ /* Author: Andrew Que (http://www.DrQue.net/) */ /* Revisions: */ /* 0.8 - 06/01/2009- QUE - Creation. */ /* 0.9 - 06/14/2012- QUE - */ /* + Bug fix: removed notice causes by uninitialized variable. */ /* + Converted naming convention. */ /* + Fix spelling errors (or the ones I found). */ /* + Changed to row-echelon method for solving matrix which is much */ /* faster than the determinant method. */ /* 0.91 - 05/17/2013- QUE - */ /* = Changed name to Polynonial regression as this is more fitting to */ /* to the function. */ /* 0.92 - 12/28/2013- QUE - */ /* + Added forced offset. */ /* 1.00 - 12/29/2013 - QUE - */ /* + Forced offset changed to allow any term to be forced. */ /* Unit complete. Correlation coefficient (r-squared) has been */ /* implemented externally in the demos. */ /* 1.1 - 2014/05/05 - QUE - */ /* + 'interpolate' is now static as it does not need an instance to */ /* operate. Useful if coefficients have been calculated elsewhere. */ /* - Deprecated 'setDegree' function. This is the wrong terminology for */ /* what the function does. It actually sets the number of */ /* coefficients for the polynomial. The degree of the polynomial is */ /* the number of coefficients less one. Made the identical function */ /* 'setNumberOfCoefficient' to replace it. */ /* + Added getter functions for anything that has a set function. */ /* */ /* This project is maintained at: */ /* http://PolynomialRegression.drque.net/ */ /* */ /* ----------------------------------------------------------------------- */ /* */ /* Polynomial regression class. */ /* Copyright (C) 2009, 2012-2014 Andrew Que */ /* */ /* This program is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program. If not, see
* Used for calculating polynomial regression coefficients. Useful for
* linear and non-linear regression, and polynomial curve fitting.
*
* @package PolynomialRegression
* @author Andrew Que ({@link http://www.DrQue.net/})
* @link http://PolynomialRegression.drque.net/ Project home page.
* @copyright Copyright (c) 2009, 2012-2014, Andrew Que
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @version 1.1
*/
/**
* Used for calculating polynomial regression coefficients and interpolation using
* those coefficients. Useful for linear and non-linear regression, and polynomial
* curve fitting.
*
* Note: Requires BC math to be compiled into PHP. Higher-degree polynomials end up
* with very large/small numbers, requiring an arbitrary precision arithmetic. Make sure
* to set "bcscale" as coefficients will likely have decimal values.
*
* Quick example of using this unit to calculate linear regression (1st degree polynomial):
*
*
* $regression = new PolynomialRegression( 2 );
* // ...
* $regression->addData( $x, $y );
* // ...
* $coefficients = $regression->getCoefficients();
* // ...
* $y = $regression->interpolate( $coefficients, $x );
*
*
*
* @package PolynomialRegression
* @link http://PolynomialRegression.drque.net/ Project home page.
0 件のコメント:
コメントを投稿