| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- <?php
- class Benford {
- private $array = null;
- private $benford = null;
- public function __construct($array = null) {
- if ($array !== null) $this->addArray($array);
- }
- public function addArray($array = null) {
- if ($array === null) throw new Exception("Missing parameter");
- if (!is_array($array)) throw new Exception("Bad parameter - non array");
- foreach ($array as $k => $v) $this->addItem($k, $v);
- }
- public function addItem($k = null, $v = null) {
- if (!is_int($k)) throw new Exception("Bad key value - non integer ({$k})");
- if ($k < 1) throw new Exception("Bad key value - less than 1 ({$k})");
- if (isset($this->array[$k])) throw new Exception("Key value already exists ({$k})");
- if (!is_numeric($v)) throw new Exception("Bad value - non numeric ({$v})");
- $v = round(abs($v * 100));
- if ($v == 0) return;
- $this->array[$k] = $v;
- $this->benford = null;
- }
- public static function benford($k = null) {
- if ($k === null) throw new Exception("Missing parameter");
- if (!is_int($k)) throw new Exception("Bad parameter - non integer ({$k})");
- if ($k < 1) throw new Exceptrion("Bad parameter - less than 1 ({$k})");
- return log10(1 + 1 / $k);
- }
- public function calculate($secondStep = true) {
- return $this->calculateFirstStep($secondStep);
- }
- public function calculateFirstStep($secondStep = false) {
- if ($this->array === null) return false;
- $this->benford = [];
- foreach ($this->array as $k => $v) {
- $s = (string) $v;
- $this->benford['firstStep'][$s[0]]['keys'][] = $k;
- }
- for ($k = 1; $k <= 9; $k++) {
- if (!isset($this->benford['firstStep'][$k])) $this->benford['firstStep'][$k]['keys'] = [];
- $v = $this->benford['firstStep'][$k];
- $this->benford['firstStep'][$k]['count'] = count($v['keys']);
- $this->benford['firstStep'][$k]['value'] = count($v['keys']) / count($this->array);
- $this->benford['firstStep'][$k]['norm'] = self::benford($k);
- if ($this->benford['firstStep'][$k]['correct'] = ($this->benford['firstStep'][$k]['value'] <= $this->benford['firstStep'][$k]['norm'])) {
- unset($this->benford['firstStep'][$k]['keys']);
- } elseif ($secondStep) {
- $this->calculateSecondStep($k);
- }
- }
- ksort($this->benford['firstStep']);
- return true;
- }
- public function calculateSecondStep($a = null) {
- if ($a === null) {
- if (!isset($this->benford['firstStep'])) $this->calculate(false);
- foreach ($this->benford['firstStep'] as $k => $v) {
- if (!$v['correct']) $this->_calculateSecondStep($k);
- }
- } else $this->_calculateSecondStep($a);
- }
- private function _calculateSecondStep($a) {
- if (!isset($this->benford['firstStep'][$a]['keys'])) throw new Exception("Wrong data ({$a})");
- foreach ($this->benford['firstStep'][$a]['keys'] as $k) {
- $s = (string) $this->array[$k];
- if (strlen($s) < 2) continue;
- $this->benford['secondStep'][$a][$s[1]]['keys'][] = $k;
- }
- for ($k = 0; $k <= 9; $k++) {
- if (!isset($this->benford['secondStep'][$a][$k])) $this->benford['secondStep'][$a][$k]['keys'] = [];
- $v = $this->benford['secondStep'][$a][$k];
- $this->benford['secondStep'][$a][$k]['count'] = count($v['keys']);
- $this->benford['secondStep'][$a][$k]['value'] = count($v['keys']) / count($this->array);
- $this->benford['secondStep'][$a][$k]['norm'] = self::benford($a * 10 + $k);
- if ($this->benford['secondStep'][$a][$k]['correct'] = ($this->benford['secondStep'][$a][$k]['value'] <= $this->benford['secondStep'][$a][$k]['norm'])) {
- unset($this->benford['secondStep'][$a][$k]['keys']);
- }
- }
- ksort($this->benford['secondStep'][$a]);
- }
- private function getResult($type = null, $k = null) {
- if ($type === null) throw new Exception("Wrong usage");
- if ($this->benford === null) $this->calculateFirstStep();
- switch ($type) {
- case 'all':
- case 'secondStep':
- if (!isset($this->benford['secondStep'])) $this->calculateSecondStep();
- case 'firstStep':
- if ($type == 'all') return $this->benford;
- else return $this->benford[$type];
- case 'secondStepItem':
- if ($k === null) throw new Exception("Missing parameter");
- if (!is_int($k)) throw new Exception("Bad parameter - not integer ({$k})");
- if ($k < 1 || $k > 9) throw new Exception("Bad parameter - not between 1 and 9 ({$k})");
- if (!isset($this->benford['secondStep'][$k])) throw new Exception("Wrong data");
- return $this->benford['secondStep'][$k];
- case 'badFirstStep':
- return array_keys(array_filter($this->benford['firstStep'], function($v) {
- if (!$v['correct']) return true;
- }));
- default: throw new Exception('Wrong usage');
- }
- }
- public function getAllResult() {
- return $this->getResult('all');
- }
- public function getFirstStep() {
- return $this->getResult('firstStep');
- }
- public function getSecondStep() {
- return $this->getResult('secondStep');
- }
- public function getSecondStepItem($k = null) {
- return $this->getResult('secondStepItem', $k);
- }
- public function getBadFirstStep() {
- return $this->getResult('badFirstStep');
- }
- }
|