PHP实现正态分布的累积概率函数
在实际项目中,遇到需要正态分布算法去计算一个数值在整体的分布区间,例如:
100,90,80,70,60,50,40,30,20,10共10个数,按从高到低的顺序排序,总数的10%分布区域为极高频,总数的30%分布区域为高频,总数的40%分布区域为中频,总数的20%分布区域为低频,比如我新增一个数字88,我如何快速得到新增数字位于那个频段?以及其他数字有那些数字频段发生了变化???
代码实现(计算数值在整体分布的累计概率):
1 <?php 2 /** 3 * php 实现excel的normdist函数 4 * 5 * 使用方法: 6 $list = array(1.09,1.50,1.31,1.44); 7 $normdist = new normdist($list); 8 echo $normdist->getCdf($list[0]); 9 */ 10 class normdist { 11 12 public $list = array(); 13 public $mu; 14 public $sigma; 15 16 public function __construct($list) 17 { 18 $this->list = $list; 19 $this->mu = $this->getMu($list); // 获取平均值 20 $this->sigma = $this->getSigma($list); // 获取标准偏差 21 } 22 23 /** 24 * @name 正态分布的累积概率函数 25 * @param string|integer $value 26 * @return number 27 */ 28 public function getCdf($value) 29 { 30 $mu = $this->mu; 31 $sigma = $this->sigma; 32 $t = $value - $mu; 33 $y = 0.5 * $this->erfcc(-$t / ($sigma * sqrt(2.0))); 34 if ($y > 1.0) $y = 1.0; 35 36 return $y; 37 } 38 39 private function erfcc($x) 40 { 41 $z = abs($x); 42 $t = 1. / (1. + 0.5 * $z); 43 $r = 44 $t * exp(-$z*$z-1.26551223+ 45 $t*(1.00002368+ 46 $t*(.37409196+ 47 $t*(.09678418+ 48 $t*(-.18628806+ 49 $t*(.27886807+ 50 $t*(-1.13520398+ 51 $t*(1.48851587+ 52 $t*(-.82215223+ 53 $t*.17087277))))))))); 54 if ($x >= 0.) 55 return $r; 56 else 57 return 2 - $r; 58 } 59 60 /** 61 * @name 获取平均值 62 * @param array $list 63 * @return number 64 */ 65 private function getMu($list) 66 { 67 return array_sum($list) / count($list); 68 } 69 70 /** 71 * @name 获取标准差 72 * @param array $list 73 * @return number 74 * @beizhu 标准差 = 方差的平方根 75 */ 76 private function getSigma($list) 77 { 78 $total_var = 0; 79 foreach ($list as $v) { 80 $total_var += pow( ($v - $this->getMu($list)), 2); 81 } 82 83 return sqrt( $total_var / (count($list) - 1 )); // 这里为什么数组元素个数要减去1 84 } 85 }