JavaScriptで配列の中央値を求める方法8選

JavaScriptで配列の中央値を求める方法JS
この記事は約23分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればサンプルコードを活用して機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

●中央値とは?

中央値は、データ分析や統計処理において非常に重要な概念です。

中央値は、データセットの中心に位置する値を表します。

つまり、データを小さい順に並べたとき、ちょうど真ん中に位置する値が中央値です。

たとえば、{1, 2, 3, 4, 5}というデータセットがあった場合、中央値は3になります。

○中央値の定義と重要性

中央値は、データセットの中心的な値を表すため、データの全体的な傾向を把握するのに役立ちます。

特に、外れ値の影響を受けにくいという特徴があります。

たとえば、{1, 2, 3, 4, 100}というデータセットがあった場合、平均値は22になりますが、中央値は3のままです。

このように、中央値は極端な値の影響を受けにくいため、データの代表値としてよく使われます。

JavaScriptで中央値を求める方法を知ることは、Webアプリケーション開発において非常に重要です。

たとえば、ユーザーの行動データを分析する際、中央値を使ってユーザーの典型的な行動パターンを把握することができます。

また、異常値の検出にも中央値が役立ちます。

○中央値と平均値の違い

中央値と平均値は、どちらもデータの代表値を表す指標ですが、その性質は異なります。

平均値は、データの合計をデータの個数で割ったものです。

たとえば、{1, 2, 3, 4, 5}というデータセットの平均値は、(1 + 2 + 3 + 4 + 5) ÷ 5 = 3になります。

一方、中央値は、データを小さい順に並べたときの中心に位置する値です。

平均値は、データの全体的な傾向を表すのに適していますが、外れ値の影響を受けやすいという欠点があります。

たとえば、{1, 2, 3, 4, 100}というデータセットの平均値は、(1 + 2 + 3 + 4 + 100) ÷ 5 = 22になります。

この場合、平均値は100という極端な値の影響を大きく受けています。

一方、中央値は外れ値の影響を受けにくいため、データの代表値としてより適している場合があります。

特に、所得分布のような歪んだデータを扱う際には、中央値の方が適しています。

●ソートとインデックス計算を使った中央値の求め方

JavaScriptで中央値を求める最もシンプルな方法は、配列をソートし、インデックス計算を使って中央値を求める方法です。

この方法は、初心者にもわかりやすく、実装も簡単です。

○ソートとインデックス計算のアルゴリズム

ソートとインデックス計算を使って中央値を求めるアルゴリズムは次のようになります。

  1. 配列を昇順にソートする
  2. 配列の長さが奇数の場合、中央のインデックスの要素が中央値
  3. 配列の長さが偶数の場合、中央の2つのインデックスの要素の平均が中央値

たとえば、{1, 2, 3, 4, 5}という配列があった場合、ソート後の配列は{1, 2, 3, 4, 5}になります。

配列の長さは5(奇数)なので、中央のインデックス2の要素である3が中央値になります。

一方、{1, 2, 3, 4, 5, 6}という配列があった場合、ソート後の配列は{1, 2, 3, 4, 5, 6}になります。

配列の長さは6(偶数)なので、中央のインデックス2と3の要素である3と4の平均値3.5が中央値になります。

○サンプルコード1:配列の長さが奇数の場合

では早速、配列の長さが奇数の場合の中央値を求めるサンプルコードを見てみましょう。

function getMedian(arr) {
  // 配列を昇順にソート
  arr.sort((a, b) => a - b);

  // 中央のインデックスを計算
  const middleIndex = Math.floor(arr.length / 2);

  // 中央値を返す
  return arr[middleIndex];
}

// 使用例
const numbers = [1, 2, 3, 4, 5];
const median = getMedian(numbers);
console.log(median); // 出力: 3

このコードでは、まずsort()メソッドを使って配列を昇順にソートしています。

sort()メソッドには、比較関数(a, b) => a - bを渡すことで、数値の昇順ソートを実現しています。

次に、Math.floor()関数を使って、配列の長さを2で割った商を中央のインデックスとして計算しています。

たとえば、配列の長さが5の場合、5 / 2 = 2.5になりますが、Math.floor(2.5) = 2となり、中央のインデックスは2になります。

最後に、計算した中央のインデックスを使って、配列から中央値を取得し、返しています。

