- 技術 💻
標準偏差の求め方と意味|n−1の違い・偏差値をPython・SQLで実演
結論
標準偏差(standard deviation・SD・σ)とは、データが平均からどれくらい散らばっているかを、元のデータと同じ単位で表した値です。求め方は「平均を出す→各値から平均を引く(偏差)→偏差を2乗して合計→個数で割る(分散)→ルートを取る」の5手順です。全部のデータなら n で、一部を抜き出した標本なら n−1 で割ります。
この記事でわかること
- 標準偏差の意味と、手計算の5ステップ(4・8・6・5・7 の例で答えは 1.414)
- n と n−1 の違いと、Python・PostgreSQL で既定が違う関数の一覧(実行結果つき)
- 平均±1σ・2σ・3σに入る割合、偏差値、外れ値の影響を自作データで実測した結果
標準偏差は「平均だけでは見えない、ばらつきの大きさ」を1つの数で表します。計算の流れを図にすると次のとおりです。
flowchart TD
A[データ x1 … xn] --> B[平均を求める]
B --> C[偏差 = 各値 − 平均]
C --> D[偏差を2乗して合計]
D --> E{全部のデータか}
E -->|母集団| F[n で割る<br>母分散]
E -->|一部の標本| G[n−1 で割る<br>不偏分散]
F --> H[ルートを取る<br>標準偏差]
G --> H
よく調べられることの答えを先にまとめます。
| やりたいこと | いちばん早い方法 | 詳しい節 |
|---|---|---|
| 標準偏差とは何かを知りたい | 平均からの散らばりの大きさ。分散のルート。記号は σ(シグマ) | 標準偏差とは |
| 標準偏差を手で求めたい | 平均→偏差→2乗→合計÷個数→ルート の5手順 | 標準偏差の求め方 |
| 分散と標準偏差の違いを知りたい | 分散は単位が2乗(cm²)。ルートを取ると元の単位(cm)に戻るのが標準偏差 | 分散と標準偏差の違い |
| n と n−1 のどちらで割るか決めたい | 全部のデータなら n、一部の標本から全体を推定するなら n−1 | 母集団と標本の違い |
| Python で標準偏差を求めたい | statistics.stdev(n−1)・np.std(既定は n)・Series.std(既定は n−1) | Pythonの節 |
| SQL で標準偏差を求めたい | PostgreSQL は stddev_pop・stddev_samp。SQLite は関数が無いので式で書く | SQLの節 |
| 偏差値を計算したい | 50 + 10 ×(得点 − 平均)÷ 標準偏差 | 偏差値の計算 |
| 2σ・3σの意味を知りたい | 正規分布なら平均±2σに約95.4%、±3σに約99.7%が入る | 平均±1σ・2σ・3σの割合 |
| 結果が他の計算と合わない | まず n と n−1 の違い(ddof)を疑う | 症状→原因→直し方 |
確認環境:Ubuntu 24.04.5 LTS(2コアの共有マシン)で、Python 3.13.18 の statistics、NumPy 2.5.3、pandas 3.0.5、SciPy 1.18.1、Python に組み込みの SQLite 3.53.1 を実行しました。PostgreSQL 16.15 は作業用のフォルダーにデータベースを作って 127.0.0.1 だけで起動し、psql 16.15 から問い合わせたあと、データベースを削除して停止しています。JavaScript は Node.js 22.23.4 で実行しました。身長・レスポンス時間・テストの点などのデータは、乱数の種(シード)を 164 に固定するか手で決めた自作のもので、実在の人や会社のデータではありません。標準偏差と偏差値の定義は総務省統計局「なるほど統計学園」、関数の仕様は Python・NumPy・pandas・SciPy・PostgreSQL・SQLite・MDN の公式ドキュメントで確かめました。表計算ソフトの関数はこの記事では扱いません。図は mermaid 11.16.0 で描画を確かめています(確認日 2026年10月29日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「標準偏差の求め方と意味|n−1の違い・偏差値をPython・SQLで実演」
標準偏差とは(意味・記号σ・読み方)
この節では、標準偏差という言葉の意味と記号、分野によって呼び方や使い方がどう変わるかが分かります。
標準偏差は、各データが平均からどれくらい離れているかを平均した「ばらつきの物差し」です。英語では standard deviation、略して SD と書き、記号はギリシャ文字の小文字 σ(シグマ)を使います。標本から求めた値は s と書くこともあります。総務省統計局の「なるほど統計学園」は、分散の正の平方根を標準偏差と呼ぶ、と説明しています。
平均だけでは、データの姿は分かりません。たとえば 3人のテストの点が 55・45・50 点でも、100・30・20 点でも、平均はどちらも 50 点です。手元で標準偏差を求めると、前者は 4.08、後者は 35.59 でした。同じ平均でも、標準偏差が大きいほど点がばらばらに散っていることが数で分かります。
import statistics as st
print(st.mean([55, 45, 50]), st.pstdev([55, 45, 50]))
print(st.mean([100, 30, 20]), st.pstdev([100, 30, 20]))
50 4.08248290463863
50 35.59026084010437
10 以上の数
全部のデータが同じ値なら 0。ばらつくほど大きくなる。マイナスにはならない。
2元と同じ単位
身長(cm)の標準偏差は cm。平均と足したり引いたりして「170±6cm」のように書ける。
3平均とセットで読む
標準偏差だけ見ても大小は判断しにくい。平均・件数・分布の形と一緒に読む。
「標準偏差」という言葉自体は同じでも、分野によって呼び方や読み方が少しずつ違います。最初に場面別に整理しておきます。
| 場面 | 呼び方・書き方 | 何を表すか |
|---|---|---|
| 統計・データ分析 | 標準偏差・SD・σ・s | データの散らばりの大きさ |
| 学校のテスト・模試 | 偏差値の元になる値 | 平均50・標準偏差10に変換するときの物差し |
| 投資・金融 | ボラティリティ・リスク | リターン(値動き)の標準偏差。大きいほど値動きが荒い |
| 品質管理・製造 | σ(シグマ)・3σ・6σ | 製品の寸法などのばらつき。管理の限界を平均±3σに置く考え方が知られている |
| 計測・実験 | 標準不確かさ・誤差棒 | 測るたびに出る値の揺れ。グラフでは平均±SDの棒で描く |
| システム監視 | stddev・ジッター | 応答時間などの揺れ。偏りが大きいデータでは p95 などと併用する |
標準偏差の求め方(手計算の5ステップ)
この節では、電卓だけで標準偏差を求める手順と、途中の数字が分かります。
例として、5人の点数 4・8・6・5・7 の標準偏差を求めます。この5人が対象の全員(母集団)だとして、n で割ります。
平均を求める
(4+8+6+5+7)÷5=30÷5=6。
偏差(各値−平均)を出す
−2・+2・0・−1・+1。偏差を足すと必ず 0 になるので、このままでは平均できない。
偏差を2乗する
4・4・0・1・1。2乗するとマイナスが消え、遠い値ほど大きく効く。
合計して個数で割る(分散)
合計は 10(偏差平方和)。10÷5=2 が分散。標本なら 10÷4=2.5。
ルートを取る(標準偏差)
√2=1.414。標本なら √2.5=1.581。電卓の √ キーで求められる。
式で書くと、標準偏差 σ = √{((x1−平均)² + (x2−平均)² + … + (xn−平均)²)÷ n}です。標本の標準偏差 s は、最後の ÷n を ÷(n−1) に替えます。途中の数字を表にすると次のとおりです。
| データ | 偏差(値−6) | 偏差の2乗 |
|---|---|---|
| 4 | −2 | 4 |
| 8 | +2 | 4 |
| 6 | 0 | 0 |
| 5 | −1 | 1 |
| 7 | +1 | 1 |
| 合計 | 0 | 10(÷5=分散2、√2=1.414) |
数が大きいときも手順は同じです。ある地域の5社の従業員数 50・35・40・33・82 人なら、平均は 48 人、偏差は 2・−13・−8・−15・34、偏差の2乗の合計は 1,618 です。分散は 1,618÷5=323.6、標準偏差は √323.6=約17.99人になります。標本として n−1 で割ると、分散 404.5、標準偏差 約20.11人です。Python で同じ手順を書いて確かめました。
import math
d = [50, 35, 40, 33, 82]
m = sum(d) / len(d)
dev = [x - m for x in d]
sq = [v * v for v in dev]
print("平均", m)
print("偏差", dev)
print("偏差の2乗", sq, "合計", sum(sq))
print("母分散", sum(sq) / 5, "母SD", math.sqrt(sum(sq) / 5))
print("標本分散", sum(sq) / 4, "標本SD", math.sqrt(sum(sq) / 4))
平均 48.0
偏差 [2.0, -13.0, -8.0, -15.0, 34.0]
偏差の2乗 [4.0, 169.0, 64.0, 225.0, 1156.0] 合計 1618.0
母分散 323.6 母SD 17.988885457415087
標本分散 404.5 標本SD 20.112185361118765
度数分布表から標準偏差を求める
元のデータが無く「60〜70点が8人」のような度数分布表しか無いときは、各階級の真ん中の値(階級値)が人数分あるとみなして計算します。階級値 45・55・65・75・85 点に 2・5・8・4・1 人(計20人)なら、平均は (45×2+55×5+65×8+75×4+85×1)÷20=63.5 点です。偏差の2乗に人数を掛けて合計し、20 で割ると分散 102.75、標準偏差は 約10.14点でした。NumPy の np.cov に人数を重み(fweights)として渡しても同じ値になります。
import math, numpy as np
cls = [45, 55, 65, 75, 85]; f = [2, 5, 8, 4, 1]
n = sum(f); m = sum(c * k for c, k in zip(cls, f)) / n
var = sum(k * (c - m) ** 2 for c, k in zip(cls, f)) / n
print("n", n, "平均", m, "分散", var, "SD", round(math.sqrt(var), 3))
print(np.sqrt(np.cov(cls, fweights=f, ddof=0)))
n 20 平均 63.5 分散 102.75 SD 10.137
10.136567466356647
階級の中で値が散らばっている分は無視されるため、元データから求めた値とは少しずれます。元データがあるなら、そちらで計算します。
分散と標準偏差の違い(ルートを取る理由)
この節では、分散と標準偏差がどう違い、なぜわざわざルートを取るのかが分かります。
分散は「偏差の2乗の平均」、標準偏差は「そのルート」です。情報としては同じものですが、分散は2乗しているため単位も2乗になります。身長(cm)の分散の単位は cm² で、平均の 170cm と足したり比べたりできません。ルートを取ると単位が cm に戻り、「平均170cm、標準偏差7cm」のように並べて読めるようになります。
手元で、5人の身長 170・165・180・175・160cm を使い、単位を変えたり全員に同じ数を足したりしたときの変化を確かめました。
import statistics as st
a = [170, 165, 180, 175, 160]
print(round(st.pstdev(a), 4), round(st.pstdev([x * 10 for x in a]), 4),
round(st.pvariance(a), 2), round(st.pvariance([x * 10 for x in a]), 2))
print("全部に+100", round(st.pstdev([x + 100 for x in a]), 4))
7.0711 70.7107 50 5000
全部に+100 7.0711
| 比べる点 | 分散 | 標準偏差 |
|---|---|---|
| 求め方 | 偏差の2乗の平均 | 分散のルート |
| 単位 | 元の単位の2乗(cm²) | 元と同じ(cm) |
| 記号 | σ²・s²・V | σ・s・SD |
| 読みやすさ | 数が大きくなり直感で読みにくい | 平均と並べて「±」で読める |
| 主な使い道 | 足し算ができる(独立な量の分散は足せる)。理論の計算・分散分析 | 報告・グラフ・偏差値・品質の管理幅 |
分散にも出番はあります。互いに関係の無い2つの量を足したとき、合計の分散は2つの分散の和になります。標準偏差は単純には足せません(3と4を足しても7にはならず、√(9+16)=5になります)。確率分布ごとの分散の公式は、関連記事「確率分布とは|種類一覧・平均と分散・選び方をPythonで実演」で扱っています。
母集団と標本の違い(n と n−1・不偏分散)
この節では、n で割る標準偏差と n−1 で割る標準偏差の違いと、どちらを使うかの決め方が分かります。
調べたい対象の全部(母集団)のデータがそろっているなら n、一部を抜き出したデータ(標本)から全体を推し量るなら n−1 で割ります。n−1 で割った分散を不偏分散と呼び、この補正をベッセルの補正と言います。Python の公式ドキュメントも、pvariance は母集団全体から計算するときに使い、標本から推定するときは通常 variance が良い、と説明しています。
n で割る(母集団の標準偏差)
クラス30人全員の点数のばらつき
今月の全注文の金額のばらつき
偏差値の計算(集団の全員で計算する)
n−1 で割る(標本の標準偏差)
全国から抜き出した500人で全国のばらつきを推定する
工場の製品から10個を抜き取って全体の品質を推定する
A/B テストや実験の結果から母集団について述べる
なぜ n−1 なのかは、実際に試すと分かります。真の分散が 36(標準偏差6)の正規分布から5個ずつ抜き出し、分散を求める作業を10万回くり返しました。
import numpy as np
rng = np.random.default_rng(164)
smp = rng.normal(0, 6, (100_000, 5))
print("÷n の平均", smp.var(axis=1, ddof=0).mean().round(3),
"÷(n-1) の平均", smp.var(axis=1, ddof=1).mean().round(3))
print("SD ddof0", smp.std(axis=1, ddof=0).mean().round(3),
"ddof1", smp.std(axis=1, ddof=1).mean().round(3))
÷n の平均 28.843 ÷(n-1) の平均 36.054
SD ddof0 5.046 ddof1 5.642
n で割った分散の平均は 28.843 で、真の 36 より約2割小さくなりました。標本の平均は標本そのものの真ん中にあるため、真の平均から測るより偏差が小さく出るからです。n−1 で割ると平均 36.054 で、ほぼ真の値になります。
一方、標準偏差は n−1 で割っても平均 5.642 で、真の 6 より小さいままでした。不偏分散のルートは、標準偏差としては偏りが残ります。それでも慣習として「標本の標準偏差」と言えば n−1 で割った値のルートを指します。
n が大きくなると、2つの差は小さくなります。n で割った値に √(n÷(n−1)) を掛けると n−1 版になるので、その倍率を計算しました。
| データの個数 n | n−1 版 ÷ n 版 | 差の目安 |
|---|---|---|
| 5 | 1.1180 | 約12%大きい |
| 10 | 1.0541 | 約5%大きい |
| 30 | 1.0171 | 約1.7%大きい |
| 100 | 1.0050 | 約0.5%大きい |
| 1,000 | 1.0005 | ほぼ同じ |
データが数件のときほど、どちらで割ったかを書き添えることが大切です。n が1件だと n−1 が 0 になり、標本の標準偏差は計算できません(エラーの原文は後の節に載せています)。
Pythonで標準偏差を求める(statistics・NumPy・pandas)
この節では、Python の3つの方法で標準偏差を求めるコードと、既定の割り方の違いが分かります。
いちばん注意したいのは、NumPy の np.std は既定で n で割り、pandas の Series.std は既定で n−1 で割ることです。同じデータを渡しても答えが違います。
import statistics as st
import numpy as np, pandas as pd
d = [50, 35, 40, 33, 82]
print(st.pstdev(d), st.stdev(d), st.pvariance(d), st.variance(d))
a = np.array(d)
print(np.std(a), np.std(a, ddof=1), np.var(a), np.var(a, ddof=1))
s = pd.Series(d)
print(s.std(), s.std(ddof=0), s.var())
17.988885457415087 20.112185361118765 323.6 404.5
17.988885457415087 20.112185361118765 323.6 404.5
20.112185361118765 17.988885457415087 404.5
| 書き方 | 割る数(既定) | 切り替え方 | NaN(欠損) |
|---|---|---|---|
| statistics.pstdev | n | 標本は stdev を使う | ValueError になる |
| statistics.stdev | n−1 | 母集団は pstdev | ValueError になる(variance は nan) |
| np.std | n(ddof=0) | ddof=1 で n−1 | nan を返す。np.nanstd で除外 |
| Series.std・DataFrame.std | n−1(ddof=1) | ddof=0 で n | 既定で除外(skipna=True) |
| scipy.stats.zscore | n(ddof=0) | ddof=1 | nan_policy で指定 |
ddof は「delta degrees of freedom」の略で、割る数を n−ddof にする引数です。ddof=1 が n−1 を意味します。
欠損値(NaN)があるとき
3番目の値を NaN にして試しました。NumPy の np.std は nan を返し、np.nanstd は NaN を除いた4件で n 割り、pandas は NaN を除いた4件で n−1 割りです。3つとも違う数になりました。
b = np.array([50, 35, np.nan, 33, 82])
print(np.std(b), np.nanstd(b), pd.Series(b).std())
nan 19.60867155112758 22.642143596988927
標準ライブラリの statistics は振る舞いがさらに分かれます。手元の Python 3.13.18 では、pstdev と stdev は ValueError: inf or nan encountered in data で止まり、pvariance と variance はエラーにならず nan を返しました。欠損があり得るデータは、先に除いてから渡します。
describe・グループ別・移動標準偏差
pandas の describe() に出る std も n−1 版です。店ごとの標準偏差は groupby、直近3件ごとの揺れは rolling で求められます。
df = pd.DataFrame({"x": [50, 35, 40, 33, 82]})
print(df.describe())
df = pd.DataFrame({"店": ["渋谷", "渋谷", "渋谷", "新宿", "新宿", "新宿"],
"売上": [100, 120, 110, 50, 200, 80]})
print(df.groupby("店")["売上"].agg(["mean", "std"]))
r = pd.Series([10, 12, 11, 13, 30, 12, 11])
print(r.rolling(3).std().round(3).tolist())
x
count 5.000000
mean 48.000000
std 20.112185
min 33.000000
25% 35.000000
50% 40.000000
75% 50.000000
max 82.000000
mean std
店
新宿 110.0 79.372539
渋谷 110.0 10.000000
[nan, nan, 1.0, 1.0, 10.44, 10.116, 10.693]
渋谷と新宿は平均がどちらも 110 ですが、標準偏差は 10.0 と 79.4 で、新宿の売上は日によって大きく揺れていることが分かります。移動標準偏差は、30 が入った窓から 10 前後に跳ね上がりました。異常な値の検知に使えます。2次元の配列では、np.std(配列, axis=0) で列ごと、axis=1 で行ごとに求めます。NumPy の基本操作は関連記事「NumPyの使い方 基本一覧|配列の作成・演算・形状変更」、pandas の集計は関連記事「pandasの使い方 逆引き81選|pandas 3.0の実行結果つき」で扱っています。
速さの違い(100万件)
100万件の正規乱数で、3回測った中の最短の時間を比べました。結果の値はどれも 10.007812 で同じです。
| 方法 | 時間(100万件) | 向く場面 |
|---|---|---|
| np.std(x, ddof=1) | 1.72ミリ秒 | 大きな配列・数値計算 |
| Series.std() | 5.80ミリ秒 | 表データ・欠損値あり・グループ別 |
| statistics.stdev(list) | 513.83ミリ秒 | 少ないデータ・追加の部品を入れたくないとき |
statistics は標準ライブラリだけで動き、分数(Fraction)や Decimal も正確に扱える代わりに、大量のデータでは遅くなります。共有マシンでの測定なので、時間は目安です。
SQLで標準偏差を求める(PostgreSQL・SQLite)
この節では、データベースの中で標準偏差を求める SQL と、PostgreSQL と SQLite の違いが分かります。
PostgreSQL には stddev_pop(n で割る)と stddev_samp(n−1 で割る)があり、stddev は stddev_samp と同じです。分散は var_pop・var_samp(variance)です。SQLite には標準偏差の関数がありません。
CREATE TABLE score(name text, shop text, v numeric);
INSERT INTO score VALUES ('a','渋谷',4),('b','渋谷',8),('c','渋谷',6),('d','渋谷',5),('e','渋谷',7),
('f','新宿',50),('g','新宿',200),('h','新宿',80),('i','新宿',NULL);
SELECT stddev_pop(v), stddev_samp(v), stddev(v), var_pop(v), var_samp(v)
FROM score WHERE shop='渋谷';
SELECT shop, count(v), round(avg(v),2) AS avg, round(stddev_samp(v),3) AS sd
FROM score GROUP BY shop ORDER BY shop;
stddev_pop | stddev_samp | stddev | var_pop | var_samp
--------------------+--------------------+--------------------+--------------------+--------------------
1.4142135623730950 | 1.5811388300841897 | 1.5811388300841897 | 2.0000000000000000 | 2.5000000000000000
(1 row)
shop | count | avg | sd
------+-------+--------+--------
新宿 | 3 | 110.00 | 79.373
渋谷 | 5 | 6.00 | 1.581
(2 rows)
新宿の NULL は数に入らず、3件で計算されています。1件しか無いグループの stddev_samp は、エラーではなく NULL(空欄)になりました。numeric 型の列から求めると結果も numeric、double precision に変えると double precision で返ります(末尾の桁が 1.5811388300841898 に変わります)。
ウィンドウ関数を使えば、1行ずつの偏差値も1つの SQL で出せます。
SELECT name, v,
round(50 + 10*(v - avg(v) OVER ())/stddev_pop(v) OVER (), 1) AS hensachi
FROM score WHERE shop='渋谷' ORDER BY v DESC;
name | v | hensachi
------+---+----------
b | 8 | 64.1
e | 7 | 57.1
c | 6 | 50.0
d | 5 | 42.9
a | 4 | 35.9
(5 rows)
SQLite では stddev を呼ぶとエラーになります。Python 組み込みの SQLite 3.53.1 では sqrt などの数学関数は使えたため、平均との差の2乗を合計する式で書きました。
SELECT stddev(v) FROM score;
-- OperationalError: no such function: stddev
SELECT shop, count(v) n,
sqrt(sum((v-m)*(v-m))/count(v)) sd_pop,
sqrt(sum((v-m)*(v-m))/(count(v)-1)) sd_samp
FROM score JOIN (SELECT shop s, avg(v) m FROM score GROUP BY shop) ON shop=s
WHERE v IS NOT NULL GROUP BY shop ORDER BY shop;
[('新宿', 3, 64.8074069840786, 79.37253933193772), ('渋谷', 5, 1.4142135623730951, 1.5811388300841898)]
sqrt は数学関数付きでビルドされた SQLite でだけ使えます。使えない場合は、アプリ側で集計関数を登録する方法があります。Python なら sqlite3 の create_aggregate で stdev という集計関数を足せ、結果は PostgreSQL の stddev_samp と同じになりました。
class SD:
def __init__(s): s.x = []
def step(s, v):
if v is not None: s.x.append(v)
def finalize(s): return st.stdev(s.x) if len(s.x) > 1 else None
con.create_aggregate("stdev", 1, SD)
print(con.execute("SELECT shop, stdev(v) FROM score GROUP BY shop ORDER BY shop").fetchall())
[('新宿', 79.37253933193772), ('渋谷', 1.5811388300841898)]
SUM・AVG・COUNT と NULL の扱いは、関連記事「SQL集計関数一覧|SUM・AVG・MAX・MIN・COUNTとNULLの扱い」で扱っています。
JavaScriptで標準偏差を求める(自作関数と落とし穴)
この節では、JavaScript で標準偏差を求める関数と、入力の型で起きる間違いが分かります。
JavaScript には標準偏差の組み込み関数がありません。Math.std のようなものは無く、手元でも typeof Math.std は undefined でした。平均と偏差の2乗の合計から自作します。
const mean = a => a.reduce((s, x) => s + x, 0) / a.length;
function sd(a, { sample = false } = {}) {
const m = mean(a);
const ss = a.reduce((s, x) => s + (x - m) ** 2, 0);
return Math.sqrt(ss / (a.length - (sample ? 1 : 0)));
}
console.log(sd([4, 8, 6, 5, 7]), sd([4, 8, 6, 5, 7], { sample: true }));
const raw = ["4", "8", "6", "5", "7"]; // input や CSV から来た文字列
console.log(mean(raw), sd(raw));
console.log(sd(raw.map(Number)));
console.log(sd([]), sd([5], { sample: true }));
1.4142135623730951 1.5811388300841898
9731.4 9725.400102823534
1.4142135623730951
NaN NaN
文字列の配列を渡すと、足し算が文字の連結になり "048657"÷5=9731.4 という平均になって、標準偏差も意味の無い数になりました。エラーが出ないので気づきにくい間違いです。空の配列と、1件で標本の標準偏差を求めたときは NaN でした。
データを1件ずつ受け取りながら計算したいときは、ウェルフォード(Welford)の方法が使えます。平均と偏差平方和を少しずつ更新するので、全部を配列に持たなくて済み、桁落ちにも強い方法です。
function welford(a) {
let n = 0, m = 0, M2 = 0;
for (const x of a) { n++; const d = x - m; m += d / n; M2 += d * (x - m); }
return { mean: m, pop: Math.sqrt(M2 / n), samp: Math.sqrt(M2 / (n - 1)) };
}
console.log(welford([4, 8, 6, 5, 7]));
{ mean: 6, pop: 1.4142135623730951, samp: 1.5811388300841898 }
入力の型
Python でも CSV の文字列を statistics に渡すと TypeError になる
計算の式
次の節で、分散がマイナスになる実例を示す
「2乗の平均−平均の2乗」で分散がマイナスになる
分散は「2乗の平均 − 平均の2乗」でも求められると教科書に載っています。式としては正しいのですが、コンピューターで大きな数に使うと桁落ちが起きます。10億前後の4つの値(真の分散は 22.5)で試しました。
const big = [1e9 + 4, 1e9 + 7, 1e9 + 13, 1e9 + 16];
const naive = big.reduce((s, x) => s + x * x, 0) / 4 - mean(big) ** 2;
console.log(naive, sd(big) ** 2, welford(big).pop ** 2);
-128 22.5 22.5
JavaScript では分散が −128 というあり得ない値になり、ルートを取ると NaN になります。Python で同じ式を書くと 0.0 でした。statistics.pvariance と np.var は 22.5 を返しましたが、NumPy でも float32 の配列にすると 0.0 になりました。浮動小数点の誤差については、関連記事「浮動小数点の落とし穴8選|0.1+0.2・丸め・金額計算」で扱っています。
平均±1σ・2σ・3σの割合(68-95-99.7を自作データで確かめる)
この節では、「平均±1σに約68%」という目安が本当に成り立つか、どんなデータで成り立たないかが分かります。
データが正規分布(左右対称の釣り鐘型)に近いとき、平均±1σに約68.3%、±2σに約95.4%、±3σに約99.7%が入ります。平均170cm・標準偏差6cmの正規乱数を10万件作り、実際に数えました。
import math, numpy as np
rng = np.random.default_rng(164)
x = rng.normal(170, 6, 100_000)
m, s = x.mean(), x.std()
print(f"平均{m:.2f} SD{s:.2f}")
for k in (1, 2, 3):
print(k, f"{np.mean(np.abs(x - m) <= k * s) * 100:.2f}%")
print("理論", [round(math.erf(k / math.sqrt(2)) * 100, 2) for k in (1, 2, 3)])
平均170.05 SD5.99
1 68.35%
2 95.42%
3 99.73%
理論 [68.27, 95.45, 99.73]
同じデータを3cm刻みのヒストグラムにすると、真ん中が高く、±2σを超えるあたりから急に少なくなる形が見えます(右端の数は人数、かっこは各区間の真ん中が平均から何σ離れているか)。
152-155 468 (-2.8σ)
155-158 ## 1611 (-2.3σ)
158-161 ####### 4293 (-1.8σ)
161-164 ############### 9056 (-1.3σ)
164-167 ######################### 15015 (-0.8σ)
167-170 ############################### 19161 (-0.3σ)
170-173 ############################### 19176 (+0.2σ)
173-176 ######################### 15080 (+0.7σ)
176-179 ############### 9265 (+1.2σ)
179-182 ####### 4411 (+1.7σ)
182-185 ## 1716 (+2.2σ)
185-188 488 (+2.7σ)
ところが、正規分布でないデータでは割合が変わります。右に裾が長いレスポンス時間(中央値約200ミリ秒の対数正規分布)と、サイコロの目(一様分布)でも10万件ずつ数えました。
| データ | ±1σ | ±2σ | ±3σ |
|---|---|---|---|
| 身長(正規分布) | 68.35% | 95.42% | 99.73% |
| レスポンス時間(右に偏る) | 89.19% | 95.79% | 98.09% |
| サイコロの目(一様) | 66.48% | 100.00% | 100.00% |
レスポンス時間は平均276.7ミリ秒、標準偏差264.4ミリ秒で、平均−1σ は 12.3ミリ秒です。下側にはみ出す値はほとんど無く、±3σ の外にある 1.91% はすべて上側でした。「平均±2σ を超えたら異常」という決まりを偏ったデータにそのまま使うと、上側だけがよく引っかかり、下側の異常は検知できません。こうしたデータには中央値や p95 を合わせて使います。
分布の形にかかわらず成り立つ下限として、チェビシェフの不等式があります。どんな分布でも平均±2σ には少なくとも 75%、±3σ には少なくとも約 89% が入ります。正規分布の 95%・99.7% はあくまで「正規分布に近いとき」の値です。正規分布・一様分布・対数正規分布の形の違いは、上で紹介した確率分布の記事で図とコードを載せています。
偏差値の計算(標準偏差から求める)
この節では、偏差値を標準偏差から計算する式と、偏差値から上位何%かを読む方法が分かります。
偏差値=50+10×(得点−平均)÷標準偏差です。総務省統計局の「なるほど統計学園」は、偏差値を、成績の分布が正規分布であると仮定し、平均が50、標準偏差が10になるように変換した値、と説明しています。同じページの例では、数学が平均42点・標準偏差8点で得点58点、国語が平均47点・標準偏差12点で得点65点です。式に当てはめると数学は 50+10×16÷8=70.0、国語は 50+10×18÷12=65.0 で、点数は国語が上でも、集団の中での位置は数学のほうが上だと分かります。
10人のテストの点で、全員の偏差値を計算しました。平均は60点、標準偏差(n で割る)は12.1点、n−1 で割ると12.754点です。
import statistics as st
sc = {"A": 82, "B": 75, "C": 68, "D": 64, "E": 61, "F": 58, "G": 55, "H": 50, "I": 44, "J": 43}
v = list(sc.values()); m = st.mean(v); s = st.pstdev(v)
for k, x in sc.items():
print(k, x, round(50 + 10 * (x - m) / s, 1), round(50 + 10 * (x - m) / st.stdev(v), 1))
| 人 | 得点 | 偏差値(n で割る) | 参考:n−1 で割る |
|---|---|---|---|
| A | 82 | 68.2 | 67.2 |
| B | 75 | 62.4 | 61.8 |
| C | 68 | 56.6 | 56.3 |
| E | 61 | 50.8 | 50.8 |
| H | 50 | 41.7 | 42.2 |
| J | 43 | 35.9 | 36.7 |
偏差値は、受けた人全員の成績から計算するので n で割る標準偏差を使うのが一般的です。n−1 で割ると、A さんの偏差値が 68.2→67.2 と1ずれます。SciPy の scipy.stats.zscore も既定は n で割ります(ddof=0)。zscore の値を10倍して50を足すと偏差値になります。
成績が正規分布に近いと仮定すると、偏差値から上位何%かが読めます。SciPy の正規分布で計算しました。
| 偏差値 | 平均から | 上位の割合 |
|---|---|---|
| 40 | −1σ | 上位84.13% |
| 50 | 平均 | 上位50.00% |
| 55 | +0.5σ | 上位30.85% |
| 60 | +1σ | 上位15.87% |
| 65 | +1.5σ | 上位6.68% |
| 70 | +2σ | 上位2.28% |
| 75 | +2.5σ | 上位0.62% |
人数が少ない集団や、満点近くに人が集まる簡単なテストでは、この割合はずれます。上の10人では偏差値68.2の A さんは10人中1位(上位10%)で、表の目安とは一致しません。
外れ値で標準偏差はどれだけ変わるか(実測)
この節では、極端な値が1つ混ざると標準偏差がどれだけ動くかと、外れ値に強い代わりの指標が分かります。
標準偏差は偏差を2乗するため、外れ値の影響を平均よりもさらに強く受けます。46〜54の10個の値(平均50、標準偏差2.449)の最後の 54 を、60・100・500 に置き換えて比べました。
import statistics as st
base = [48, 52, 50, 47, 53, 49, 51, 50, 46, 54]
print("元", st.mean(base), round(st.pstdev(base), 3), st.median(base))
for o in (60, 100, 500):
d = base[:-1] + [o]
print(o, st.mean(d), round(st.pstdev(d), 3), st.median(d))
元 50 2.449 50.0
60 50.6 3.747 50.0
100 54.6 15.272 50.0
500 94.6 135.149 50.0
入力ミスや測定の失敗が1件あるだけで、標準偏差は何十倍にもなります。外れ値に強い散らばりの指標として、中央絶対偏差(MAD:各値と中央値の差の絶対値の、中央値)があります。正規分布のとき標準偏差と同じ大きさになるよう 1.4826 を掛けて使うことが多く、手元では外れ値が無くても 500 が入っても 2.965 で変わりませんでした。
1行目が 500 の入ったデータ、2行目が元のデータの結果です。
med = st.median(d); mad = st.median([abs(v - med) for v in d])
print("MAD", mad, "1.4826*MAD", round(1.4826 * mad, 3))
med = st.median(base); mad = st.median([abs(v - med) for v in base])
print("元MAD", mad, round(1.4826 * mad, 3))
MAD 2.0 1.4826*MAD 2.965
元MAD 2.0 2.965
外れ値を除くかどうかは、原因を確かめてから決めます。入力ミスなら直し、本当に起きた値なら残して、中央値・MAD・四分位範囲を並べて報告します。平均値・中央値・最頻値の違いは、同じ統計の入口として「中央値とは?平均値・最頻値との違いと求め方をPython・SQLで実演」の記事で扱っています。
変動係数・標準誤差と標準偏差の違い
この節では、標準偏差と名前の似た変動係数・標準誤差が、それぞれ何を表すかが分かります。
単位や大きさの違うデータのばらつきを比べるときは、標準偏差を平均で割った変動係数(CV)を使います。5人の身長と体重で比べました。
身長cm 170 7.071 CV=4.16%
体重kg 62 8.462 CV=13.65%
標準偏差は身長 7.07cm、体重 8.46kg で、単位が違うので大小を比べられません。変動係数にすると身長 4.16%、体重 13.65% で、体重のほうが相対的に大きくばらついていると言えます。変動係数は、0 を基準にした量(長さ・重さ・金額)に使い、気温(℃)のように 0 に特別な意味の無い量には向きません。
標準誤差(SE)は、データそのもののばらつきではなく「平均値の推定がどれくらい揺れるか」です。標準偏差 ÷ √n で求めます。平均50・標準偏差10の正規乱数400件では、標準偏差 9.921 に対して標準誤差は 9.921÷√400=0.496 でした(scipy.stats.sem の結果も 0.496)。
| 指標 | 求め方 | 何を表すか | n を増やすと |
|---|---|---|---|
| 標準偏差(SD) | 分散のルート | 1件1件のデータの散らばり | ほぼ変わらない |
| 標準誤差(SE) | SD ÷ √n | 平均値の推定の精度 | 小さくなる |
| 変動係数(CV) | SD ÷ 平均 | 平均に対する散らばりの割合 | ほぼ変わらない |
| 分散 | SD の2乗 | 散らばり(単位は2乗) | ほぼ変わらない |
グラフの誤差棒が SD なのか SE なのかで、意味は大きく違います。SE の棒は SD の棒より √n 分の1に短くなるため、図には必ずどちらかを書き添えます。標準誤差は検定や信頼区間で使われます。検定の考え方は、関連記事「p値とは|意味・有意水準・よくある誤解をPythonで実演」で扱っています。
標準偏差の計算が合わないとき(症状→原因→直し方)
この節では、標準偏差を求めたときに出るエラーの原文と、他の計算と結果が合わないときの原因が分かります。
「計算した値が電卓や他のツールと違う」原因の多くは、n と n−1 の違いです。手元で出たエラーと症状をまとめました。
| 症状(原文) | 原因 | 直し方 |
|---|---|---|
| NumPy と pandas で値が違う(17.99 と 20.11) | np.std は n、Series.std は n−1 で割る | ddof をそろえる。np.std(a, ddof=1) か s.std(ddof=0) |
| StatisticsError: stdev requires at least two data points | statistics.stdev に1件だけ渡した | 2件以上にするか、母集団なら pstdev を使う |
| RuntimeWarning: Degrees of freedom <= 0 for slice(結果は nan) | np.std(1件, ddof=1)。n−1 が 0 | 件数を確かめてから計算する |
| 結果が nan | データに NaN が入っている(np.std) | np.nanstd を使うか、欠損を除く |
| ValueError: inf or nan encountered in data | statistics.pstdev・stdev に NaN を渡した | NaN を除いてから渡す |
| TypeError: can't convert type 'str' to numerator/denominator | statistics に文字列を渡した(CSV の読み込み直後など) | float や int に変換してから渡す |
| ERROR: function stddev(text) does not exist | PostgreSQL で文字列の列に stddev を使った | 列を数値型にするか ::numeric で変換する |
| OperationalError: no such function: stddev | SQLite には標準偏差の関数が無い | 式で書くか create_aggregate で登録する |
| 分散がマイナス・標準偏差が NaN | 「2乗の平均−平均の2乗」の桁落ち | 平均との差の2乗を足す式か Welford の方法 |
| 標本の標準偏差が異様に大きい | 外れ値・入力ミス・単位の混在 | 最大値・最小値を見る。MAD や中央値と並べる |
Python の statistics.variance に xbar(平均)を自分で渡せますが、正しい平均かどうかは調べられません。公式ドキュメントにも、任意の値を渡すと不正な結果になりうると書かれています。手元で 4・8・6・5・7 に正しい平均 6 を渡すと 2.5、誤って 0 を渡すと 47.5 が返り、エラーにはなりませんでした。
標準偏差の使い分け(判断表)
この節では、どの標準偏差を使い、どう報告するかを場面ごとに決める方法が分かります。
- 1対象の全員・全件がそろっている → n で割るクラス全員の成績・今月の全注文。偏差値もこちら
- 2一部から全体を推定する → n−1 で割る抜き取り検査・アンケート・実験。統計の検定もこちら
- 3分布が左右対称に近い → 平均±SD で報告身長・寸法・測定誤差。±2σ・3σ の目安も使える
- 4右に偏る・外れ値がある → 中央値と四分位範囲・MAD も併記年収・レスポンス時間・待ち時間
- 5単位や大きさが違うものを比べる → 変動係数身長と体重・売上の規模が違う店
- 6平均値の確からしさを示す → 標準誤差実験の平均の誤差棒・信頼区間
| やりたいこと | Python | SQL(PostgreSQL) |
|---|---|---|
| 全件のばらつき | st.pstdev・np.std(a) | stddev_pop |
| 標本から推定 | st.stdev・np.std(a, ddof=1)・s.std() | stddev_samp・stddev |
| 欠損を除いて | np.nanstd・s.std() | NULL は自動で除外 |
| グループごと | df.groupby(列)[列].std() | GROUP BY |
| 行ごとの偏差値 | 50+10×stats.zscore(a) | ウィンドウ関数 OVER () |
報告する前に、次の点を確かめます。
- 1n と n−1 のどちらで割ったか書いた数件のデータでは1割以上違う
- 2件数と欠損の数を書いたNaN・NULL を除いたかで値が変わる
- 3ヒストグラムで分布の形を見た偏っているなら ±2σ の目安は使えない
- 4最大値・最小値で入力ミスを探した1件の誤りで標準偏差は数十倍になる
- 5誤差棒が SD か SE か書いたSE は √n 分の1に短い
表示する桁は、元のデータより1〜2桁多くする目安がよく使われます。整数の点数なら標準偏差は小数第1〜2位まで、のように決め、途中の計算では丸めずに最後だけ丸めます。
よくある質問
この節では、標準偏差について検索されることの多い疑問への答えが分かります。
Q. 標準偏差とは簡単に言うと何ですか? A. データが平均から「だいたいどれくらい離れているか」を表す数です。0 なら全員が同じ値で、大きいほどばらばらです。単位は元のデータと同じです。
Q. 標準偏差の求め方を一言で言うと? A. 各値と平均の差を2乗して平均し(分散)、そのルートを取ります。4・8・6・5・7 なら分散2、標準偏差 √2=1.414 です。
Q. 分散と標準偏差はどちらを使えばよいですか? A. 報告やグラフには、元と同じ単位の標準偏差が読みやすいです。分散は単位が2乗になりますが、独立な量を足したときの計算や理論の式で使います。
Q. n で割るのと n−1 で割るのはどちらが正しいですか? A. 目的で決まります。全部のデータのばらつきそのものなら n、一部の標本から全体のばらつきを推定するなら n−1 です。手元の10万回の試行では、5個の標本を n で割った分散は平均 28.843 で真の 36 より小さく、n−1 で割ると 36.054 でした。
Q. 標準偏差がマイナスになることはありますか? A. ありません。2乗の合計のルートなので 0 以上です。マイナスや NaN が出たら、「2乗の平均−平均の2乗」の式による桁落ちか、プログラムの間違いを疑います。
Q. 標準偏差はいくつなら大きいと言えますか? A. 決まった基準はありません。平均や単位によって変わるので、平均で割った変動係数や、同じ種類の過去のデータと比べて判断します。
Q. 2σ・3σとは何ですか? A. 標準偏差の2倍・3倍の幅です。正規分布なら平均±2σに約95.4%、±3σに約99.7%が入ります。10万件の自作データでは 95.42%・99.73% でした。偏ったデータではこの割合になりません。
Q. 偏差値はどう計算しますか? A. 50+10×(得点−平均)÷標準偏差です。総務省統計局の例(平均42点・標準偏差8点で58点)なら偏差値70です。偏差値70は、正規分布なら上位約2.28%に当たります。
Q. 標準偏差と標準誤差の違いは? A. 標準偏差は1件1件のデータの散らばり、標準誤差は平均値の推定の揺れで、標準偏差÷√n です。データを増やすと標準誤差は小さくなりますが、標準偏差はほぼ変わりません。
Q. Python で標準偏差を求めるには? A. 標準ライブラリなら statistics.stdev(n−1)と pstdev(n)、NumPy なら np.std(既定は n、ddof=1 で n−1)、pandas なら Series.std(既定は n−1)です。既定の違いに気をつけます。
Q. データが1つしか無いときの標準偏差は? A. 母集団としては 0 です。標本の標準偏差は n−1 が 0 になるため計算できず、statistics.stdev はエラー、NumPy と pandas は nan、PostgreSQL の stddev_samp は NULL を返しました。
まとめ
- 標準偏差(SD・σ)は、平均からの散らばりを元と同じ単位で表す値。分散(偏差の2乗の平均)のルートで、0 以上になる。
- 求め方は「平均→偏差→2乗→合計÷個数→ルート」。4・8・6・5・7 なら分散2、標準偏差1.414。全部のデータなら n、標本なら n−1 で割る。
- np.std は既定で n、pandas の std と PostgreSQL の stddev は n−1 で割る。値が合わないときはまず ddof を確かめる。SQLite と JavaScript には関数が無いので式で書く。
- 正規分布なら平均±1σ・2σ・3σに約68%・95%・99.7%が入る。偏ったレスポンス時間では ±1σ に 89%、はみ出しは上側だけだった。偏差値は 50+10×(得点−平均)÷標準偏差。
- 外れ値1つで標準偏差は 2.449→135.149 と55倍になった。中央値・MAD を並べ、「2乗の平均−平均の2乗」の式は桁落ちで分散がマイナスになるので使わない。
参考・出典
確認日はいずれも 2026年10月29日です。
- 総務省統計局「なるほど統計学園」データの散らばりを見る:https://www.stat.go.jp/naruhodo/10_tokucho/chirabari.html
- Python「statistics — Mathematical statistics functions」:https://docs.python.org/3/library/statistics.html
- NumPy「numpy.std」:https://numpy.org/doc/stable/reference/generated/numpy.std.html
- NumPy「numpy.nanstd」:https://numpy.org/doc/stable/reference/generated/numpy.nanstd.html
- pandas「pandas.Series.std」:https://pandas.pydata.org/docs/reference/api/pandas.Series.std.html
- SciPy「scipy.stats.zscore」:https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.zscore.html
- SciPy「scipy.stats.sem」:https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.sem.html
- PostgreSQL 16「Aggregate Functions」(Aggregate Functions for Statistics):https://www.postgresql.org/docs/16/functions-aggregate.html
- SQLite「Built-In Mathematical SQL Functions」:https://sqlite.org/lang_mathfunc.html
- Python「sqlite3 — DB-API 2.0 interface for SQLite databases」(create_aggregate):https://docs.python.org/3/library/sqlite3.html
- MDN「Math」:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「標準偏差の求め方と意味|n−1の違い・偏差値をPython・SQLで実演」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。