5

I have an array that has been sorted from low to high which has over 260k values in. I have found out the mean(average) and median of the array just need to find out the mode?

I cannot use any mathematical functions that PHP has, it has to be all done manually.

I would like it so there could be just one value that is the mode but then there can be multiple values that can be the mode. I also need to be able to record the number of times that the value is stored. For example the number 51 appears 6 times so I can print both values.

This is my code so far:

$amountRecords = 0;
$totalValue = 0;
$valueArray = array();

// reads in csv file
$handle = fopen('Task1-DataForMeanMedianMode.csv', 'r');
// to skip the header names/values
fgetcsv($handle);

// creates array containing variables of csv file in ascending order
while(($row = fgetcsv($handle, "\r")) != FALSE)
{

    // if amountRecords equals 0
    if($amountRecords == 0)
    {

        // adds value from csv to array
        $valueArray[] = $row[1];

    } // else amountRecords does not equal 0
    else 
    {

        // if the value in array location before is greater than the current value from the csv file
        if($valueArray[$amountRecords - 1] > $row[1])
        {

             // the current array location becomes the one in the location before
             $valueArray[] = $valueArray[$amountRecords - 1];
             // add the value from the csv to the location before
             $valueArray[$amountRecords - 1] = $row[1];

         } // if the value in the location before is not greater than the current value in the csv file
         else 
         {

             // adds value from csv to array
             $valueArray[] = $row[1];

         }

    }

    // calculates the total value of the values in csv file
    $totalValue = $totalValue + $row[1];
    // calculates the number of values in the csv file
    $amountRecords++;

}    

// calculate average value of payments
$averageValue = $totalValue / $amountRecords;
// limit integer to 2 decimal place
$average = number_format($averageValue,2,'.','');

// finds middle value
$middle = floor(($amountRecords / 2) - 1);

// calculates the median value
// if array size is even
if($amountRecords % 2 == 0)
{

    // calculates median
    $median = $valueArray[$middle];

} 
else // if array size is odd
{

    // calculate low and high values
    $low = $valueArray[$middle];
    $high = $valueArray[$middle + 1];
    // calculates median
    $median = (($low + $high) / 2);

}

// works out mode
// creates array count
$count = array();
// for each value in the valueArray
foreach( $valueArray as $value )
{

    if( isset( $count[$value] ))
    {

        $count[$value]++;

    }
    else
    {

        $count[$value] = 1;

    }

}

$mostCommon = "";
$iter = 0;

foreach( $count as $k => $v )
{

     if( $v > $iter )
     {

         $mostCommon = $k;
         $iter = $v;

     }

}

$modeArray = array( "mode" => $mostCommon , "count" => $iter );

5 Answers5

26

The mode of a numerical set is the number that occurs the most often. You can do this with PHP using code similar to the following:

$values = array_count_values($valueArray); 
$mode = array_search(max($values), $values);
White Elephant
  • 1,361
  • 2
  • 13
  • 28
  • Like I said in my post it has to be done manually without using any mathematical functions PHP has. This includes count and max and min etc. –  Aug 20 '12 at 10:43
  • Have a go at working out the mode and then we can help you out with it. Based on the code above, it looks like you haven't even attempted it. – White Elephant Aug 20 '12 at 11:14
  • @WhiteElephant I have something but it only returns one value not multiple if there multiple. I have edited my original post with the added mode code that I have done. –  Aug 20 '12 at 11:25
  • 3
    This solution is good, but if there are more than one mode numbers, its only pick the first one of the order in the array. I am trying to get all numbers that occurs the most often, for example {2,2,3,3,1} -> I need to get 2 and 3. Can you have any other solution? Sorry for my poor English – kayla Aug 10 '15 at 12:48
  • solution with multiple modes: `$values = array_count_values($cells); asort($values); $modes = array_keys($values, max($values)); ` – 8ctopus Nov 25 '20 at 07:05
1

Simple!

$arr = array(4,6,7,1,4,7,4,7,1);
$freq = array();
for($i=0; $i<count($arr); $i++)
{
   if(isset($freq[$arr[$i]])==false)
   {
       $freq[$arr[$i]] = 1;
   }
   else
   {
       $freq[$arr[$i]]++;
   }
}
$maxs = array_keys($freq, max($freq));

for($i=0; $i<count($maxs); $i++)
{
   echo $maxs[$i] . ' ' . $freq[$maxs[$i]];
   echo '<br />';
}
Taslim A. Khan
  • 516
  • 1
  • 8
  • 26
0

Mathematical only solution:

    //sample data
$dataArr = ["1", "3", "5", "1", "3", "7", "1", "8", "1"];

//a multidimensional array to hold the keys (extracted fro above) and their values (number of occurrences)
$multiDArr = [];
for ($i = 0; $i < count($dataArr); $i++) {
    $key = $dataArr[$i];

    if (isset($multiDArr[$key])) {
        //key already exists; increment count of its value
        $multiDArr[$key] = $multiDArr[$key] + 1;
    } else {
        //key does nto exist; add it and an inital value of 1
        $multiDArr[$key] = 1;
    }
}

$highestOccuring = 0;
$highestOccuringKey = null;
foreach ($multiDArr as $key => $value) {

    if ($value > $highestOccuring) {
        $highestOccuring = $value;
        $highestOccuringKey = $key;
    }

}

echo "MODE / highest occuring key: " . $highestOccuringKey;
CodesmithX
  • 246
  • 4
  • 8
0
/** find array mode, most often see value
 * @param list(int) $a_in
 * @return list(int)
 */
function array_mode(array $a_in): array{
    $a_freq = [];
    foreach( $a_in as $v ) {
        if (!isset($a_freq[$v])) {
            $a_freq[$v] = 0;
        }
        $a_freq[$v]++;
    }
    $a_maxs = array_keys($a_freq, max($a_freq));
    return $a_maxs;
}
// test code
$a_in = [4,6,7,1,4,7,4,7,1];
array_mode( $a_in);
devsmt
  • 56
  • 1
  • 4
0

This will take values and turn it into an array of the modes. For Example: print_r(get_mode(1,2,2,3,3,3,4,4,5,5,5,6,7,8,9)); will return,

Array
(
    [0] => Array
        (
            [value] => 3
            [count] => 3
        )

    [1] => Array
        (
            [value] => 5
            [count] => 3
        )

)

code:

function get_mode(...$inputArray){
    $max=0;
    return array_reduce(
        array_values(array_reduce(array_values($inputArray),function($talliedArray,$inputNode){
            if(isset($talliedArray[(string)$inputNode])) 
                $talliedArray[(string)$inputNode]['count']++;
            else 
                $talliedArray[(string)$inputNode] = [
                    'value' => $inputNode,
                    'count' => 1
                ];
            return $talliedArray;
    },[])),function($modeArray,$talliedNode)use(&$max){
        if($talliedNode['count'] < $max) return $modeArray;
        if($talliedNode['count']=== $max) return array_merge($modeArray,[$talliedNode]);
        //if count > $max
        $max = $talliedNode['count'];
        return [$talliedNode];
    },[]);
}

This satisfies the "no math functions", the "multiple return modes" and the "have the value and number of occurrences returned".

This will only really work with strings and numbers. It will go weird with booleans, Objects and Arrays.

bad_coder
  • 11,289
  • 20
  • 44
  • 72