>開発>python>[Pythonで数学]相乗平均と対数平均と調和平均

相乗平均

標本は、統計の対象となるデータの集まりから取り出した一部のデータのことです。国語のテストの例で言えば、生徒個人個人の点数が標本となります。相加平均では、標本の総和を標本数で除算して求めたが、相乗平均は標本を全て乗算して、標本の数の分を1乗する。

\(\displaystyle (\prod_{ i = 1 }^n x_i )^\frac{1}{n} = \sqrt[n]{x_1 \cdot x_2 \ldots x_n }\)

Pythonで相乗平均を求める

# nの要素
x = [1, 2, 3, 4, 5]
# Πの値
p = 1

for i in range(len(x)):
    # 相乗する
    p *= x[i]

print(p)

この場合だと、\(\displaystyle 1 \times 2 \times 3 \times 4 \times 5 = 120\)になる。

120

次は、GDPの成長率を求めてみる。

\(\displaystyle GDPの成長率 = \frac{本年度のGDP – 前年度のGDP}{前年度のGDP} \times 100 \)[%]

前年度比で考えると、\(\displaystyle \frac{本年度のGDP}{前年度のGDP} \)となる。よって、

\(\displaystyle GDPの成長率 = \frac{本年度のGDP – 前年度のGDP}{前年度のGDP} \times 100 = \frac{本年度のGDP}{前年度のGDP} – 1 \times 100 \)

よって、\(\displaystyle 1 + \frac{GDPの成長率}{100} = \frac{本年度のGDP}{前年度のGDP} \)

因みにGDP成長率は内閣府のサイトからデータを取ってきた。2000年から2021年のGDP成長率を使う。

# 2000年から2021年までのGDP成長率(内閣府のデータ)
gdp = [2.8,0.4,0,1.5,2.2,1.8,1.4,1.5,-1.2,-5.7,4.1,0,1.4,2,0.3,1.6,0.8,1.7,0.6,-0.2,-4.5,1.6]
# 要素数
n = len(gdp)
# 相乗平均
gm = 1.0

for i in range(n):
  gm *= 1.0 + gdp[i] /100

gm **= (1/n)
gm = (gm - 1) * 100
print(gm )
0.6178924801243157

相乗平均はScipyでも求められる。

from scipy.stats import gmean
import numpy as np

# 2000年から2021年までのGDP成長率(内閣府のデータ) Numpy配列に変換
gdp = np.array([2.8,0.4,0,1.5,2.2,1.8,1.4,1.5,-1.2,-5.7,4.1,0,1.4,2,0.3,1.6,0.8,1.7,0.6,-0.2,-4.5,1.6])
gdp = 1 + gdp / 100
gm = (gmean(gdp) - 1) * 100
print(gm)
0.6178924801243157

対数平均

対数平均は、相乗平均と同じ結果が得られるが、グラフの積分から平均化して導くような感覚です。パソコンに計算させる場合、相乗平均に比べ桁溢れし難いといったメリットがあります。対数平均は、次のような式で表されます。

\(\displaystyle \exp(\frac{1}{n} \sum_{ i = 1 }^n ln(x_i)) \)

因みに、\(\displaystyle ln \)はネイピア数\(\displaystyle e \)を底とする自然対数のことです。

\(\displaystyle ln(x) = \log_e x \)

また、\(\displaystyle \exp \)は、指数関数\(\displaystyle e^x \)のことです。

\(\displaystyle x = \exp(ln(x)) \)

Pythonで対数平均を求める

先程の相乗平均の計算で使った2000年から2021年の日本のGDP成長率を使う。

import numpy as np

# 2000年から2021年までのGDP成長率(内閣府のデータ)
gdp = np.array([2.8,0.4,0,1.5,2.2,1.8,1.4,1.5,-1.2,-5.7,4.1,0,1.4,2,0.3,1.6,0.8,1.7,0.6,-0.2,-4.5,1.6])
gdp = 1 + gdp / 100

# 要素数
n = len(gdp)
lm = 0.0

