Pythonでウィンドウをずらしながら平均、分散、回帰直線の傾き、相関係数を求める。
有名な方の分散を求める(平均を中に含んでいる)式を素直に使って計算すると、ループを2回なめないといけませんが、式をいじると1回のループで平均と分散が同時に出る、というのはたぶん有名な話だと思います。今回はそれに似ていて、n個のデータからサイズmの連続している部分を切り出して、そのそれぞれの統計を行う方法のハックです。普通にやるとO(mn - m^2)くらいかかるわけですが、これがO(n - m)になっていると思います。たぶん。
水曜日に始めたC言語の勉強で、せっかくだからパフォーマンスが要求されるようなプログラムを作ろうと思って考えたのがこれです。ってアルゴリズムの部分で高速化しても「Cで書いてよかった」という満足感は味わえないんですがね…。
class RingCalc:
def __init__(self, size):
self.size = size
self.Sx = size * (size - 1) / 2
self.Sx2 = sum([x * x for x in range(size)])
def setValues(self, values):
self.values = values[:self.size]
self.index = 0
self.initCalc()
for v in values[self.size:]:
self.append(v)
def append(self, value):
oldValue = self.values[self.index]
self.values[self.index] = value
self.index += 1
self.index %= self.size
self.stepCalc(oldValue, value)
def initCalc(self):
self.sumY = sum(self.values)
self.sumY2 = sum([y * y for y in self.values])
self.sumXY = sum([x * y for (x, y) in enumerate(self.values)])
self.calced()
def stepCalc(self, oldValue, value):
self.sumY = self.sumY - oldValue + value
self.sumY2 = self.sumY2 - oldValue ** 2 + value ** 2
self.sumXY = self.sumXY - self.sumY + self.size * value
self.calced()
def calced(self):
from math import sqrt
n = self.size
Sy2 = self.sumY2
Sy = self.sumY
Sxy = self.sumXY
Sx = self.Sx
Sx2 = self.Sx2
SySy = float(Sy * Sy)
SxSy = float(Sx * Sy)
SxSx = float(Sx * Sx)
Vxy = Sxy * n - SxSy
Vxx = Sx2 * n - SxSx
Vyy = Sy2 * n - SySy
print "ave:", Sy / n
print "var:", Vyy / n / (n - 1)
print "katamuki:", Vxy / Vxx
print "cor:", Vxy / sqrt (Vyy * Vxx)
フィードバック
西尾さん。この間のPython Edge 2007で司会をしていた二宮です。お疲れ様です。Pythonで相関係数を計算してみようと思ってネットで情報を探していたら、西尾さんのHPに行きつきました。PythonはエクセルのようなCORREL関数は持っていないのでしょうか?お時間のある時に、御願いします。