我正在尝试估算adstock几何函数的参数(参数名称为alpha),但是PyMC3会以某种方式收敛到完全错误的结果。
我不确定这是否取决于我对adstock函数的执行情况或其他因素。
adstock函数由python中的以下代码定义:
def geometric_adstock_function(xx, alpha, normalize=True):
result = []
for i, x in enumerate(xx):
cumsum = 0
wcumsum = 0
for l in range(i + 1):
w = alpha ** l
cumsum += w * xx[i - l]
wcumsum += w
if not normalize:
result.append(cumsum)
else:
result.append(cumsum / wcumsum)
return np.array(result)
,然后使用
使用PyMC3定义用于参数估计的theano函数def geometric_adstock_theano(xx, alpha):
"""
This very complex function implement a normalized, geometric adstock using scan in theano
"""
def fn(x, prior_result, prior_norm, carry, prior_numerator, alpha):
carry = carry * alpha
new_norm = prior_norm + carry
new_result = (x + alpha * prior_numerator) / prior_norm
new_numerator = (x + alpha * prior_numerator)
return new_result, new_norm, carry, new_numerator
channel_adstock, updates = theano.scan(fn=fn,
sequences=[xx],
outputs_info=[tt.zeros_like(alpha), tt.ones_like(alpha),
tt.ones_like(alpha), tt.zeros_like(alpha)],
non_sequences=alpha)
return channel_adstock, updates
使用theano运行这两个函数时,它们返回相同的结果:
import theano
from theano import tensor as tt
alpha = tt.scalar("alpha",dtype='float64')
xx = tt.vector("X",dtype='float64')
channel_adstock,updates = geometric_adstock_theano(xx,alpha)
test_adstock = theano.function(inputs=[xx,alpha], outputs=channel_adstock, updates=updates)
#the two functions return the same result for the same value of alpha here 0.8
print(test_adstock([1.,0,0.,0, 0 , 0],.8)[0])
print(geometric_adstock_function([1.,0.,0.,0, 0, 0],.8))
但是,当使用PyMC3估算已知信号的alpha值时,我得到的估算值很差。
在theano中实现几何广告素材或在PyMC3代码中存在任何错误吗?
# defines groud truth for the original signal and the transformed one
true_alpha = 0.8
original = np.sin(np.linspace(0,np.pi*2*4,50))
transformed = geometric_adstock_function(original, alpha=true_alpha)
# tries to estimate alpha using pymc3
with pm.Model() as model:
alpha = pm.Beta('alpha', .5, .5)
channel_adstock, _ = geometric_adstock_theano(original, alpha)
likelyhood =pm.Normal('y',mu=channel_adstock,observed=transformed,sd=.001)
#map estimate for alpha also very off
map_estimate = pm.find_MAP(model=model, method='L-BFGS-B',start=dict(alpha=.8))
print(map_estimate)
#using the sampling strategy
with model:
trace = pm.sample(500, cores=2, tune=500)# use_mmap=True, nuts_kwargs=dict(target_accept=.99)) # draw 3000 posterior samples using NUTS sampling
result = pm.summary(trace)
print(result)
estimated_alpha = result.loc['alpha']['mean']
ppc = pm.sample_ppc(trace, samples=500, model=model)
mean_prediction = ppc['y'].mean(axis=0)[0]
# plotting some results
plt.figure(figsize = (12,20))
plt.subplot(1,2,1)
plt.plot(geometric_adstock_function([1,0,0,0,0,0],estimated_alpha),'-')
plt.plot(geometric_adstock_function([1,0,0,0,0,0],true_alpha),'-')
plt.legend(['kernel estimated','kernel original'])
plt.subplot(1,2,2)
plt.plot(geometric_adstock_function(original,estimated_alpha),'-')
plt.plot(geometric_adstock_function(original,true_alpha),'-')
plt.plot(mean_prediction)
plt.plot(theano_channel_adstock,'-')
plt.legend(['signal estimated','signal original','mean_prediction','theano result with true alpha'])