核心規則:如何不出錯地找出數據集的中位數
要找出數據集的中位數,請將所有數值依升序排列並鎖定中間值。若觀測值數量 n 為奇數,中位數位於第 (n+1)/2 位。若 n 為偶數,則取兩個中間位數(第 n/2 位與第 n/2+1 位)的算術平均數。這單一規則支撐了你會執行的每一次中位數計算,從五年級的小考到 PB 級點擊流分析。
當我第一次提取一週的電商結帳延遲資料要向利害關係人報告時,我以為中位數只是簡單的複製貼上。我們的原始匯出資料有 14,392 列,未排序,且包含來自機器人點擊的重複 0.00 項目,以及時鐘偏移造成的負偏移。我貼到試算表中,按下排序,卻不小心把標題列留在選取範圍內。「中位數」因此偏移了 40 毫秒——足以觸發錯誤的效能警示。公式是對的;資料準備才是問題所在。
關於中位數,沒人告訴你的是,它是一個位置統計量,而非算術統計量。它不在乎數值之間的距離。在排序清單 [1, 2, 1000] 中,中位數是 2。單一十億級離群值會讓平均數偏移數百萬,但中位數卻紋風不動。正因如此,NIST 工程統計手冊將中位數歸類為具有 50% 崩潰點的穩健估計量。
幾何上,中位數是將有序資料分成兩個等面積半部的點。若繪製累積分布函數,中位數是 F(x)=0.5 的第 50 百分位數。這個觀點有助於處理分組資料或連續分布。
讓我們用一組小而雜亂的每日活躍使用者資料來具體說明核心步驟:[12, 30, 5, 30, 12, 30, 8]。首先,排序:[5, 8, 12, 12, 30, 30, 30]。這裡 n=7(奇數),所以中位數 = 第 (7+1)/2 = 4 位 → 值 12。再加入一天的 40 位使用者:n=8(偶數)。排序後:[5,8,12,12,30,30,30,40]。中間位數是第 4 和第 5 位(值 12 和 30)。中位數 = (12+30)/2 = 21。注意 21 從未出現在原始資料中——這是新手常感到驚訝的地方。
若你自行撰寫函數,請記住數學使用 1 為基底的排名,而 Python 等程式語言使用 0 為基底的索引。當你把 (n+1)/2 轉譯成程式碼時,差一錯誤很容易悄悄出現。邊緣情況:空資料集沒有中位數;統計函式庫會回傳 NaN 或拋出錯誤。單一值資料集的中位數就是該值。若要對乾淨清單進行快速合理性檢查,我們的中位數計算器會立即回傳正確值,但在信任任何自動化處理生產資料之前,請先了解其運作機制。
處理雜亂的真實世界資料:未排序、重複、負數、小數
競爭對手的文章止步於整齊的整數清單。在實務中,你會遇到雜訊。以下是當資料集反擊時,中位數的行為。
未排序資料與排序陷阱
真實匯出資料從不預先排序。來自帳單系統的 CSV 或沒有明確 ORDER BY 的 SQL 查詢會產生任意順序。你必須先排序才能定位中間值。在 Python 中,sorted(raw_list) 是安全的;在 Excel 中,請明確排序該欄並確認標題列已排除。我曾除錯一份月度報告,其中「中位數」是在視覺上已排序的工作表上計算的,但底層篩選器壞了——公式參照了未排序的儲存格,靜默地回報了偏差 15% 的值。
命令列工具如 sort -n 能有效率地處理數百萬行。對於 500 MB 的存取日誌,我透過 awk 提取欄位,再 sort -n,然後 sed 選取中間行。這避免了載入 RAM,並在筆電上於一分鐘內完成。
重複值與並列
重複值是合法的觀測值,不是需要清除的錯誤。若你的資料集是 [3,3,3,3,3],中位數是 3。位置公式仍然適用;重複值只是佔據連續的排名。最常見的誤解是你應該先「去重」清單。這樣會剝奪頻率資訊,並使中位數偏向稀有值。例如,調查評分 [5,5,5,1,1] 的中位數是 5。若你去重為 [1,5],中位數變成 3——這是虛構的。
在機率術語中,多重集合的經驗中位數會以每個相異值的計數加權。將資料視為集合而非多重集合會改變底層分布。這個錯誤在樸素的 SQL SELECT DISTINCT 前置處理中很常見。我記得 2019 年的一次日誌分析中,移除重複值人為地將中位數頁面載入時間降低了 0.4 秒,因為機器人產生了重複的 0.1 秒點擊。「改善後」的中位數在副總的儀表板上看起來很棒,但在統計上無效。修正方法是按工作階段計數加權,而非去重。
負數與小數
負數排序在零的左側;小數遵循標準浮點數排序。溫度資料集 -5.2、-1.0、0.3、2.8 的中位數介於 -1.0 和 0.3 之間 → -0.35。實務者常忽略浮點數捨入可能讓兩個看似相等的值在小數點後第十位有所不同;排序演算法能處理,但人眼不行。此外,無效的負數(例如時鐘偏移產生的 -0.01 秒延遲)應視為遺失資料,而非排序為真正的負數——這是一個會偏移中位數的取捨,必須記錄在案。
金融資料集常包含負值(損失、退款)。正確排序至關重要:-$200 小於 -$10。我分析過一個信用帳本,中位數退款為 -$45,表示半數退款的幅度更大。若以文字排序(’-$200′ 對 ‘-$10’)會把 -$200 放在 -$10 之後,翻轉中位數符號。排序前務必轉換為數值型別。
大型資料集(n > 1000)
當 n 很大時,手動計數不可能。使用直方圖、資料庫函數或串流近似。對於 120 萬筆共乘距離,我使用了 t-digest 草圖,因為載入所有點到記憶體成本高昂。精確中位數需要完整排序;近似中位數在 0.1 英里內——對儀表板足夠,但不足以處理帳單爭議。要知道何時需要精確性,何時 99% 信賴區間的估計已足夠。
現代函式庫使用 introselect(中位數之中位數變體)在 O(n) 平均時間內找到中位數,無需完整排序。對於 1000 萬個浮點數,numpy.median 在我的工作站上花了 0.8 秒;樸素的 Timsort 再索引花了 2.1 秒。差異在夜間批次作業中會累積。
分組與頻率表資料:你很少見到的中位數公式
教科書顯示原始清單;現實常給出區間分組。家庭收入、年齡層或回應時間區間以頻率表呈現。你無法恢復確切值,但可以透過內插估計中位數。
分組中位數公式為:中位數 = L + [ (n/2 – CF) / f ] × w,其中 L 是中位數組的下限,n 是總頻率,CF 是中位數組之前的累積頻率,f 是中位數組的頻率,w 是組距。
類別區間的實際範例
100人の従業員を想定し、給与階級: 20k-30k(15人)、30k-40k(25人)、40k-50k(30人)、50k-60k(20人)、60k-70k(10人)。n/2 = 50。累積度数: 15、40、70。中央値階級は40k-50kで、50は40の後かつ70の前にあるためです。L=40,000、CF=40、f=30、w=10,000。中央値 = 40,000 + [(50-40)/30]×10,000 = 40,000 + 3,333 = 43,333。これは推定値であり、正確な値ではありません。
隠れた前提と開放端の階級
ほとんどの人は、グループ化された中央値が中央値階級内の一様分布を仮定していることに気づいていません。階級が歪んでいる場合、推定値はずれます。「70k+」のような開放端の区間は、wが不明なため公式が使えません。実際には、そのような階級を妥当な中点で上限を設定し、その仮定を脚注に記載するか、できれば生データを要求します。政策分析では、常に補間方法を明記してください。
小数幅の階級と2つ目の例
応答時間が0.0-0.1秒(12件)、0.1-0.2秒(30件)、0.2-0.3秒(8件)に階級化されているとします。n=50、n/2=25。累積: 12、42。中央値階級は0.1-0.2。L=0.1、CF=12、f=30、w=0.1。中央値 = 0.1 + [(25-12)/30]×0.1 = 0.1 + 0.0433 = 0.1433秒。この推定値は、コスト削減のため正確なログが削除されたCDNの調整判断に役立ちました。
ツールベースの方法: コピーして使えるExcel、Python、SQLスニペット
手動ソートは大規模データには不向きです。日常分析で使う実績あるスニペットを紹介します。
ExcelとGoogle Sheets
=MEDIAN(A1:A100)を使用します。テキストや空白は無視されます。ただし、下に行を追加しても、テーブルや動的配列(=MEDIAN(A:A)など)を使わない限り、範囲は自動拡張されません(巨大な列では遅い)。微妙な落とし穴: MEDIANは非表示行を含みます。SUBTOTALとは異なります。フィルタリングされたシートで中央値を計算し、抑制された行を数えていたことに気づかず、8%の誤差が出たことがあります。Google Sheetsも同様に動作し、両方とも表示結果を丸めるため、スライドにコピーする前にセルの書式を確認してください。
Python
標準ライブラリまたはnumpyをインポートします。statistics.median([3,1,2])は2を返します。10万件以上の配列では、numpy.median(np_array)は完全なソートではなくパーティション選択を使用するため、数秒節約できます。Pandasでは: df['latency'].median()。アウトオブコアデータでは、Daskのdask.dataframe.median()がパーティション間で近似値を計算します。注意点: statistics.medianは空の入力でStatisticsErrorを発生させますが、numpy.medianは空の配列でNaNを返します。ライブラリの仕様を理解しておいてください。
コード例:
import numpy as np
data = np.array([0.12, 0.05, 0.2, 0.15, 0.05])
print(np.median(np.sort(data))) # 明確にするための明示的ソート
SQL方言
PostgreSQLとOracleはPERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY column)をサポートしており、偶数nの場合に中央の2行を正しく平均します。MySQL 8+はAPPROX_MEDIAN()を提供します。SQLiteには組み込みの中央値関数がなく、ROW_NUMBER()を使ったウィンドウ関数と中央ランクの平均を使用します。230万行のログテーブルでは、列にbtreeインデックスがある場合、PostgreSQLの呼び出しは1.4秒で返りました。
SQLiteでは、次を使用します: SELECT AVG(value) FROM (SELECT value FROM metrics ORDER BY value LIMIT 2 OFFSET (SELECT (COUNT(*)-1)/2 FROM metrics))で奇数/偶数の処理をサブクエリで行います。冗長ですが正確です。Snowflakeでは、MEDIAN()がネイティブです。BigQueryでは、APPROX_MEDIAN()が500M行で4秒以内に返り、誤差は<0.01%でした。正確なPERCENTILE_CONTは40秒かかりました。SLAに基づいて選択してください。
外れ値耐性の重要性: 中央値と平均値の実践的な違い
中央値の強みは極端な値を無視することです。9人が$50k、1人が$5Mの収入を持つデータセットでは、平均値は約$495k、中央値は$50kです。どちらが典型的な労働者を表すでしょうか?賃金報告では、中央値は億万長者による歪みを避けます。総給与が重要な容量計画では、平均値が適切なツールです。
NISTハンドブックによると、ロバスト性は破壊点で定量化されます: 中央値は50%、平均値は0%です。中央値が失敗する前にデータセットの半分を破壊できますが、1つの不良行で平均値は台無しになります。政府機関は歪んだ分布に中央値を選ぶことがよくあります。米国国勢調査局は、上位所得者に引っ張られて中流階級の傾向を隠すため、平均値ではなく中央値の世帯収入を報告しています。
もう1つのニュアンス: 中央値は常に「正確」とは限りません。データ生成プロセスが対称で軽い裾の場合(例: 較正されたセンサーからの測定誤差)、平均値は分散が低く、統計的に好ましいです。ロバスト性は効率を犠牲にします。コードを書かずに高速な生リストチェックが必要な場合は、中央値計算機がここで説明したように外れ値と重複を正確に処理します。
よくある落とし穴チェックリスト: 実際の分析で何が問題になるか
キャリア初期に、インデックスに整数除算を使ったPythonスクリプトをリリースしました: len(l)//2で偶数/奇数を別々に処理しませんでした。4項目の偶数リストで、中央左の要素だけを取得し、中心傾向を5%過小評価しました。同僚がコードレビューで気づきました。現在は、データセットが制約のあるマイクロコントローラに埋め込まれていない限り、ライブラリ関数を使用します。
- 偶数nでのオフバイワン: n/2とn/2+1の位置を平均するべきで、n/2とn/2-1ではありません。本番Javaコードでこのバグを見たことがあります。
- 範囲にヘッダー行を含める: ラベルを含めるとnが1増え、中央値がずれます。特に小規模サンプルで顕著です。
- アルファベット順のソート: テキスト列は’10’を’2’より前にソートし、順序が間違います。最初に数値にキャストしてください。
- 重複の削除: 頻度の重みを失い、まれなイベントに結果が偏ります。
- 中央値がデータセットにあると仮定: 偶数nでは、2つの値の間の補間であることが多く、観測値ではありません。
- グループ化公式の誤用: 生リストのロジックをビン化テーブルに適用すると無意味です。補間公式を使用してください。
- Excelの非表示行を無視: SUBTOTALを使わない限り、MEDIANはフィルタリングされたデータを数えます。
- ロケールの小数点区切り: Excelは米国ロケールで0,5をテキストとして解析し、ソートを壊す可能性があります。
ほとんどのアナリストは、数学自体よりも汚れた入力に時間を費やします。計算前にソート順、型、範囲を検証してください。
実用的な平均値と中央値の決定マトリックス
間違った中心傾向を選ぶと、ステークホルダーを誤解させる可能性があります。このマトリックスを現場のルールとして使用してください:
| 条件 | 中央値を使用 | 平均値を使用 |
|---|---|---|
| 重度の外れ値または歪んだ分布 | はい | いいえ |
| 合計または予算が必要 | いいえ | はい |
| 順序データ(評価、ランク) | はい | いいえ |
| ほぼ対称で極端な値なし | どちらでも | どちらでも |
| グループ化されたビンのみ、生データなし | 公式で推定 | 信頼できない |
この流れに従ってください: (1) データは順序ですか?→ 中央値。 (2) 比率スケールで極端な裾がありますか?→ 中央値。 (3) 合計が必要ですか?→ 平均値。 (4) ビンのみ利用可能ですか?→ グループ化中央値。このマトリックスは、1つの豪邸によって歪んだ平均住宅価格を「典型的」として提示するという、クライアント会議で信頼を損なうミスから私を救ってくれました。
具体的なフローチャート: 開始 → データは順序か? はい → 中央値。 いいえ → 対称か? はい → どちらでも。 いいえ → 外れ値か? はい → 中央値。 いいえ → 合計が必要か? はい → 平均値。この4つの質問ツリーは、私が遭遇するケースの90%を解決します。バイモーダルな給与データセット(例: ジュニアとシニアのクラスター)では、中央値がモード間の谷に落ち、実際の従業員を表さないことがあります。これは競合他社が言及しない限界です。報告前に可視化してください。
中央値は万能薬ではない。それは大きさの情報を捨て去り、二峰性の分布を隠してしまうことがある。常にヒストグラムや四分位数と組み合わせること。実際には、データセットが十分に大きい場合は平均値と中央値の両方を報告すること。その差は、どの単一の数値よりも歪みを示すシグナルとなる。
