Посчитать mean в Numpy игнорируя 0

Рейтинг: 1Ответов: 3Опубликовано: 10.06.2023

у меня есть три массива 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 при подсчете. может быть есть какой-то метод? или нужно через маску создать новый массив? но тогда пропадет кол-во измерений, не? или через фильтр лямбда?

Ответы

▲ 1Принят

Есть такое предложение. Сначала поменяем нули на 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.

▲ 6

numpy.mean имеет параметр where, который позволяет отбирать значения для рассчета среднего:

np.mean(a, axis=axis, where=a != 0)
▲ 3

Можно использовать функцию 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)