/**
  * Calculates the regression parameters.
  */
 public function calculate()
 {
     $v = $this->v;
     $w = $this->w;
     $x’ = Single::subtract($this->xs, $v);
     $y’ = Single::subtract($this->ys, $w);
     $parameters = $this->leastSquares($y’, $x’, 1, 0)->getColumn(0);
     $this->m = $parameters[0];
     $this->b = $this->w - $this->m * $this->v;
     $this->parameters = [$this->b, $this->m];
 }
 /**
  * Calculate the regression parameters by least squares on linearized data
  * y⁻¹ = K * V⁻¹ * x⁻¹ + V⁻¹
  */
 public function calculate()
 {
     // Linearize the relationship by taking the inverse of both x and y
     $x’ = Single::pow($this->xs, -1);
     $y’ = Single::pow($this->ys, -1);
     // Perform Least Squares Fit
     $linearized_parameters = $this->leastSquares($y’, $x’)->getColumn(0);
     // Translate the linearized parameters back.
     $V = 1 / $linearized_parameters[0];
     $K = $linearized_parameters[1] * $V;
     $this->parameters = [$V, $K];
 }
Beispiel #3
0
 /**
  * Evaluate for x
  * Use the smoothness parameter α to determine the subset of data to consider for
  * local regression. Perform a weighted least squares regression and evaluate x.
  *
  * @param  number $x
  *
  * @return number
  */
 public function evaluate($x)
 {
     $α = $this->α;
     $λ = $this->λ;
     $n = $this->n;
     // The number of points considered in the local regression
     $Δx = Single::abs(Single::subtract($this->xs, $x));
     $αᵗʰΔx = Average::kthSmallest($Δx, $this->number_of_points - 1);
     $arg = Single::min(Single::divide($Δx, $αᵗʰΔx * max($α, 1)), 1);
     // Kernel function: tricube = (1-arg³)³
     $tricube = Single::cube(Single::multiply(Single::subtract(Single::cube($arg), 1), -1));
     $weights = $tricube;
     // Local Regression Parameters
     $parameters = $this->leastSquares($this->ys, $this->xs, $weights, $λ);
     $X = new VandermondeMatrix([$x], $λ + 1);
     return $X->multiply($parameters)[0][0];
 }
 /**
  * Sum of squares
  *
  * ∑⟮xᵢ⟯²
  *
  * @param array $numbers
  *
  * @return number
  */
 public static function sumOfSquares(array $numbers)
 {
     if (empty($numbers)) {
         return null;
     }
     $∑⟮xᵢ⟯² = array_sum(Map\Single::square($numbers));
     return $∑⟮xᵢ⟯²;
 }
Beispiel #5
0
 /**
  * Generalized Hypergeometric Function
  *
  * https://en.wikipedia.org/wiki/Generalized_hypergeometric_function
  *
  *                                       ∞
  *                                      ____
  *                                      \     ∏ap⁽ⁿ⁾ * zⁿ
  * pFq(a₁,a₂,...ap;b₁,b₂,...,bq;z)=      >    ------------
  *                                      /      ∏bq⁽ⁿ⁾ * n!
  *                                      ‾‾‾‾
  *                                       n=0
  *
  * Where a⁽ⁿ⁾ is the Pochhammer Function or Rising Factorial
  *
  * We are evaluating this as a series:
  *
  *               (a + n - 1) * z
  * ∏n = ∏n₋₁  * -----------------
  *               (b + n - 1) * n
  *
  *                  n   (a + n - 1) * z
  *   ₁F₁ = ₁F₁n₋₁ + ∏  -----------------  = ₁F₁n₋₁ + ∏n
  *                  1   (b + n - 1) * n
  *
  * @param int   $p      the number of parameters in the numerator
  * @param int   $q      the number of parameters in the denominator
  * @param array $params a collection of the a, b, and z parameters
  *
  * @return number
  *
  * @throws BadParameterException if the number of parameters is incorrect
  */
 public static function generalizedHypergeometric(int $p, int $q, ...$params)
 {
     $n = count($params);
     if ($n !== $p + $q + 1) {
         $expected_num_params = $p + $q + 1;
         throw new Exception\BadParameterException("Number of parameters is incorrect. Expected {$expected_num_params}; got {$n}");
     }
     $a = array_slice($params, 0, $p);
     $b = array_slice($params, $p, $q);
     $z = $params[$n - 1];
     $tol = 1.0E-8;
     $n = 1;
     $sum = 0;
     $product = 1;
     do {
         $sum += $product;
         $a_sum = array_product(Single::add($a, $n - 1));
         $b_sum = array_product(Single::add($b, $n - 1));
         $product *= $a_sum * $z / $b_sum / $n;
         $n++;
     } while ($product / $sum > $tol);
     return $sum;
 }