実行すると、numbers配列の中央値である3が出力されます。

○サンプルコード2:配列の長さが偶数の場合

配列の長さが偶数の場合は、中央の2つのインデックスの要素の平均を計算する必要があります。

サンプルコードを見てみましょう。

function getMedian(arr) {
  // 配列を昇順にソート
  arr.sort((a, b) => a - b);

  // 中央のインデックスを計算
  const middleIndex = Math.floor(arr.length / 2);

  // 配列の長さが偶数の場合
  if (arr.length % 2 === 0) {
    // 中央の2つの要素の平均を返す
    return (arr[middleIndex - 1] + arr[middleIndex]) / 2;
  }

  // 配列の長さが奇数の場合
  return arr[middleIndex];
}

// 使用例
const numbers = [1, 2, 3, 4, 5, 6];
const median = getMedian(numbers);
console.log(median); // 出力: 3.5

このコードでは、配列の長さが偶数の場合の処理を追加しています。

if文を使って、配列の長さを2で割った余りが0かどうかを判定しています。

配列の長さが偶数の場合、中央のインデックスとその1つ前のインデックスの要素の平均を計算し、返しています。

たとえば、配列の長さが6の場合、中央のインデックスは3になります。

中央値は、インデックス2とインデックス3の要素の平均値になるので、(arr[2] + arr[3]) / 2を返しています。

実行すると、numbers配列の中央値である3.5が出力されます。

●reduce()メソッドを使った中央値の求め方

JavaScriptの配列には、reduce()メソッドという強力なメソッドがあります。

reduce()メソッドを使うと、配列の要素を1つの値に集約することができます。

この特性を利用して、中央値を求めることができるんです。

○reduce()メソッドの使い方

reduce()メソッドは、配列の各要素に対して、指定したコールバック関数を実行し、単一の値を生成します。

コールバック関数には、アキュムレータ(累積値)、現在の要素、現在のインデックス、元の配列の4つの引数が渡されます。

reduce()メソッドの構文は次のようになります。

arr.reduce(callback[, initialValue])

callbackは、配列の各要素に対して実行されるコールバック関数です。

initialValueは、アキュムレータの初期値を指定するオプションの引数です。

たとえば、配列の合計値を求める場合は、次のように記述できます。

const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue);
console.log(sum); // 出力: 15

このコードでは、reduce()メソッドのコールバック関数で、アキュムレータ(accumulator)に現在の要素(currentValue)を足していくことで、配列の合計値を求めています。

○サンプルコード3:reduce()メソッドによる中央値の求め方

それでは実際に、reduce()メソッドを使って中央値を求めるサンプルコードを見てみましょう。

function getMedian(arr) {
  // 配列を昇順にソート
  const sorted = arr.sort((a, b) => a - b);

  // 配列の長さが奇数の場合
  if (sorted.length % 2 === 1) {
    return sorted[Math.floor(sorted.length / 2)];
  }

  // 配列の長さが偶数の場合
  const middleIndex = sorted.length / 2;
  return (sorted[middleIndex - 1] + sorted[middleIndex]) / 2;
}

// reduce()メソッドを使って中央値を求める
function getMedianUsingReduce(arr) {
  const { length } = arr;
  const isEven = length % 2 === 0;
  const middleIndex = Math.floor(length / 2);

  const median = arr.sort((a, b) => a - b).reduce((accumulator, currentValue, index) => {
    if (isEven && index === middleIndex - 1) {
      return (accumulator + currentValue) / 2;
    }
    if (!isEven && index === middleIndex) {
      return currentValue;
    }
    return accumulator;
  });

  return median;
}

// 使用例
const numbers = [1, 2, 3, 4, 5, 6];
const median = getMedianUsingReduce(numbers);
console.log(median); // 出力: 3.5

このコードでは、まずgetMedian()関数を定義しています。

この関数は、前述のソートとインデックス計算を使って中央値を求めます。

次に、getMedianUsingReduce()関数を定義しています。

この関数では、reduce()メソッドを使って中央値を求めています。

reduce()メソッドのコールバック関数では、配列の長さが偶数の場合と奇数の場合で処理を分けています。

配列の長さが偶数の場合、中央のインデックスとその1つ前のインデックスの要素の平均を計算し、アキュムレータ(accumulator)に設定しています。

