Избегайте значений NaN и добавляйте две матрицы поэлементно в python - PullRequest
0 голосов
/ 01 июня 2018

У меня есть две 4D матрицы, которые я хотел бы добавить.Матрицы имеют одинаковую размерность и количество элементов, но обе они содержат случайно распределенные значения NaN.

Я бы предпочел добавить их, как показано ниже, используя numpy.nansum.
(1), если добавлено два значения, я хочу, чтобы сумма была значением,
(2), если значение иДобавлены NaN. Я хочу, чтобы сумма была значением, и
(3), если добавлено два NaN, я хочу, чтобы сумма была NaN.

При этом я пытался

a[6x7x180x360]
b[6x7x180x360]

C=np.nansum[(a,b)]
C=np.nansum(np.dstack((a,b)),2)

Но я не могу получить результирующую матрицу с тем же размером, что и для ввода.Это означает, что результирующая матрица C должна быть в [6x7x180x360].Любой может помочь в этом отношении.Заранее спасибо.

Ответы [ 3 ]

0 голосов
/ 01 июня 2018

Я считаю, что функция np.nansum не подходит в вашем случае.Если я правильно понимаю ваш вопрос, вы хотите сделать поэлементное добавление двух матриц с небольшой логикой в ​​отношении значений NaN.

Вот полный пример того, как это сделать:

import numpy as np

a = np.array([  [np.nan, 2],
                [3, np.nan]])

b = np.array([  [3, np.nan],
                [1, np.nan]])

result = np.add(a,b)

a_is_nan = np.isnan(a)
b_is_nan = np.isnan(b)

result_is_nan = np.isnan(result)

mask_a = np.logical_and(result_is_nan, np.logical_not(a_is_nan))
result[mask_a] = a[mask_a]

mask_b = np.logical_and(result_is_nan, np.logical_not(b_is_nan))
result[mask_b] = b[mask_b]

print(result)

Немного объяснения:

Первая операция - np.add (a, b).Это добавляет обе матрицы, и любой элемент NaN будет также давать результат NaN.

Чтобы выбрать значения NaN из любого массива, мы используем логическую маску:

# result_is_nan is a boolean array containing True whereve the result is np.NaN. This occurs when any of the two element were NaN
result_is_nan = np.isnan(result)

# mask_a is a boolean array which 'flags' elements that are NaN in result but were not NaN in a !
mask_a = np.logical_and(result_is_nan, np.logical_not(a_is_nan))
# Using that mask, we assign those value to result
result[mask_a] = a[mask_a]

Там у вас есть!

0 голосов
/ 01 июня 2018

Я думаю, что самый простой способ - использовать np.where

result = np.where(
    np.isnan(a+b),
    np.where(np.isnan(a), b, a), 
    a+b
)

Это читается как: если a+b не nan, используйте a+b, иначе используйте a, если толькоравен nan, затем используйте b.В любом случае, b nan не имеет большого значения.

Кроме того, вы можете использовать его следующим образом:

result2 = np.where(
    np.isnan(a) & np.isnan(b),
    np.nan,
    np.nansum(np.stack((a,b)), axis=0)
)

np.testing.assert_equal(result, result2) pass

0 голосов
/ 01 июня 2018

Вы можете использовать np.stack((a,b)) для суммирования по новой оси 0, а затем вызвать nansum для суммирования по этой оси 0:

C = np.nansum(np.stack((a,b)), axis=0)

ДляНапример,

In [34]: a = np.random.choice([1,2,3,np.nan], size=(6,7,180,360))

In [35]: b = np.random.choice([1,2,3,np.nan], size=(6,7,180,360))

In [36]: np.stack((a,b)).shape
Out[36]: (2, 6, 7, 180, 360)

In [37]: np.nansum(np.stack((a,b)), axis=0).shape
Out[37]: (6, 7, 180, 360)

У вас была правильная идея, но np.dstack стекается вдоль третьей оси, что здесь нежелательно, поскольку у вас уже есть 4 оси:

In [31]: np.dstack((a,b)).shape
Out[31]: (6, 7, 360, 360)

Относительно вашей точки зрения (3): Обратите внимание, что поведение np.nansum зависит от версии NumPy :

В версиях NumPy <= 1.8.0 Nan возвращается для срезов, которые являются полностью NaN или пустыми.В более поздних версиях возвращается ноль. </p>

Если вы используете версию NumPy> 1.8.0, то вам, возможно, придется использовать решение , такое как от Мартена Фабре, для решения этой проблемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...