Посчитать mean в Numpy игнорируя 0
у меня есть три массива np.array: одномерный, двухмерный и трехмерный. в каждом массиве есть значения от 0 до 4. необходимо посчитать средние mean (в том числе и с axis), но с условием, что 0-ые значения игнорируются при подсчете среднего
train_1 = np.random.randint(0,4*10+1,12)
array([17, 28, 9, 0, 39, 31, 28, 19, 13, 9, 5, 20])
train_1.sum(),round(train_1.mean(),1)
(218, 18.2)
train_2 = np.random.randint(0,4+1,12*10).reshape(12,-1)
array([[2, 1, 4, 4, 1, 3, 4, 2, 2, 0],
[4, 0, 4, 3, 3, 4, 3, 3, 4, 1],
[2, 3, 1, 1, 0, 0, 4, 0, 1, 3],
[1, 4, 3, 0, 2, 3, 4, 1, 4, 1],
[1, 2, 3, 2, 4, 2, 0, 0, 0, 4],
[4, 1, 2, 3, 3, 1, 3, 4, 4, 3],
[3, 3, 2, 4, 3, 1, 2, 3, 2, 3],
[1, 1, 0, 1, 3, 4, 3, 0, 1, 4],
[2, 0, 3, 0, 1, 0, 4, 0, 1, 4],
[4, 1, 0, 3, 1, 4, 1, 3, 4, 0],
[4, 2, 0, 4, 2, 4, 2, 4, 4, 2],
[2, 4, 1, 3, 4, 2, 4, 4, 0, 2]])
train_3 = np.random.randint(0,2+1,12*10*2).reshape(2,12,10)
array([[[1, 1, 0, 0, 0, 2, 1, 1, 2, 0],
[2, 1, 2, 1, 1, 0, 0, 1, 0, 0],
[2, 0, 2, 2, 1, 2, 1, 2, 0, 2],
[1, 0, 2, 1, 2, 2, 1, 0, 2, 0],
[1, 1, 2, 0, 0, 2, 0, 0, 2, 1],
[2, 1, 1, 1, 0, 2, 1, 1, 1, 0],
[0, 0, 2, 2, 0, 1, 0, 1, 2, 2],
[1, 0, 0, 1, 1, 2, 0, 1, 2, 0],
[1, 0, 1, 2, 1, 1, 0, 0, 0, 0],
[2, 2, 2, 0, 2, 0, 2, 2, 2, 1],
[2, 2, 2, 1, 0, 2, 0, 1, 2, 0],
[1, 1, 1, 0, 2, 1, 0, 1, 2, 1]],
[[1, 1, 1, 2, 1, 2, 1, 2, 1, 2],
[0, 2, 0, 1, 1, 2, 2, 1, 2, 2],
[1, 2, 1, 0, 0, 2, 2, 1, 0, 1],
[1, 1, 1, 0, 2, 1, 0, 2, 0, 1],
[2, 1, 0, 0, 0, 0, 2, 0, 1, 2],
[0, 0, 1, 0, 2, 1, 1, 0, 0, 0],
[0, 2, 1, 2, 1, 0, 1, 1, 0, 1],
[2, 0, 2, 0, 1, 1, 2, 1, 2, 1],
[2, 2, 0, 1, 0, 1, 0, 0, 0, 0],
[1, 2, 1, 0, 0, 2, 1, 0, 0, 0],
[1, 0, 2, 2, 0, 2, 1, 2, 0, 2],
[0, 1, 1, 1, 1, 2, 0, 0, 2, 2]]])
как можно заметить, mean учитывает и 0-ые значения. а я бы хотел игнорировать 0 при подсчете. может быть есть какой-то метод? или нужно через маску создать новый массив? но тогда пропадет кол-во измерений, не? или через фильтр лямбда?
Ответы (3 шт):
Есть такое предложение. Сначала поменяем нули на np.nan. А затем применяем np.nanmean(). Получаем что требуется. Как-то так:
import numpy as np
# генерим массив хотя бы с одним нулем
train_1 = np.random.randint(0, 4 * 10 + 1, 12)
while ~np.any((train_1 == 0)):
train_1 = np.random.randint(0, 4 * 10 + 1, 12)
print(train_1)
print(np.mean(train_1))
# меняем нули на np.nan
train_1_float = train_1.astype(np.float16)
train_1_float[train_1_float == 0] = np.nan
# приходится приводить к float иначе не заменим на np.nan
print(train_1_float)
print(round(np.nanmean(train_1_float), 1))
Разумеется, это если не беспокоит приведение к float.
numpy.mean имеет параметр where, который позволяет отбирать значения для рассчета среднего:
np.mean(a, axis=axis, where=a != 0)
Можно использовать функцию np.ma.masked_equal() для создания маски непосредственно при подсчете среднего значения, без явного создания отдельной маски.
mean = np.ma.masked_equal(train_x, 0).mean()
В mean(axis=x) можно указать axis если нужно вычислить среднее только по определенным осям, для 3-мерного массива все средние будут высчитываться как-то так:
mean = np.ma.masked_equal(train_x, 0).mean()
mean_axis0 = np.ma.masked_equal(train_x, 0).mean(axis=0)
mean_axis1 = np.ma.masked_equal(train_x, 0).mean(axis=1)
mean_axis2 = np.ma.masked_equal(train_x, 0).mean(axis=2)