循环遍历clump_masked索引

时间:2018-05-17 15:30:39

标签: python numpy masked-array

我有一个包含一些屏蔽值的数组y_filtered。我希望将这些值替换为我根据其相邻值计算的某个值。我可以使用masked_slices = ma.clump_masked(y_filtered)获取被屏蔽值的索引。这将返回切片列表,例如[slice(194, 196, None)]

我可以使用y_filtered[masked_slices]轻松地从我的蒙面数组中获取值,甚至可以循环遍历它们。但是,我还需要访问值的索引,因此我可以根据其邻居计算其新值。枚举(逻辑上)返回0,1等,而不是我需要的索引。

这是我提出的解决方案。

# get indices of masked data
masked_slices = ma.clump_masked(y_filtered)

y_enum = [(i, y_i) for i, y_i in zip(range(len(y_filtered)), y_filtered)]

for sl in masked_slices:
    for i, y_i in y_enum[sl]:
        # simplified example calculation
        y_filtered[i] = np.average(y_filtered[i-2:i+2])

这是非常丑陋的方法i.m.o.我认为必须有一个更好的方法来做到这一点。有什么建议吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

编辑:

我想出了一个更好的方法来实现我想你想做的事情。此代码选取5个元素的每个窗口并计算其(屏蔽)平均值,然后使用这些值填充原始数组中的间隙。如果某个索引没有任何未屏蔽的值足够接近,则只会将其保留为蒙版:

import numpy as np
from numpy.lib.stride_tricks import as_strided

SMOOTH_MARGIN = 2
x = np.ma.array(data=[1, 2, 3, 4, 5, 6, 8, 9, 10],
                mask=[0, 1, 0, 0, 1, 1, 1, 1, 0])
print(x)
# [1 -- 3 4 -- -- -- -- 10]

pad_data = np.pad(x.data, (SMOOTH_MARGIN, SMOOTH_MARGIN), mode='constant')
pad_mask = np.pad(x.mask, (SMOOTH_MARGIN, SMOOTH_MARGIN), mode='constant',
                  constant_values=True)
k = 2 * SMOOTH_MARGIN + 1
isize = x.dtype.itemsize
msize = x.mask.dtype.itemsize
x_pad = np.ma.array(
    data=as_strided(pad_data, (len(x), k), (isize, isize), writeable=False),
    mask=as_strided(pad_mask, (len(x), k), (msize, msize), writeable=False))
x_avg = np.ma.average(x_pad, axis=1).astype(x_pad.dtype)
fill_mask = ~x_avg.mask & x.mask
result = x.copy() 
result[fill_mask] = x_avg[fill_mask]
print(result)
# [1 2 3 4 3 4 10 10 10]

(注意这里的所有值都是整数,因为x最初是整数类型)

原始发布的代码有一些错误,首先它在循环中从y_filtered读取和写入值,因此后面的索引的结果会受到先前迭代的影响,这可以通过副本修复原y_filtered。其次,[i-2:i+2]应该是[max(i-2, 0):i+3],以使对称窗口始终为零或更晚。

你可以这样做:

from itertools import chain

# get indices of masked data
masked_slices = ma.clump_masked(y_filtered)
for idx in chain.from_iterable(range(s.start, s.stop) for s in masked_slices):
    y_filtered[idx] = np.average(y_filtered[max(idx - 2, 0):idx + 3])