Цикл по индексам clump_masked - PullRequest
0 голосов
/ 17 мая 2018

У меня есть массив 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])

Это очень уродливый метод. и я думаю, что должен быть лучший способ сделать это. Есть предложения?

Спасибо!

1 Ответ

0 голосов
/ 18 мая 2018

РЕДАКТИРОВАТЬ:

Я нашел лучший способ достичь того, что, я думаю, вы хотите сделать.Этот код выбирает каждое окно из 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])
...