配列の長さが奇数の場合、中央のインデックスの要素をアキュムレータ(accumulator)に設定しています。

最後に、アキュムレータ(accumulator)の値を中央値として返しています。

実行すると、numbers配列の中央値である3.5が出力されます。

reduce()メソッドを使った方法は、配列をソートする必要があるため、計算量はO(n log n)になります。

しかし、reduce()メソッドを使うことで、コードがシンプルになり、可読性が向上するメリットがあります。

特に、配列の長さが奇数の場合と偶数の場合で処理を分ける必要がなくなるため、コードがすっきりします。

●Math.medianを使った中央値の求め方

JavaScriptには、中央値を求めるための組み込み関数であるMath.medianがあります。

Math.medianを使うと、簡単に配列の中央値を求めることができるんです。

○Math.medianの使い方

Math.medianは、数値の配列を引数として受け取り、その配列の中央値を返します。

使い方はとてもシンプルです。

Math.median([1, 2, 3, 4, 5]); // 返り値: 3
Math.median([1, 2, 3, 4, 5, 6]); // 返り値: 3.5

配列の長さが奇数の場合は、中央のインデックスの要素が中央値として返されます。

配列の長さが偶数の場合は、中央の2つのインデックスの要素の平均値が中央値として返されます。

Math.medianを使うことで、ソートやインデックス計算を自分で実装する必要がなくなり、コードがすっきりします。

特に、配列の長さが奇数の場合と偶数の場合で処理を分ける必要がないのは大きなメリットですね。

○サンプルコード4:Math.medianによる中央値の求め方

それでは実際に、Math.medianを使って中央値を求めるサンプルコードを見てみましょう。

// Math.medianを使って中央値を求める
function getMedianUsingMathMedian(arr) {
  return Math.median(arr);
}

// 使用例
const numbers = [1, 2, 3, 4, 5, 6];
const median = getMedianUsingMathMedian(numbers);
console.log(median); // 出力: 3.5

このコードでは、getMedianUsingMathMedian()関数を定義しています。

この関数では、単純にMath.medianに配列を渡して中央値を求めています。

実行すると、numbers配列の中央値である3.5が出力されます。

Math.medianを使った方法は、非常にシンプルで使いやすいですね。

ソートやインデックス計算の実装が不要なため、コードの可読性も高くなります。

●lodashライブラリを使った中央値の求め方

JavaScriptの開発では、よく使われるユーティリティライブラリにlodashがあります。

lodashには、配列操作に関する便利なメソッドがたくさん用意されています。中央値を求めるメソッドもあります。

○lodashライブラリのインストールと使い方

lodashを使うには、まずnpmを使ってインストールする必要があります。

ターミナルで次のコマンドを実行しましょう。

npm install lodash

インストールが完了したら、JavaScriptファイルでlodashをインポートします。

const _ = require('lodash');

これで、_というオブジェクトを通じて、lodashの機能を使えるようになります。

○サンプルコード5:lodashライブラリによる中央値の求め方

それでは実際に、lodashを使って中央値を求めるサンプルコードを見てみましょう。

const _ = require('lodash');

// lodashを使って中央値を求める
function getMedianUsingLodash(arr) {
  return _.median(arr);
}

// 使用例
const numbers = [1, 2, 3, 4, 5, 6];
const median = getMedianUsingLodash(numbers);
console.log(median); // 出力: 3.5

このコードでは、getMedianUsingLodash()関数を定義しています。

この関数では、lodashの_.median()メソッドを使って中央値を求めています。

実行すると、numbers配列の中央値である3.5が出力されます。

lodashの_.median()メソッドは、内部的にはソートとインデックス計算を行っているため、計算量はO(n log n)になります。

しかし、コードがシンプルで読みやすいのが大きなメリットです。

●中央値を求める際のよくあるエラーと対処法

JavaScriptで中央値を求めるときには、いくつか注意点があります。

エラーが発生すると、思わぬ結果になったり、プログラムが止まったりすることがあります。

ただ、後述のよくあるエラーを知っておけば、適切に対処できるようになります。

○配列が空の場合のエラーと対処法

中央値を求めるときに、配列が空だとエラーになることがあります。

たとえば、次のようなコードを実行すると、エラーが発生します。

