Вы можете попробовать решить свою проблему следующим образом:
# main ideas described in very high level pseudo code
choose suitable base kernel shape and type (gaussian?)
while true
loop over your array (moving average manner)
adapt your base kernel to current sparsity pattern
set current value based on adapted kernel
break if converged
На самом деле это можно реализовать довольно просто (особенно если производительность не является главной проблемой).
Очевидно, что это всего лишь эвристика, и вам нужно провести несколько экспериментов с вашими фактическими данными, чтобы найти подходящую схему адаптации. Если вы рассматриваете адаптацию ядра как повторное взвешивание ядра, вы можете захотеть сделать это в зависимости от того, как были распространены значения. Например, ваш вес для исходных опор равен 1, и они уменьшаются в зависимости от того, на какой итерации они возникли.
Также может быть непросто определить, когда этот процесс фактически сойдется. В зависимости от приложения, в конечном итоге может быть разумным оставить некоторые «области пробелов» «незаполненными».
Обновление. Вот очень простая реализация в соответствии со строками *), описанными выше:
from numpy import any, asarray as asa, isnan, NaN, ones, seterr
from numpy.lib.stride_tricks import as_strided as ast
from scipy.stats import nanmean
def _a2t(a):
"""Array to tuple."""
return tuple(a.tolist())
def _view(D, shape, strides):
"""View of flattened neighbourhood of D."""
V= ast(D, shape= shape, strides= strides)
return V.reshape(V.shape[:len(D.shape)]+ (-1,))
def filler(A, n_shape, n_iter= 49):
"""Fill in NaNs from mean calculated from neighbour."""
# boundary conditions
D= NaN* ones(_a2t(asa(A.shape)+ asa(n_shape)- 1), dtype= A.dtype)
slc= tuple([slice(n/ 2, -(n/ 2)) for n in n_shape])
D[slc]= A
# neighbourhood
shape= _a2t(asa(D.shape)- asa(n_shape)+ 1)+ n_shape
strides= D.strides* 2
# iterate until no NaNs, but not more than n iterations
old= seterr(invalid= 'ignore')
for k in xrange(n_iter):
M= isnan(D[slc])
if not any(M): break
D[slc][M]= nanmean(_view(D, shape, strides), -1)[M]
seterr(**old)
A[:]= D[slc]
И простая демонстрация filler(.)
в действии будет примерно такой:
In []: x= ones((3, 6, 99))
In []: x.sum(-1)
Out[]:
array([[ 99., 99., 99., 99., 99., 99.],
[ 99., 99., 99., 99., 99., 99.],
[ 99., 99., 99., 99., 99., 99.]])
In []: x= NaN* x
In []: x[1, 2, 3]= 1
In []: x.sum(-1)
Out[]:
array([[ nan, nan, nan, nan, nan, nan],
[ nan, nan, nan, nan, nan, nan],
[ nan, nan, nan, nan, nan, nan]])
In []: filler(x, (3, 3, 5))
In []: x.sum(-1)
Out[]:
array([[ 99., 99., 99., 99., 99., 99.],
[ 99., 99., 99., 99., 99., 99.],
[ 99., 99., 99., 99., 99., 99.]])
*) Итак, здесь nanmean(.)
просто используется для демонстрации идеи процесса адаптации. Основываясь на этой демонстрации, должно быть довольно просто реализовать более сложную схему адаптации и затухающего взвешивания. Также обратите внимание, что фактической производительности выполнения не уделяется внимания, но она все равно должна быть хорошей (с разумными формами ввода).
person
eat
schedule
05.04.2011