Beispiel #6
0
 /**
  * Standard error of the regression parameters (coefficients)
  *
  *              _________
  *             /  ∑eᵢ²
  *            /  -----
  * se(m) =   /     ν
  *          /  ---------
  *         √   ∑⟮xᵢ - μ⟯²
  *
  *  where
  *    eᵢ = residual (difference between observed value and value predicted by the model)
  *    ν  = n - 2  degrees of freedom
  *
  *           ______
  *          / ∑xᵢ²
  * se(b) = /  ----
  *        √    n
  *
  * @return array [m => se(m), b => se(b)]
  */
 public function standardErrors()
 {
     $X = new VandermondeMatrix($this->xs, 2);
     $⟮XᵀX⟯⁻¹ = $this->⟮XᵀX⟯⁻¹;
     $σ² = $this->meanSquareResidual();
     $standard_error_matrix = $⟮XᵀX⟯⁻¹->scalarMultiply($σ²);
     $standard_error_array = Single::sqrt($standard_error_matrix->getDiagonalElements());
     return ['m' => $standard_error_array[1], 'b' => $standard_error_array[0]];
 }
Beispiel #7
0
 /**
  * ρ - Spearman's rank correlation coefficient (Spearman's rho)
  *
  * https://en.wikipedia.org/wiki/Spearman%27s_rank_correlation_coefficient
  *
  *          6 ∑ dᵢ²
  * ρ = 1 - ---------
  *         n(n² − 1)
  *
  *  Where
  *   dᵢ: the difference between the two ranks of each observation
  *
  * @param array $X values for random variable X
  * @param array $Y values for random variable Y
  *
  * @return number
  *
  * @throws BadDataException if both random variables do not have the same number of elements
  */
 public static function spearmansRho(array $X, array $Y)
 {
     if (count($X) !== count($Y)) {
         throw new Exception\BadDataException('Both random variables must have the same number of elements');
     }
     $n = count($X);
     // Sorted Xs and Ys
     $Xs = $X;
     $Ys = $Y;
     rsort($Xs);
     rsort($Ys);
     // Determine ranks of each X and Y
     // Some items might show up multiple times, so record each successive rank.
     $rg⟮X⟯ = [];
     $rg⟮Y⟯ = [];
     foreach ($Xs as $rank => $xᵢ) {
         if (!isset($rg⟮X⟯[$xᵢ])) {
             $rg⟮X⟯[$xᵢ] = [];
         }
         $rg⟮X⟯[$xᵢ][] = $rank;
     }
     foreach ($Ys as $rank => $yᵢ) {
         if (!isset($rg⟮Y⟯[$yᵢ])) {
             $rg⟮Y⟯[$yᵢ] = [];
         }
         $rg⟮Y⟯[$yᵢ][] = $rank;
     }
     // Determine average rank of each X and Y
     // Rank will not change if value only shows up once.
     // Average is for when values show up multiple times.
     $rg⟮X⟯ = array_map(function ($x) {
         return array_sum($x) / count($x);
     }, $rg⟮X⟯);
     $rg⟮Y⟯ = array_map(function ($y) {
         return array_sum($y) / count($y);
     }, $rg⟮Y⟯);
     // Difference between the two ranks of each observation
     $d = array_map(function ($x, $y) use($rg⟮X⟯, $rg⟮Y⟯) {
         return abs($rg⟮X⟯[$x] - $rg⟮Y⟯[$y]);
     }, $X, $Y);
     // Numerator: 6 ∑ dᵢ²
     $d² = Map\Single::square($d);
     $∑d² = array_sum($d²);
     // Denominator: n(n² − 1)
     $n⟮n² − 1⟯ = $n * ($n ** 2 - 1);
     /*
      *          6 ∑ dᵢ²
      * ρ = 1 - ---------
      *         n(n² − 1)
      */
     return 1 - 6 * $∑d² / $n⟮n² − 1⟯;
 }
Beispiel #8
0
 /**
  * Infinity norm (‖A‖∞)
  * Maximum absolute row sum of the matrix
  *
  * @return number
  */
 public function infinityNorm()
 {
     $m = $this->m;
     $‖A‖∞ = array_sum(Map\Single::abs($this->A[0]));
     for ($i = 1; $i < $m; $i++) {
         $‖A‖∞ = max($‖A‖∞, array_sum(Map\Single::abs($this->A[$i])));
     }
     return $‖A‖∞;
 }
Beispiel #9
0
 /**
  * Max norm (infinity norm) (|x|∞)
  *
  * |x|∞ = max |x|
  *
  * @return number
  */
 public function maxNorm()
 {
     return max(Map\Single::abs($this->A));
 }