const numbers = [];
const median = numbers.sort((a, b) => a - b)[Math.floor(numbers.length / 2)];
console.log(median); // エラー: TypeError: Cannot read property 'sort' of undefined

このエラーは、配列が空の場合にsort()メソッドを呼び出そうとしているために発生します。

エラーを防ぐには、配列が空かどうかを事前にチェックする必要があります。

次のように、if文を使って配列の長さが0かどうかを判定しましょう。

function getMedian(arr) {
  if (arr.length === 0) {
    return null; // 配列が空の場合はnullを返す
  }

  const sorted = [...arr].sort((a, b) => a - b);
  const middleIndex = Math.floor(sorted.length / 2);

  if (sorted.length % 2 === 0) {
    return (sorted[middleIndex - 1] + sorted[middleIndex]) / 2;
  }

  return sorted[middleIndex];
}

// 使用例
const numbers = [];
const median = getMedian(numbers);
console.log(median); // 出力: null

このgetMedian()関数では、まず配列の長さが0かどうかを判定しています。

配列が空の場合は、nullを返すようにしています。

これで、エラーを防ぎつつ、配列が空であることを示すことができます。

○配列の要素が数値以外の場合のエラーと対処法

中央値を求めるときには、配列の要素が数値であることを前提としています。

しかし、実際には文字列やundefinedなどの数値以外の要素が混ざっていることがあります。

たとえば、次のようなコードを実行すると、意図しない結果になります。

const numbers = [1, 2, 'three', 4, 5];
const median = numbers.sort((a, b) => a - b)[Math.floor(numbers.length / 2)];
console.log(median); // 出力: NaN

この場合、'three'という文字列が配列に含まれているため、sort()メソッドで数値としてソートできません。

その結果、NaN(Not a Number)が返されてしまいます。

このようなエラーを防ぐには、配列の要素が数値かどうかを確認する必要があります。

typeof演算子を使って、要素の型が'number'であるかどうかを判定しましょう。

function getMedian(arr) {
  const filteredArr = arr.filter(item => typeof item === 'number');

  if (filteredArr.length === 0) {
    return null; // 数値の要素がない場合はnullを返す
  }

  const sorted = [...filteredArr].sort((a, b) => a - b);
  const middleIndex = Math.floor(sorted.length / 2);

  if (sorted.length % 2 === 0) {
    return (sorted[middleIndex - 1] + sorted[middleIndex]) / 2;
  }

  return sorted[middleIndex];
}

// 使用例
const numbers = [1, 2, 'three', 4, 5];
const median = getMedian(numbers);
console.log(median); // 出力: 3

このgetMedian()関数では、まずfilter()メソッドを使って、配列から数値の要素だけを抽出しています。

typeof item === 'number'という条件式で、要素の型が'number'であるかどうかを判定しています。

抽出した数値の要素からなる配列filteredArrの長さが0の場合は、nullを返すようにしています。

これは、配列に数値の要素がない場合を表しています。

その後は、filteredArrを使って中央値を求める処理を行っています。

これで、数値以外の要素を無視して、正しく中央値を計算することができます。

●中央値を使ったデータ分析の応用例

中央値は、データ分析や統計処理において非常に有用な指標です。

外れ値の影響を受けにくいため、データの全体的な傾向を把握するのに適しています。

JavaScriptで中央値を求める方法を学んだら、実際のデータ分析に応用してみましょう。

○サンプルコード6:データの中央値を使った外れ値の検出

データ分析では、外れ値(異常値)の検出が重要なタスクの1つです。

外れ値は、データの全体的な傾向から大きく外れた値のことを指します。

中央値を使うと、外れ値を検出することができます。

サンプルコードを見てみましょう。

function detectOutliers(data) {
  const median = getMedian(data);
  const lowerQuartile = getMedian(data.filter(value => value <= median));
  const upperQuartile = getMedian(data.filter(value => value >= median));
  const interQuartileRange = upperQuartile - lowerQuartile;

  const lowerThreshold = lowerQuartile - 1.5 * interQuartileRange;
  const upperThreshold = upperQuartile + 1.5 * interQuartileRange;

  const outliers = data.filter(value => value < lowerThreshold || value > upperThreshold);

  return outliers;
}

// 使用例
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100];
const outliers = detectOutliers(data);
console.log(outliers); // 出力: [100]

