У меня есть массив значений MxN, взятый из эксперимента. Некоторые из этих значений являются недопустимыми и для них указывается 0. Я могу создать маску действительных/недопустимых значений, используя
mask = (mat1 == 0) & (mat2 == 0)
который создает массив MxN из bool. Следует отметить, что маскированные местоположения не аккуратно следуют за столбцами или строками матрицы - так что просто обрезка матрицы не является вариантом.
Теперь я хочу взять среднее значение вдоль одной оси моего массива (EG заканчивается массивом 1xN), исключая эти недопустимые значения в среднем вычислении. Интуитивно я подумал
np.mean(mat1[mask],axis=1)
должен сделать это, но mat1[mask]
создает 1D-массив, который, по-видимому, является только тем элементом, где mask
является истиной, что не помогает, когда мне нужно только среднее значение для одного измерения массива.
Есть ли способ "python-esque" или numpy для этого? Я предполагаю, что могу использовать маску для установки маскированных элементов в NaN
и использовать np.nanmean
- но это все еще кажется неуклюжим. Есть ли способ сделать это "чисто"?
Я думаю, что лучший способ сделать это - это нечто вроде:
masked = np.ma.masked_where(mat1 == 0 && mat2 == 0, array_to_mask)
Затем возьмите среднее значение с
masked.mean(axis=1)
Один такой же неуклюжий, но эффективный способ состоит в том, чтобы умножить ваш массив на маску, установив маскированные значения в ноль. Тогда, конечно, вам придется разделить на количество незамаскированных значений вручную. Отсюда и неуклюжесть. Но это будет работать с целочисленными массивами, что нельзя сказать о случае nan
. Он также кажется самым быстрым как для небольших, так и для больших массивов (в том числе решение маскированного массива в другом ответе):
import numpy as np
def nanny(mat, mask):
mat = mat.astype(float).copy() # don't mutate the original
mat[~mask] = np.nan # mask values
return np.nanmean(mat, axis=0) # compute mean
def manual(mat, mask):
# zero masked values, divide by number of nonzeros
return (mat*mask).sum(axis=0)/mask.sum(axis=0)
# set up dummy data for testing
N,M = 400,400
mat1 = np.random.randint(0,N,(N,M))
mask = np.random.randint(0,2,(N,M)).astype(bool)
print(np.array_equal(nanny(mat1, mask), manual(mat1, mask))) # True