調和平均とは?公式・求め方といつ使うかをPythonで解説(statistics.harmonic_mean)
調和平均とは「逆数の平均をとって、もう一度逆数に戻した値」で、速度・単価・処理レートのような「○○あたり」の数値を平均するときに使います。Pythonでは標準ライブラリのstatistics.harmonic_mean()で1行で求められます。
この記事では、調和平均の公式と手計算での求め方、どんなときに使うのか(なぜ普通の平均ではずれるのか)を、実際に動かしたPythonのコードと結果で説明します。実行環境はPython 3.12です。
調和平均とは?公式と求め方
n個の正の数 x1, x2, …, xn の調和平均Hは、次の式で求めます。
H = n ÷ (1/x1 + 1/x2 + … + 1/xn)
手順にすると3つです。
- それぞれの値の逆数(1/x)をとる
- 逆数の平均を出す(逆数の和 ÷ 個数)
- その平均の逆数をとる
たとえば2、3、6の調和平均は、逆数が1/2、1/3、1/6で、和がちょうど1です。個数3を和1で割って、答えは3になります。
import statistics
data = [2, 3, 6]
n = len(data)
inv_sum = sum(1 / x for x in data)
print("逆数の和:", inv_sum)
print("手計算 :", n / inv_sum)
print("関数 :", statistics.harmonic_mean(data))
実行結果:
逆数の和: 1.0
手計算 : 3.0
関数 : 3.0
Pythonの公式ドキュメントも、調和平均を「データの逆数の算術平均の逆数」と説明し、3つの値なら3/(1/a + 1/b + 1/c)と同じになると書いています(statistics — 数理統計関数、2026年10月18日確認)。
2つの値a、bだけなら、式を整理した 2ab ÷ (a + b) でも同じ値になります。後で出てくるF1スコアの公式がこの形です。
調和平均はいつ使う?普通の平均との違い
調和平均を使うかどうかは、平均したい数値が「○○あたり△△」の形で、しかも「○○」ではなく「△△」の側がそろっているかどうかで決まります。いちばん分かりやすい例が往復の平均速度です。
例1:往復の平均速度
行きは時速40km、帰りは時速60kmで同じ道を走りました。平均速度は時速50kmでしょうか。
import statistics
print("調和平均:", statistics.harmonic_mean([40, 60]))
print("単純平均:", statistics.mean([40, 60]))
d = 120 # 片道120km
print("総距離 ÷ 総時間:", 2 * d / (d / 40 + d / 60))
実行結果:
調和平均: 48.0
単純平均: 50
総距離 ÷ 総時間: 48.0
正解は時速48kmです。片道120kmなら、行きに3時間、帰りに2時間かかり、240kmを5時間で走っています。遅い行きのほうに長い時間を使っているので、平均は50より下に引っ張られます。単純平均(算術平均)は「走った時間が同じ」ときにしか合いません。
例2:同じ金額ずつ買ったときの平均単価
1個100円の店と1個200円の店で、1万円ずつ買い物をしたときの平均単価も調和平均です。
import statistics
prices = [100, 200]
print("調和平均:", statistics.harmonic_mean(prices))
print("実際 :", 20000 / (10000 / 100 + 10000 / 200))
print("単純平均:", statistics.mean(prices))
実行結果:
調和平均: 133.33333333333334
実際 : 133.33333333333334
単純平均: 150
2万円で150個買っているので、1個あたりは約133円です。安い店でたくさん買っているぶん、単純平均の150円より安くなります。
判断の目安
| そろっているもの | 使う平均 | 例 |
|---|---|---|
| 分母(時間・個数)がそろっている | 算術平均 | 1時間ずつ時速40kmと60kmで走った → 50 |
| 分子(距離・金額)がそろっている | 調和平均 | 同じ距離を時速40kmと60kmで走った → 48 |
| どちらもそろっていない | 重み付き調和平均(後述) | 5kmと30kmを別々の速度で走った |
ほかにも、1秒あたりの処理件数(同じ件数を処理したときの平均)、燃費(km/L)を同じ距離で比べるとき、機械学習のF1スコアなどが調和平均の出番です。
Pythonで調和平均を求める:statistics.harmonic_mean()
statisticsは標準ライブラリなので、インストールは不要です。書式は次のとおりです。
statistics.harmonic_mean(data, weights=None)
dataにはリストやタプルなど、数値の並びを渡します。weights(重み)は省略できます。公式ドキュメントによると、関数自体はPython 3.6で追加され、weightsはPython 3.10で追加されました(2026年10月18日確認)。
重み付き調和平均(weights)
区間ごとに距離が違う場合は、距離を重みとして渡します。5kmを時速40km、30kmを時速60kmで走ったときの平均速度です。
import statistics
print(statistics.harmonic_mean([40, 60], weights=[5, 30]))
print(35 / (5 / 40 + 30 / 60))
実行結果:
56.0
56.0
総距離35kmを総時間(5/40 + 30/60時間)で割った値と一致します。重みには「そろっていない側の量」(ここでは距離、単価なら支払った金額)を入れると覚えておくと迷いません。
0・負の数・空のデータを渡したとき
実務でつまずきやすいのがここです。
import statistics
print(statistics.harmonic_mean([0, 4, 16]))
print(statistics.harmonic_mean([0, -1]))
実行結果:
0
0
0が含まれると、エラーにならず結果は0になります。公式ドキュメントには、0を見つけた時点で計算を打ち切るため、その後ろの値の妥当性は確認されないとも書かれています。2行目で負の数(-1)があるのに0が返っているのはこのためです。
一方、0がなくて負の数がある場合や、データが空の場合はStatisticsErrorになります。
StatisticsError: harmonic mean does not support negative values
StatisticsError: harmonic_mean requires at least one data point
データに0や負の数が混ざる可能性があるなら、関数に渡す前に取り除くか、0が意味するもの(止まっていた区間など)を先に確認しておきましょう。
エクセルのHARMEAN関数との違い
ExcelではHARMEAN関数で調和平均を求めます。Microsoftのサポートページによると、書式はHARMEAN(数値1, [数値2], ...)で、引数に0以下の数値が含まれているとエラー値#NUM!が返ります(HARMEAN 関数、2026年10月18日確認)。
| 入力 | Python harmonic_mean() | Excel HARMEAN |
|---|---|---|
| 0を含む | 0を返す | #NUM! |
| 負の数を含む(0なし) | StatisticsError | #NUM! |
| 重み付き | weightsで指定できる(3.10以降) | 引数はない |
同じデータでもPythonとExcelで結果(0かエラーか)が変わるので、Excelで作った集計をPythonに移すときは注意してください。
F1スコアは適合率と再現率の調和平均
機械学習の分類モデルの評価に使うF1スコアも調和平均です。
import statistics
precision = 0.8 # 適合率
recall = 0.5 # 再現率
print("調和平均 :", statistics.harmonic_mean([precision, recall]))
print("2pr/(p+r) :", 2 * precision * recall / (precision + recall))
print("算術平均 :", statistics.mean([precision, recall]))
実行結果:
調和平均 : 0.6153846153846154
2pr/(p+r) : 0.6153846153846154
算術平均 : 0.65
調和平均は小さいほうの値に強く引っ張られるので、適合率と再現率のどちらかが低いとF1も低くなります。再現率が0ならF1も0になるのは、先ほどの「0を含むと0」と同じ性質です。適合率・再現率そのものの意味は機械学習の評価指標の記事で解説しています。混同行列やF1スコアのような評価指標は、テックジムのAIエンジニア養成コースでは第11章「アンサンブル学習と精度向上手法」で扱います。
算術平均・幾何平均・調和平均の大小関係
import statistics
data = [1, 10, 100]
print("算術平均:", statistics.mean(data))
print("幾何平均:", statistics.geometric_mean(data))
print("調和平均:", statistics.harmonic_mean(data))
実行結果:
算術平均: 37
幾何平均: 10.000000000000002
調和平均: 2.7027027027027026
正の数では、必ず「算術平均 ≧ 幾何平均 ≧ 調和平均」が成り立ちます(すべての値が等しいときだけ3つとも等しくなります)。MicrosoftのHARMEAN関数の解説にも同じ関係が書かれています。
| 平均 | 計算 | 向いているデータ | Python |
|---|---|---|---|
| 算術平均(相加平均) | 足して個数で割る | 足し算で意味を持つ量(点数・金額) | statistics.mean() |
| 幾何平均(相乗平均) | 掛けてn乗根 | 掛け算で積み上がる量(成長率・倍率) | statistics.geometric_mean() |
| 調和平均 | 逆数の平均の逆数 | 「○○あたり」の量(速度・単価・レート) | statistics.harmonic_mean() |
幾何平均の使い方(年平均成長率の計算など)はstatistics.geometric_mean()の記事、普通の平均と重み付き平均はstatistics.mean()の記事、statisticsモジュール全体はstatisticsモジュールの使い方で解説しています。
よくある質問
Q. 調和平均はなぜ速度の平均に使うのですか?
同じ距離を走る場合、遅い区間ほど長い時間がかかり、平均速度は「総距離 ÷ 総時間」で決まるからです。この計算を整理すると、速度の逆数の平均の逆数、つまり調和平均になります。
Q. 調和平均と算術平均はどちらが大きくなりますか?
正の数なら算術平均のほうが大きいか等しくなります。調和平均は小さい値に強く引っ張られるため、値にばらつきがあるほど差が開きます。
Q. データに0が含まれるとどうなりますか?
Pythonのstatistics.harmonic_mean()は0を返します。ExcelのHARMEAN関数は0以下の値があるとエラー値#NUM!を返すので、同じデータでも結果が変わります。
Q. 重み付きの調和平均はPythonで計算できますか?
Python 3.10以降なら、statistics.harmonic_mean(data, weights=[…])のようにweightsを指定して計算できます。区間ごとに距離が違う速度の平均などに使います。

