Pythonによる調和平均 (Harmonic mean)
PythonのSciPyを利用して調和平均を求める。SciPyのインストールを先にしておくこと。
pip install scipy
計算対象は全て0より大きい値(正の実数)でないと、例外を投げる。
負の数は分母を減少させ、調和平均が大きな値になってしまうため。
例えば、3,-3,4の調和平均を式に従い計算すると12になってしまう。このような値は使えない。
harmonic_mean1.py
from scipy import stats
# 1, 2, 4の調和平均 ⇒ 1.71428571429
print(stats.hmean([1, 2, 4]))
# 1, 0.5, 2.0, 10の調和平均 ⇒ 1.11111111111
print(stats.hmean([1, 0.5, 2.0, 10]))
# 以降は負の値を試した例
# 3,-3,4の調和平均 ⇒ ValueError: Harmonic mean only defined if all elements greater than zero
print(stats.hmean([3, -3, 4]))
# 調和平均の式に従って計算した場合 ⇒ 12 値が増えた!? いいえ、無効な値です。
print(3 / ((1 / 3.0) + (1 / -3.0) + (1 / 4.0)))
0や負の値が登場しても、調和平均のような値を取得したい場合
※正確な調和平均ではない為、この方法を適用して良いかどうか判断して参考にしてください
例外対策をしたstats.hmean()のラッパーを作ってみた。
0以下の値は非常に小さい正の実数に置き換えて計算する。 以下の例では0.0001で置き換えてみた。
値が全て0以下だった場合は平均を0にする。HM_OFFSETを返すと不自然な為。
Noneを扱えるようにしたので、計算対象の数値が取得できなかった場合はNoneとする。
これによって、取得できなかった数値が調和平均の値に影響を与えないようにする。
harmonic_mean2.py
from scipy import stats
HM_OFFSET = 0.0001
def custom_hmean(values_list):
u"""調和平均の関数を例外対策したラッパー."""
# 計算する値が全てNoneなら調和平均をNoneとする
if values_list[0] is None and\
values_list == [values_list[0]] * len(values_list):
return None
# 計算する値が全て0以下なら調和平均を0とする
if max(values_list) <= 0:
return 0
# 計算する値がNoneの場合はデータが無いものとみなし、0以下の場合はHM_OFFSETの値とする
return stats.hmean(
[v if v > 0 else HM_OFFSET for v in values_list if v is not None])
print custom_hmean([3, 0, 4]) # 0.000299982501021
print custom_hmean([3, None, 4]) # 3.42857142857
print custom_hmean([0, -1, -2, -3]) # 0
print custom_hmean([0, -1, -2, 1]) # 0.000133328889037
print custom_hmean([0, 0, 1, 0]) # 0.000133328889037
print custom_hmean([None, None, 1, None]) # 1.0
print custom_hmean([None, None, None, None]) # None
print custom_hmean([0, 0, 0, 0]) # 0
scipy.stats.hmeanの詳細 英語
調和平均の式はウィキペディア参照 ⇒ 調和平均は逆数の算術平均の逆数