How to get median and quartiles/percentiles of an array in JavaScript (or PHP)?



PHP Snippet 1:

// sort array ascending
const asc = arr => arr.sort((a, b) => a - b);

const sum = arr => arr.reduce((a, b) => a + b, 0);

const mean = arr => sum(arr) / arr.length;

// sample standard deviation
const std = (arr) => {
    const mu = mean(arr);
    const diffArr = arr.map(a => (a - mu) ** 2);
    return Math.sqrt(sum(diffArr) / (arr.length - 1));
};

const quantile = (arr, q) => {
    const sorted = asc(arr);
    const pos = (sorted.length - 1) * q;
    const base = Math.floor(pos);
    const rest = pos - base;
    if (sorted[base + 1] !== undefined) {
        return sorted[base] + rest * (sorted[base + 1] - sorted[base]);
    } else {
        return sorted[base];
    }
};

const q25 = arr => quantile(arr, .25);

const q50 = arr => quantile(arr, .50);

const q75 = arr => quantile(arr, .75);

const median = arr => q50(arr);

PHP Snippet 2:

//from https://blog.poettner.de/2011/06/09/simple-statistics-with-php/

function Median($Array) {
  return Quartile_50($Array);
}

function Quartile_25($Array) {
  return Quartile($Array, 0.25);
}

function Quartile_50($Array) {
  return Quartile($Array, 0.5);
}

function Quartile_75($Array) {
  return Quartile($Array, 0.75);
}

function Quartile($Array, $Quartile) {
  sort($Array);
  $pos = (count($Array) - 1) * $Quartile;

  $base = floor($pos);
  $rest = $pos - $base;

  if( isset($Array[$base+1]) ) {
    return $Array[$base] + $rest * ($Array[$base+1] - $Array[$base]);
  } else {
    return $Array[$base];
  }
}

function Average($Array) {
  return array_sum($Array) / count($Array);
}

function StdDev($Array) {
  if( count($Array) < 2 ) {
    return;
  }

  $avg = Average($Array);

  $sum = 0;
  foreach($Array as $value) {
    $sum += pow($value - $avg, 2);
  }

  return sqrt((1 / (count($Array) - 1)) * $sum);
}

PHP Snippet 3:

//adapted from https://blog.poettner.de/2011/06/09/simple-statistics-with-php/
function Median(data) {
  return Quartile_50(data);
}

function Quartile_25(data) {
  return Quartile(data, 0.25);
}

function Quartile_50(data) {
  return Quartile(data, 0.5);
}

function Quartile_75(data) {
  return Quartile(data, 0.75);
}

function Quartile(data, q) {
  data=Array_Sort_Numbers(data);
  var pos = ((data.length) - 1) * q;
  var base = Math.floor(pos);
  var rest = pos - base;
  if( (data[base+1]!==undefined) ) {
    return data[base] + rest * (data[base+1] - data[base]);
  } else {
    return data[base];
  }
}

function Array_Sort_Numbers(inputarray){
  return inputarray.sort(function(a, b) {
    return a - b;
  });
}

function Array_Sum(t){
   return t.reduce(function(a, b) { return a + b; }, 0); 
}

function Array_Average(data) {
  return Array_Sum(data) / data.length;
}

function Array_Stdev(tab){
   var i,j,total = 0, mean = 0, diffSqredArr = [];
   for(i=0;i<tab.length;i+=1){
       total+=tab[i];
   }
   mean = total/tab.length;
   for(j=0;j<tab.length;j+=1){
       diffSqredArr.push(Math.pow((tab[j]-mean),2));
   }
   return (Math.sqrt(diffSqredArr.reduce(function(firstEl, nextEl){
            return firstEl + nextEl;
          })/tab.length));  
}

PHP Snippet 4:

  //Credit D3: https://github.com/d3/d3-array/blob/master/LICENSE
  function quantileSorted(values, p, fnValueFrom) {
    var n = values.length;
    if (!n) {
      return;
    }

    fnValueFrom =
      Object.prototype.toString.call(fnValueFrom) == "[object Function]"
        ? fnValueFrom
        : function (x) {
            return x;
          };

    p = +p;

    if (p <= 0 || n < 2) {
      return +fnValueFrom(values[0], 0, values);
    }

    if (p >= 1) {
      return +fnValueFrom(values[n - 1], n - 1, values);
    }

    var i = (n - 1) * p,
      i0 = Math.floor(i),
      value0 = +fnValueFrom(values[i0], i0, values),
      value1 = +fnValueFrom(values[i0 + 1], i0 + 1, values);

    return value0 + (value1 - value0) * (i - i0);
  }

PHP Snippet 5:

function Quartile(data, q) {
  data=Array_Sort_Numbers(data);        // we're assuming it's already sorted, above, vs. the function use here. same difference.
  var pos = ((data.length) - 1) * q;    // i = (n - 1) * p
  var base = Math.floor(pos);           // i0 = Math.floor(i)
  var rest = pos - base;                // (i - i0);
  if( (data[base+1]!==undefined) ) {
    //      value0    + (i - i0)   * (value1 which is values[i0+1] - value0 which is values[i0])
    return data[base] + rest       * (data[base+1]                 - data[base]);
  } else {
    // I think this is covered by if (p <= 0 || n < 2)
    return data[base];
  }
}