Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 5 |
CRAP | |
0.00% |
0 / 140 |
| ParetoAbc | |
0.00% |
0 / 1 |
|
0.00% |
0 / 5 |
1406.00 | |
0.00% |
0 / 140 |
| deduceIntento | |
0.00% |
0 / 1 |
132.00 | |
0.00% |
0 / 41 |
|||
| deduce | |
0.00% |
0 / 1 |
110.00 | |
0.00% |
0 / 33 |
|||
| byValue | |
0.00% |
0 / 1 |
72.00 | |
0.00% |
0 / 30 |
|||
| byNumberOfItems | |
0.00% |
0 / 1 |
42.00 | |
0.00% |
0 / 32 |
|||
| array_key_last | |
0.00% |
0 / 1 |
6.00 | |
0.00% |
0 / 4 |
|||
| <?php | |
| namespace ia\Lib; | |
| class ParetoAbc { | |
| public static function deduceIntento($products, $levels = ['A','B','C']) { | |
| if(empty($products) || empty($levels)) { | |
| return []; | |
| } | |
| arsort($products, SORT_NUMERIC); | |
| echo "<pre>prod = ".print_r($products, true); | |
| $run = 0; | |
| foreach($products as $productId => $value) { | |
| $run += $value; | |
| $acc[$productId] = $run; | |
| } | |
| echo "<pre>acc = ".print_r($acc, true); | |
| foreach($acc as $productId => $value) { | |
| //@TODO que hacer en valores negativos ? aceptar, pasar a cero, abs, rechazar? | |
| if(isset($valuePrev)) { | |
| $diff[$productId] = abs($valuePrev - $value); | |
| } else { | |
| $diff[$productId] = 0; | |
| } | |
| $valuePrev = $value; | |
| } | |
| arsort($diff, SORT_NUMERIC); | |
| $topInflection = array_slice($diff, 0, count($levels)-1, true); | |
| echo "<pre>diff = ".print_r($diff, true); | |
| echo "<pre>topf = ".print_r($topInflection, true); | |
| foreach($levels as $levelKey) { | |
| $levelValue[$levelKey] = 0.00; | |
| $productsPerLevel[$levelKey] = []; | |
| } | |
| $levelsClone = $levels; | |
| $currentKey = array_shift($levelsClone); | |
| foreach($products as $productId => $value) { | |
| if(!empty($levelsClone) && array_key_exists($productId, $topInflection)) { | |
| $currentKey = array_shift($levelsClone); | |
| } | |
| $productsPerLevel[$currentKey][] = $productId; | |
| $levelValue[$currentKey] += $value; | |
| } | |
| $sumProducts = array_sum($products); | |
| $countProducts = count($products); | |
| foreach($levels as $levelKey) { | |
| $numItems = count($productsPerLevel[$levelKey]); | |
| $pareto[$levelKey] = [ | |
| 'percent_of_value' => $levelValue[$levelKey]/$sumProducts, | |
| 'total_value' => $levelValue[$levelKey], | |
| 'percent_of_items' => $numItems / $countProducts, | |
| 'number_of_items' => $numItems, | |
| ]; | |
| } | |
| return [ | |
| 'classified' => $productsPerLevel, | |
| 'pareto' => $pareto, | |
| 'levels' => $levels, | |
| 'totals' => ['sum' => $sumProducts, 'count' => $countProducts], | |
| ]; | |
| } | |
| public static function deduce($products, $levels = ['A','B','C']) { // no jala bien | |
| if(empty($products) || empty($levels)) { | |
| return []; | |
| } | |
| arsort($products, SORT_NUMERIC); | |
| foreach($products as $productId => $value) { | |
| //@TODO que hacer en valores negativos ? aceptar, pasar a cero, abs, rechazar? | |
| if(isset($valuePrev)) { | |
| $diff[$productId] = abs($valuePrev - $value); | |
| } else { | |
| $diff[$productId] = 0; | |
| } | |
| $valuePrev = $value; | |
| } | |
| //echo "<pre>diff = ".print_r($diff, true); | |
| arsort($diff, SORT_NUMERIC); | |
| $topInflection = array_slice($diff, 0, count($levels)-1, true); | |
| foreach($levels as $levelKey) { | |
| $levelValue[$levelKey] = 0.00; | |
| $productsPerLevel[$levelKey] = []; | |
| } | |
| $levelsClone = $levels; | |
| $currentKey = array_shift($levelsClone); | |
| foreach($products as $productId => $value) { | |
| if(!empty($levelsClone) && array_key_exists($productId, $topInflection)) { | |
| $currentKey = array_shift($levelsClone); | |
| } | |
| $productsPerLevel[$currentKey][] = $productId; | |
| $levelValue[$currentKey] += $value; | |
| } | |
| $sumProducts = array_sum($products); | |
| $countProducts = count($products); | |
| foreach($levels as $levelKey) { | |
| $numItems = count($productsPerLevel[$levelKey]); | |
| $pareto[$levelKey] = [ | |
| 'percent_of_value' => $levelValue[$levelKey]/$sumProducts, | |
| 'total_value' => $levelValue[$levelKey], | |
| 'percent_of_items' => $numItems / $countProducts, | |
| 'number_of_items' => $numItems, | |
| ]; | |
| } | |
| return [ | |
| 'classified' => $productsPerLevel, | |
| 'pareto' => $pareto, | |
| 'levels' => $levels, | |
| 'totals' => ['sum' => $sumProducts, 'count' => $countProducts], | |
| ]; | |
| } | |
| public static function byValue($products, $levels = ['A' => 0.8, 'B' => 0.15, 'C' => 0.05]) { | |
| if(empty($products) || empty($levels)) { | |
| return []; | |
| } | |
| arsort($products, SORT_NUMERIC); | |
| $sumProducts = array_sum($products); | |
| foreach($levels as $levelKey => $percent) { | |
| $limits[$levelKey] = ceil($percent * $sumProducts); | |
| } | |
| //echo "<pre>limits = ".print_r($limits, true); | |
| $limitsClone = array_reverse($limits); | |
| $currentKey = self::array_key_last($limitsClone); | |
| $levelLimit = array_pop($limitsClone); | |
| $tot = 0.00; | |
| foreach($products as $k => $value) { | |
| if( $tot >= $levelLimit && !empty($limitsClone) ) { //@TODO minimum diference to consider equal? | |
| $currentKey = self::array_key_last($limitsClone); | |
| $levelLimit = array_pop($limitsClone); | |
| $tot = 0.00; | |
| } | |
| $tot += $value; | |
| $productsPerLevel[$currentKey][$k] = $value; | |
| } | |
| $countProducts = count($products); | |
| foreach($productsPerLevel as $level => $items) { | |
| $totalItems = array_sum($items); | |
| $numberItems = count($items); | |
| $pareto[$level] = [ | |
| 'percent_of_value' => $totalItems/$sumProducts, | |
| 'total_value' => $totalItems, | |
| 'percent_of_items' => $numberItems/$countProducts, | |
| 'number_of_items' => $numberItems, | |
| ]; | |
| } | |
| return [ | |
| 'classified' => $productsPerLevel, | |
| 'pareto' => $pareto, | |
| 'levels' => $levels, | |
| 'totals' => ['sum' => $sumProducts, 'count' => $countProducts], | |
| ]; | |
| } | |
| public static function byNumberOfItems($products, $levels = ['A' => 0.2, 'B' => 0.25, 'C' => 1 - 0.2 - 0.25]) { | |
| if(empty($products) || empty($levels)) { | |
| return []; | |
| } | |
| arsort($products, SORT_NUMERIC); | |
| $sliceFrom = 0; | |
| $sumProducts = array_sum($products); | |
| $countProducts = count($products); | |
| $lastKey = self::array_key_last($levels); | |
| foreach($levels as $levelKey => $percent) { | |
| $itemsInLevel = ceil($percent * $countProducts); //@TODO ceil, floor, round? | |
| if($itemsInLevel <= 0) { | |
| $productsPerLevel[$levelKey] = ['XEO']; | |
| $pareto[$levelKey] = [ | |
| 'percent_of_value' => 0.00, | |
| 'total_value' => 0.00, | |
| 'percent_of_items' => 0.00, | |
| 'number_of_items' => $itemsInLevel, | |
| ]; | |
| } else { | |
| if($levelKey === $lastKey) { | |
| $items = array_slice($products, $sliceFrom); | |
| } else { | |
| $items = array_slice($products, $sliceFrom, $itemsInLevel); | |
| $sliceFrom += $itemsInLevel; | |
| } | |
| $productsPerLevel[$levelKey] = array_keys($items); | |
| $totalItems = array_sum($items); | |
| $numberItems = count($items); | |
| $pareto[$levelKey] = [ | |
| 'percent_of_value' => $totalItems/$sumProducts, | |
| 'total_value' => $totalItems, | |
| 'percent_of_items' => $numberItems/$countProducts, | |
| 'number_of_items' => $numberItems, | |
| ]; | |
| } | |
| } | |
| return [ | |
| 'classified' => $productsPerLevel, | |
| 'pareto' => $pareto, | |
| 'levels' => $levels, | |
| 'totals' => ['sum' => $sumProducts, 'count'=>$countProducts], | |
| ]; | |
| } | |
| private static function array_key_last($products) { | |
| if( function_exists( 'array_key_last' ) ) { | |
| return array_key_last($products); | |
| } | |
| end( $products ); | |
| return key( $products ); | |
| } | |
| } |