合計/平均/分散/中央値/etc を計算する【JavaScript】

合計

1行実装

const sumValue = array.reduce((pre, cr) => pre+cr);

簡易実装

const sum = (array) => {
  const len = array.length;
  let sum = 0
  for (let i=0; i<len; i++) {
    sum = sum + array[i];
  }
  return sum;
};

サンプル

var array = [1, 3, 5, 7, 9, 8, 6, 4, 2];
var sumValue = array.reduce((pre, cr) => pre+cr);
console.log(sumValue);          // 45
console.log(sum(array));        // 45
console.log(sum([2]));          // 2
console.log(sum([2, 3]));       // 5
console.log(sum([2, 3, 5]));    // 10

平均

1行実装

const avgValue = array.reduce((pre, cr) => pre+cr) / array.length;

簡易実装

const average = (array) => {
  const len = array.length;
  if (len === 0) { return 0; }

  let sum = 0
  for (let i=0; i<len; i++) {
    sum = sum + array[i];
  }
  return sum / len;
};

サンプル

var array = [1, 3, 5, 7, 9, 8, 6, 4, 2];
var avgValue = array.reduce((pre, cr) => pre+cr) / array.length;
console.log(avgValue);          // 5
console.log(average(array));    // 5
console.log(average([2]));      // 2
console.log(average([2, 3]));   // 2.5
console.log(average([2, 3, 5]));// 3.3333333333333335

分散

簡易実装

const variance = (array) => {
  const len = array.length;
  if (len === 0) { throw new Error('Cannot calculate variance of an empty array.'); }

  let sum = 0
  for (let i=0; i<len; i++) {
    sum = sum + array[i];
  }
  const avg = sum / len;

  let vsum = 0;
  for (let i=0; i<len; i++) {
    vsum = vsum + (array[i] - avg)**2
  }

  return vsum / len;            // 標本分散
  //return vsum / (len-1);        // 不偏分散
};

サンプル

console.log(variance([1, 2, 3]));       // 0.6666666666666666
console.log(variance([1, 5, 9]));       // 10.666666666666666
console.log(variance([9, 7, 5, 3, 1, 2, 4, 6, 8]));    // 6.666666666666667
console.log(variance([9, 7, 5, 3, 1, 0, 2, 4, 6, 8])); // 8.25

標準偏差

簡易実装

const stdev = (array, normalize) => {
  const len = array.length;
  if (len === 0) { throw new Error('Cannot calculate standard deviation of an empty array.'); }

  let sum = 0
  for (let i=0; i<len; i++) {
    sum = sum + array[i];
  }
  const avg = sum / len;

  let vsum = 0;
  for (let i=0; i<len; i++) {
    vsum = vsum + (array[i] - avg)**2
  }

  return Math.sqrt(vsum / len);         // 母集団標準偏差
  //return Math.sqrt(vsum / (len-1));     // 標本標準偏差
};

サンプル

console.log(stdev([1, 2, 3]));  // 0.816496580927726
console.log(stdev([1, 5, 9]));  // 3.265986323710904
console.log(stdev([9, 7, 5, 3, 1, 2, 4, 6, 8]));    // 2.581988897471611
console.log(stdev([9, 7, 5, 3, 1, 0, 2, 4, 6, 8])); // 2.8722813232690143

最大値

1行実装

const maxValue = array.reduce((pre, cr) => pre > cr ? pre : cr);

const maxValue = Math.max(...array);

簡易実装

const max = function(array) {
  const len = array.length;
  if (len === 0) { throw new Error('Cannot calculate min of an empty array.'); }

  let max = array[0];
  for (let i=1; i<len; i++) {
    if (max < array[i]) {
      max = array[i];
    }
  }
  return max;
};

サンプル

var array = [1, 3, 5, 7, 9, 8, 6, 4, 2];
var maxValue = array.reduce((pre, cr) => pre > cr ? pre : cr);
console.log(maxValue);          // 9
console.log(max(array));        // 9

最小値

1行実装

const minValue = array.reduce((pre, cr) => pre < cr ? pre : cr);

const minValue = Math.min(...array);

簡易実装

const min = function(array) {
  const len = array.length;
  if (len === 0) { throw new Error('Cannot calculate max of an empty array.'); }

  let min = array[0];
  for (let i=1; i<len; i++) {
    if (array[i] < min) {
      min = array[i];
    }
  }
  return min;
};