for i in range(n):
    # 自然対数
    lm += np.log(gdp[i])

# 指数関数(exp)
lm = (np.exp(lm / n) - 1) * 100
print(lm)
0.6178924801243157

相乗平均の時と同じ結果になった。また、自然対数の相加平均に指数関数\(\displaystyle e^x \)を掛けて求めることもできる。

import numpy as np

gdp = np.array([2.8,0.4,0,1.5,2.2,1.8,1.4,1.5,-1.2,-5.7,4.1,0,1.4,2,0.3,1.6,0.8,1.7,0.6,-0.2,-4.5,1.6])
gdp = 1 + gdp / 100

# 自然対数の相加平均に指数関数(exp)を掛ける
lm = (np.exp(np.log(gdp).mean()) - 1) * 100
print(lm)
0.6178924801243157

相乗平均と対数平均が同じ結果になるのは、対数の法則にある。対数の法則から自然対数は次のように表すことができる。

\(\displaystyle ln(xy) = ln(x) + ln(y) \)

例えば、従って下記のように自然対数を掛け算しても、足し算しても両方同じ結果となる。

a1 = np.exp(np.log(5) + np.log(42))
a2 = np.exp(np.log(5 * 42))
print(a1)
print(a2)
209.99999999999994
209.99999999999994

調和平均

調和平均は、変化の割合を求める方法の1つで、平均速度や並列接続された抵抗の合成抵抗などを求める際によく利用される。逆数の相加平均の逆数です。また、各標本に重みが付けられたものを重み付き調和平均という。

調和平均 : \(\displaystyle H = \frac{n}{\sum_{ i = 1 }^n \frac{1}{x_i}} = \frac{n}{\frac{1}{x_1}+\frac{1}{x_2}+\frac{1}{x_3}+ \cdots +\frac{1}{x_n}} \)

調和平均(2) : \(\displaystyle H = \frac{n \prod_{ j = 1 }^n x_j}{\sum_{ i = 1 }^n \frac{\prod_{ j = 1 }^n x_j}{x_i}} \)

重み付き調和平均 : \(\displaystyle \frac{\sum_{ i = 1 }^n \omega_i}{\sum_{ i = 1 }^n \frac{\omega_i}{x_i}} \)

Pythonで調和平均を求める

並列で繋がれた3つの電気抵抗Rの調和平均を求めてみる。

調和平均 : \(\displaystyle H = \frac{n}{\sum_{ i = 1 }^n \frac{1}{x_i}} = \frac{n}{\frac{1}{x_1}+\frac{1}{x_2}+\frac{1}{x_3}+ \cdots +\frac{1}{x_n}} \)

x = [30, 20, 12]
n = len(x)
hm = 0.0

for i in range(n):
    hm += 1 / x[i]

hm = n / hm

print(hm)
17.999999999999996

実際の電気回路の抵抗値はこの値を要素数n(この場合は3)で割ってやる。すると、約6となる。つまり\(\displaystyle 6 \Omega \)ということです。

print(17.999999999999996 / 3)
5.999999999999999

Pythonで重み付き調和平均を求める

10人の陸上選手の時速を配列に並べてみた。これの重み付き調和平均を求めてみる。scipyの関数でたった1行で計算できる。ただ、重みの指定はできないので、重みを指定したい場合はpandasなどの関数を使うとよい。

重み付き調和平均 : \(\displaystyle \frac{\sum_{ i = 1 }^n \omega_i}{\sum_{ i = 1 }^n \frac{\omega_i}{x_i}} \)

import pandas as pd
from scipy.stats import hmean

x = pd.DataFrame([43.73780824, 41.09899956, 41.50503355, 39.78532623, 43.46219017, 39.37055411, 38.97916627, 37.0838443, 42.09026011, 37.12927313])
print(hmean(x))
x = [43.73, 41.09, 41.50, 39.78, 43.46, 39.37, 38.97, 37.08, 42.09, 37.12]

数学

記事を読んでいただきありがとうございました。

Page Top