我有一系列日期和每个日期的衡量标准。我想计算每个日期的指数移动平均线。有人知道怎么做吗?
我是python的新手。看起来平均值并没有内置到标准的python库中,这让我觉得有些奇怪。也许我找不到合适的地方。
因此,鉴于以下代码,我如何计算日历日期的IQ点的移动加权平均值?
from datetime import date
days = [date(2008,1,1), date(2008,1,2), date(2008,1,7)]
IQ = [110, 105, 90]
(可能有更好的方法来构建数据,任何建议都会受到赞赏)
答案 0 :(得分:19)
编辑:
来自mov_average_expw()
的scikits.timeseries.lib.moving_funcs子模块中的SciKits函数(补充SciPy的附加工具包)似乎更适合您的问题的措辞。
使用平滑因子alpha
计算exponential smoothing数据(维基百科条款为(1 - alpha)
):
>>> alpha = 0.5
>>> assert 0 < alpha <= 1.0
>>> av = sum(alpha**n.days * iq
... for n, iq in map(lambda (day, iq), today=max(days): (today-day, iq),
... sorted(zip(days, IQ), key=lambda p: p[0], reverse=True)))
95.0
以上不是很好,所以让我们稍微重构一下:
from collections import namedtuple
from operator import itemgetter
def smooth(iq_data, alpha=1, today=None):
"""Perform exponential smoothing with factor `alpha`.
Time period is a day.
Each time period the value of `iq` drops `alpha` times.
The most recent data is the most valuable one.
"""
assert 0 < alpha <= 1
if alpha == 1: # no smoothing
return sum(map(itemgetter(1), iq_data))
if today is None:
today = max(map(itemgetter(0), iq_data))
return sum(alpha**((today - date).days) * iq for date, iq in iq_data)
IQData = namedtuple("IQData", "date iq")
if __name__ == "__main__":
from datetime import date
days = [date(2008,1,1), date(2008,1,2), date(2008,1,7)]
IQ = [110, 105, 90]
iqdata = list(map(IQData, days, IQ))
print("\n".join(map(str, iqdata)))
print(smooth(iqdata, alpha=0.5))
示例:
$ python26 smooth.py
IQData(date=datetime.date(2008, 1, 1), iq=110)
IQData(date=datetime.date(2008, 1, 2), iq=105)
IQData(date=datetime.date(2008, 1, 7), iq=90)
95.0
答案 1 :(得分:9)
我做了一些谷歌搜索,我找到了以下示例代码(http://osdir.com/ml/python.matplotlib.general/2005-04/msg00044.html):
def ema(s, n):
"""
returns an n period exponential moving average for
the time series s
s is a list ordered from oldest (index 0) to most
recent (index -1)
n is an integer
returns a numeric array of the exponential
moving average
"""
s = array(s)
ema = []
j = 1
#get n sma first and calculate the next n period ema
sma = sum(s[:n]) / n
multiplier = 2 / float(1 + n)
ema.append(sma)
#EMA(current) = ( (Price(current) - EMA(prev) ) x Multiplier) + EMA(prev)
ema.append(( (s[n] - sma) * multiplier) + sma)
#now calculate the rest of the values
for i in s[n+1:]:
tmp = ( (i - ema[j]) * multiplier) + ema[j]
j = j + 1
ema.append(tmp)
return ema
答案 2 :(得分:8)
我总是用熊猫计算EMA:
以下是如何操作的示例:
import pandas as pd
import numpy as np
def ema(values, period):
values = np.array(values)
return pd.ewma(values, span=period)[-1]
values = [9, 5, 10, 16, 5]
period = 5
print ema(values, period)
关于熊猫EWMA的更多信息:
http://pandas.pydata.org/pandas-docs/stable/generated/pandas.ewma.html
答案 3 :(得分:5)
我的python有点生疏(任何人都可以随意编辑此代码进行更正,如果我以某种方式搞砸了语法),但这里有....
def movingAverageExponential(values, alpha, epsilon = 0):
if not 0 < alpha < 1:
raise ValueError("out of range, alpha='%s'" % alpha)
if not 0 <= epsilon < alpha:
raise ValueError("out of range, epsilon='%s'" % epsilon)
result = [None] * len(values)
for i in range(len(result)):
currentWeight = 1.0
numerator = 0
denominator = 0
for value in values[i::-1]:
numerator += value * currentWeight
denominator += currentWeight
currentWeight *= alpha
if currentWeight < epsilon:
break
result[i] = numerator / denominator
return result
此函数从列表末尾向后移动,通过向后工作计算每个值的指数移动平均值,直到元素的权重系数小于给定的epsilon。
在函数结束时,它会在返回列表之前反转值(这样它们对调用者的顺序正确)。
(侧面注意:如果我使用的语言不是python,我首先创建一个全尺寸的空数组,然后按顺序填充它,这样我就不必在最后反转它了。但是我不认为你可以在python中声明一个大的空数组。而在python列表中,追加比预先添加要便宜得多,这就是为什么我以相反的顺序构建列表。如果我错了,请纠正我。)
'alpha'参数是每次迭代的衰减因子。例如,如果您使用0.5的alpha,那么今天的移动平均值将由以下加权值组成:
today: 1.0
yesterday: 0.5
2 days ago: 0.25
3 days ago: 0.125
...etc...
当然,如果你有大量的价值观,那么十天或十五天前的价值对今天的加权平均数的贡献不大。 'epsilon'参数允许您设置一个截止点,低于该截止点您将不再关注旧值(因为它们对今天的价值的贡献将是无关紧要的。)
你会调用这样的函数:
result = movingAverageExponential(values, 0.75, 0.0001)
答案 4 :(得分:5)
在matplotlib.org示例(http://matplotlib.org/examples/pylab_examples/finance_work2.html)中提供了使用numpy的指数移动平均值(EMA)函数的一个很好的例子:
def moving_average(x, n, type):
x = np.asarray(x)
if type=='simple':
weights = np.ones(n)
else:
weights = np.exp(np.linspace(-1., 0., n))
weights /= weights.sum()
a = np.convolve(x, weights, mode='full')[:len(x)]
a[:n] = a[n]
return a
答案 5 :(得分:4)
我不知道Python,但对于平均部分,你的意思是指数形式的指数衰减低通滤波器
y_new = y_old + (input - y_old)*alpha
其中alpha = dt / tau,dt =滤波器的时间步长,tau =滤波器的时间常数? (变量 - 时间步形式如下,只是剪辑dt / tau不超过1.0)
y_new = y_old + (input - y_old)*dt/tau
如果您想过滤类似日期的内容,请确保转换为自1970年1月1日以来的秒数#浮点数。
答案 6 :(得分:4)
您也可以使用SciPy过滤器方法,因为EMA是IIR过滤器。与 enumerate()方法相比,在大型数据集上使用 timeit 在我的系统上测得的速度大约快64倍。
import numpy as np
from scipy.signal import lfilter
x = np.random.normal(size=1234)
alpha = .1 # smoothing coefficient
zi = [x[0]] # seed the filter state with first value
# filter can process blocks of continuous data if <zi> is maintained
y, zi = lfilter([1.-alpha], [1., -alpha], x, zi=zi)
答案 7 :(得分:2)
我发现@earino上面的代码片段非常有用 - 但是我需要能够不断平滑价值流的东西 - 所以我重构了它:
def exponential_moving_average(period=1000):
""" Exponential moving average. Smooths the values in v over ther period. Send in values - at first it'll return a simple average, but as soon as it's gahtered 'period' values, it'll start to use the Exponential Moving Averge to smooth the values.
period: int - how many values to smooth over (default=100). """
multiplier = 2 / float(1 + period)
cum_temp = yield None # We are being primed
# Start by just returning the simple average until we have enough data.
for i in xrange(1, period + 1):
cum_temp += yield cum_temp / float(i)
# Grab the timple avergae
ema = cum_temp / period
# and start calculating the exponentially smoothed average
while True:
ema = (((yield ema) - ema) * multiplier) + ema
我这样用它:
def temp_monitor(pin):
""" Read from the temperature monitor - and smooth the value out. The sensor is noisy, so we use exponential smoothing. """
ema = exponential_moving_average()
next(ema) # Prime the generator
while True:
yield ema.send(val_to_temp(pin.read()))
(其中pin.read()产生我想要消耗的下一个值)。
答案 8 :(得分:1)
以下是我根据http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_averages
编写的一个简单示例请注意,与他们的电子表格不同,我不会计算SMA,并且我不会等待10个样本后生成EMA。这意味着我的值稍有不同,但是如果你绘制图表,它会紧跟在10个样本之后。在前10个样本期间,我计算的EMA被适当地平滑。
def emaWeight(numSamples):
return 2 / float(numSamples + 1)
def ema(close, prevEma, numSamples):
return ((close-prevEma) * emaWeight(numSamples) ) + prevEma
samples = [
22.27, 22.19, 22.08, 22.17, 22.18, 22.13, 22.23, 22.43, 22.24, 22.29,
22.15, 22.39, 22.38, 22.61, 23.36, 24.05, 23.75, 23.83, 23.95, 23.63,
23.82, 23.87, 23.65, 23.19, 23.10, 23.33, 22.68, 23.10, 22.40, 22.17,
]
emaCap = 10
e=samples[0]
for s in range(len(samples)):
numSamples = emaCap if s > emaCap else s
e = ema(samples[s], e, numSamples)
print e
答案 9 :(得分:0)
快速方式(从here复制粘贴)如下:
middle
答案 10 :(得分:0)
我正在使用一个列表和一个衰减率作为输入。考虑到深度递归在python中不稳定,我希望只有两行的小功能可以对您有所帮助。
def expma(aseries, ratio):
return sum([ratio*aseries[-x-1]*((1-ratio)**x) for x in range(len(aseries))])
答案 11 :(得分:0)
使用熊猫更简单
namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\SoftDeletes;
use Laravel\Lumen\Auth\Authorizable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
class Offer extends Model implements AuthenticatableContract, AuthorizableContract
{
use Authenticatable, Authorizable, SoftDeletes;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'info_id','approved','expiry','branch_id'
];
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
protected $hidden = ['deleted_at'];
public $timestamps = true;
protected $dates = [
'deleted_at'
];
public function prices()
{
return $this->hasMany('App\OfferPrice');
}
public function information()
{
return $this->belongsTo('App\Information');
}
}
答案 12 :(得分:0)
可能最短:
#Specify decay in terms of span
#data_series should be a DataFrame
ema=data_series.ewm(span=5, adjust=False).mean()
答案 13 :(得分:0)
当我尝试使用代码时,出现以下错误。
非常感谢您的帮助
a[:n] = a[n]
IndexError:索引26超出了尺寸为1的轴0的边界
答案 14 :(得分:0)
Papahaba的答案几乎是我想要的(谢谢!),但是我需要匹配初始条件。将IIR滤波器与scipy.signal.lfilter
配合使用无疑是最有效的。这是我的redux:
给出一个NumPy向量x
import numpy as np
from scipy import signal
period = 12
b = np.array((1,), 'd')
a = np.array((period, 1-period), 'd')
zi = signal.lfilter_zi(b, a)
y, zi = signal.lfilter(b, a, x, zi=zi*x[0:1])
获取向量y
中返回的N点EMA(此处为12)
答案 15 :(得分:0)
我参加聚会有点晚了,但给出的解决方案都不是我想要的。使用递归和投资百科中给出的确切公式的小挑战。 不需要 numpy 或 pandas。
prices = [{'i': 1, 'close': 24.5}, {'i': 2, 'close': 24.6}, {'i': 3, 'close': 24.8}, {'i': 4, 'close': 24.9},
{'i': 5, 'close': 25.6}, {'i': 6, 'close': 25.0}, {'i': 7, 'close': 24.7}]
def rec_calculate_ema(n):
k = 2 / (n + 1)
price = prices[n]['close']
if n == 1:
return price
res = (price * k) + (rec_calculate_ema(n - 1) * (1 - k))
return res
print(rec_calculate_ema(3))