サンプル

var array = [9, 7, 5, 3, 1, 2, 4, 6, 8];
var minValue = array.reduce((pre, cr) => pre - cr < 0 ? pre : cr);
console.log(minValue);          // 1
console.log(min(array));        // 1

k番目の値

簡易実装

// see https://blog.teamleadnet.com/2012/07/quick-select-algorithm-find-kth-element.html
const selectKth = function(array, k) {
  const len = array.length;
  if (k < 0 || len <= k) { throw new Error('k is out of bounds.'); }

  let count = 0;
  let from = 0;
  let to = len - 1;
  while (from < to) {
    let r = from;
    let w = to;
    let mid = array[(r+w)/2|0];

    while (r < w) {
      if (array[r] >= mid) {
        const tmp = array[w];
        array[w] = array[r];
        array[r] = tmp;
        w--;
      } else {
        r++;
      }
    }
    if (array[r] > mid) {
      r--;
    }

    if (k <= r) {
      to = r;
    } else {
      from = r + 1;
    }
  }
  return array[k];
};
const small = function(array, k) { return selectKth(array, k); };
const large = function(array, k) { return selectKth(array, array.length-k-1); };

selectKth()は、array を不完全に並び替えます。

サンプル

console.log(small([1, 3, 5, 7, 9, 8, 6, 4, 2], 0));        // 1
console.log(small([1, 3, 5, 7, 9, 8, 6, 4, 2], 1));        // 2
console.log(small([9, 8, 7, 6, 5, 4, 3, 2, 1], 2));        // 3
console.log(small([9, 8, 7, 6, 5, 4, 3, 2, 1], 3));        // 4
console.log(small([9, 7, 5, 3, 1, 2, 4, 6, 8], 4));        // 5
console.log(small([1, 2, 3, 4, 5, 6, 7, 8, 9], 5));        // 6
console.log(small([1, 2, 3, 4, 5, 6, 7, 8, 9], 6));        // 7
console.log(small([9, 7, 5, 3, 1, 2, 4, 6, 8], 7));        // 8
console.log(small([9, 7, 5, 3, 1, 2, 4, 6, 8], 8));        // 9

console.log(large([1, 2, 3, 4, 5, 6, 7, 8, 9], 0));        // 9
console.log(large([1, 2, 3, 4, 5, 6, 7, 8, 9], 1));        // 8
console.log(large([9, 7, 5, 3, 1, 2, 4, 6, 8], 2));        // 7
console.log(large([9, 7, 5, 3, 1, 2, 4, 6, 8], 3));        // 6
console.log(large([9, 7, 5, 3, 1, 2, 4, 6, 8], 4));        // 5
console.log(large([1, 3, 5, 7, 9, 8, 6, 4, 2], 5));        // 4
console.log(large([1, 3, 5, 7, 9, 8, 6, 4, 2], 6));        // 3
console.log(large([9, 8, 7, 6, 5, 4, 3, 2, 1], 7));        // 2
console.log(large([9, 8, 7, 6, 5, 4, 3, 2, 1], 8));        // 1

中央値

簡易実装(sort()版)

const median = (array) => {
  const len = array.length;
  if (len === 0) { throw new Error('Cannot calculate median of an empty array.'); }

  array.sort((a, b) => a-b);

  if (len % 2) {
    return array[(len-1) / 2)];
  } else {
    const mid = len / 2;
    return (array[mid-1] + array[mid]) / 2;
  }
};

簡易実装(selectKth()版)

const median = (array) => {
  const len = array.length;
  if (len === 0) { throw new Error('Cannot calculate median of an empty array.'); }

  if (len % 2) {
    return selectKth(array, (len-1)/2);
  } else {
    const mid = len/2 - 1;
    const large = selectKth(array, mid+1);
    let small = array[mid];
    for (let i=0; i<mid; i++) {
      if (small < array[i]) {
        small = array[i]
      }
    }
    return (small + large) / 2;
  }
};

※完全には並び替えないため、sort()よりselectKth()の方が高速です。
selectKth()は、「k番目の値」参照

サンプル

console.log(median([2, 3]));    // 2.5
console.log(median([5, 2, 3])); // 3
console.log(median([9, 7, 5, 3, 1, 2, 4, 6, 8]));    // 5
console.log(median([9, 7, 5, 3, 1, 0, 2, 4, 6, 8])); // 4.5

参考