このdetectOutliers()関数では、中央値を使って外れ値を検出しています。

まず、getMedian()関数を使ってデータ全体の中央値を求めます。

次に、中央値以下のデータと中央値以上のデータに分けて、それぞれの中央値(第1四分位数と第3四分位数)を求めます。

第1四分位数と第3四分位数の差を計算し、それを「四分位範囲」と呼びます。

外れ値は、第1四分位数から四分位範囲の1.5倍を引いた値よりも小さい値、または第3四分位数に四分位範囲の1.5倍を足した値よりも大きい値として定義されます。

最後に、filter()メソッドを使って、外れ値に該当するデータを抽出し、outliers配列として返します。

実行すると、data配列から外れ値である100が検出され、outliers配列に格納されます。

このように、中央値を使うことで、データの外れ値を検出することができます。

外れ値の検出は、データクレンジングやデータの前処理において重要な役割を果たします。

○サンプルコード7:複数のデータセットの中央値を比較する

複数のデータセットがある場合、それぞれのデータセットの中央値を比較することで、データの分布の違いを把握することができます。

サンプルコードを見てみましょう。

function compareMedians(dataset1, dataset2) {
  const median1 = getMedian(dataset1);
  const median2 = getMedian(dataset2);

  if (median1 === median2) {
    console.log('両データセットの中央値は等しいです');
  } else if (median1 < median2) {
    console.log('データセット1の中央値はデータセット2の中央値よりも小さいです');
  } else {
    console.log('データセット1の中央値はデータセット2の中央値よりも大きいです');
  }
}

// 使用例
const dataset1 = [1, 2, 3, 4, 5];
const dataset2 = [3, 4, 5, 6, 7];
compareMedians(dataset1, dataset2);
// 出力: データセット1の中央値はデータセット2の中央値よりも小さいです

このcompareMedians()関数では、2つのデータセットdataset1dataset2の中央値を比較しています。

まず、getMedian()関数を使って、それぞれのデータセットの中央値median1median2を求めます。

次に、if文を使って中央値を比較し、結果に応じたメッセージを出力します。

中央値が等しい場合は「両データセットの中央値は等しいです」、dataset1の中央値がdataset2の中央値よりも小さい場合は「データセット1の中央値はデータセット2の中央値よりも小さいです」、そうでない場合は「データセット1の中央値はデータセット2の中央値よりも大きいです」と出力します。

実行すると、dataset1の中央値(3)がdataset2の中央値(5)よりも小さいため、「データセット1の中央値はデータセット2の中央値よりも小さいです」というメッセージが出力されます。

このように、複数のデータセットの中央値を比較することで、データの分布の違いを把握することができます。

たとえば、異なる条件下で収集されたデータを比較する際に、中央値の比較が役立つでしょう。

○サンプルコード8:中央値を使ったデータの正規化

データの正規化とは、データの値を一定の範囲内に収めるように変換することを指します。

中央値を使ってデータを正規化することで、外れ値の影響を軽減し、データの分布を揃えることができます。

サンプルコードを見てみましょう。

function normalizeData(data) {
  const median = getMedian(data);
  const normalizedData = data.map(value => value / median);

  return normalizedData;
}

// 使用例
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const normalizedData = normalizeData(data);
console.log(normalizedData);
// 出力: [0.2, 0.4, 0.6, 0.8, 1, 1.2, 1.4, 1.6, 1.8, 2]

このnormalizeData()関数では、中央値を使ってデータを正規化しています。

まず、getMedian()関数を使ってデータの中央値medianを求めます。

次に、map()メソッドを使って、データの各要素を中央値で割ることで正規化します。

正規化されたデータは、normalizedData配列に格納されます。

実行すると、data配列の各要素が中央値(5.5)で割られ、正規化されたデータがnormalizedData配列に格納されます。

中央値を使ったデータの正規化は、データの尺度を揃えるのに役立ちます。

たとえば、異なる単位で測定されたデータを比較する際に、中央値で正規化することで、データの分布を揃えることができます。

まとめ

この記事を通じて、JavaScriptで配列の中央値を求める方法について理解が深まったのではないでしょうか。

サンプルコードを参考に、実際にコードを書いて試してみることをおすすめします。

そうすることで、中央値の概念や求め方が身につき、実務で活用できるスキルが身につくはずです。