はじめに
bitFlyer Lightning API[1]で暗号資産の買い注文をいい感じに執行するPython3のプログラムを書いてみたのですが、その途中でデータ列の加重平均を計算する必要が出てきました。
そこで、Python3を使った加重平均の計算を簡潔に記述できるプログラムで、かつ思いついたものをメモしておくことにしました。
加重平均とは?
まず、最初に加重平均について簡単に説明します。
ある2個の長さ$n$のデータ列$a = \{ a_1, \cdots , a_n \}, b = \{ b_1, \cdots , b_n \}$があり、$a$の各項が$b$の対応する項の重みを表すとき、加重平均$c$は
c &= \displaystyle\frac{\displaystyle\sum^{n}_{k=1}a_kb_k}{\displaystyle\sum^{n}_{k=1}a_k} \label{eq:weightedmean}
\end{align}
となります。重みを表す文字には$a$でなく$w$が使われることの方が一般的かもしれませんが、この記事では最初のプログラム例も含めて$a$を使い通すことにします。また、加重平均についてもこの記事では$c$で表すことにします。
プログラム例
Python3を使ってできるだけ簡潔にプログラムを書くというコンセプトの下、Windows 10にインストールしたPython 3.7.4のインタプリタでプログラムを書くことにします。
その1: a及びbともに配列の場合
プログラム例
(\ref{eq:weightedmean})式の$a$及び$b$がともに長さ10の配列の場合には、加重平均$c$は以下のプログラムで計算できます。
内包表記を使うと1行で書いても(少し長くなりますが、)可読性を犠牲にすることなくプログラムを書くことができます。
また、配列の最初の5個ずつのデータを使って加重平均を計算する場合には…
のようにrange関数の第2引数を変更することで計算の対象範囲を変えることができます。
計算例
Python 3.7.4のインタプリタによる計算例は以下の通りです。
>>> a = [1,3,5,7,8,10,11,12,14,15]
>>> b = [50,100,20,4,25,12,47,1,22,230]
>>> c = sum([a[i]*b[i] for i in range(0,10)])/sum([a[i] for i in range(0,10)])
>>> c
59.127906976744185
>>> c = sum([a[i]*b[i] for i in range(0,5)])/sum([a[i] for i in range(0,5)])
>>> c
28.25
その2: dictのキーにデータ列、値に重みの組が格納されている場合
プログラム例
キーにデータ列、値に重みの組が格納されているdict型の変数aaが与えられた場合には、加重平均$c$は以下のプログラムで計算できます。
スポンサーリンク
その1の例におけるrange関数に替わって変数aaのキーを取り出す関数keys()が登場しています。
また、配列の最初の5個ずつのデータを使って加重平均を計算する場合には…
と書くことができます。
keys()関数は引数を取らないため、すべてのキー及び値の組を加重平均の計算の対象とする場合に限れば、その2のケースはその1のケースよりも簡潔に書くことができますが、キー及び値の組のうちの一部のデータを使って加重平均を計算する場合には、keys()関数で返されるdict_keys型の変数をlistに変換する処理が必要になるため、その1のケースよりも少々繁雑なプログラムになります。
計算例
Python 3.7.4のインタプリタによる計算例は以下の通りです。
>>> aa = { 1:50, 3:100, 5:20, 7:4, 8:25, 10:12, 11:47, 12:1, 14:22, 15:230 }
>>> c = sum(i*aa[i] for i in list(aa.keys()))/sum(i for i in aa.keys())
>>> c
59.127906976744185
>>> c = sum(i*aa[i] for i in list(aa.keys())[0:5])/sum(i for i in list(aa.keys())[0:5])
>>> c
28.25
その1の計算例と同じ計算結果になっていることが確認できました。
まとめ
次に加重平均を使うプログラムを作ることになった時には割と普通に忘れそう(特にその2)なので、メモしておくことにした次第です。
この記事は以上です。