Принимая среднее значение numpy ndarray с замаскированными элементами - PullRequest
0 голосов
/ 16 октября 2018

У меня есть массив значений MxN, взятых из эксперимента.Некоторые из этих значений недействительны и установлены в 0, чтобы указать на это.Я могу создать маску допустимых / недействительных значений, используя

mask = (mat1 == 0) & (mat2 == 0)

, которая создает массив MxN bool.Следует отметить, что замаскированные местоположения не следуют аккуратно за столбцами или строками матрицы - поэтому просто обрезать матрицу не вариант.

Теперь я хочу взять среднее значение вдоль одной оси моего массива (EG в конечном итоге с массивом 1xN), исключая эти недопустимые значения в вычислении среднего.Интуитивно я подумал, что

 np.mean(mat1[mask],axis=1)

должен это сделать, но операция mat1[mask] создает одномерный массив, который выглядит как элементы, для которых mask истинно - что не помогает, когда я хочу толькоИмеется в виду по одному измерению массива.

Есть ли «питон-esque» или простой способ сделать это?Я полагаю, я мог бы использовать маску для установки маскируемых элементов на NaN и использовать np.nanmean - но это все еще кажется неуклюжим.Есть ли способ сделать это «чисто»?

Ответы [ 2 ]

0 голосов
/ 16 октября 2018

Один такой же неуклюжий, но эффективный способ - умножить ваш массив на маску, установив маскированные значения на ноль.Тогда, конечно, вам придется разделить число немаскированных значений вручную.Отсюда и грубость.Но это будет работать с целочисленными массивами, чего нельзя сказать о случае 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
0 голосов
/ 16 октября 2018

Я думаю, что лучшим способом сделать это было бы что-то вроде:

masked = np.ma.masked_where(mat1 == 0 && mat2 == 0, array_to_mask)

Затем возьмите среднее значение с

masked.mean(axis=1)
...