У меня есть большой Numpy ndarray, вот пример:
myarray = np.array([[1.01,9.4,0.0,6.9,5.7],[1.9,2.6,np.nan,4.7,-2.45],[np.nan,0.2,0.3,4.2,15.1]])
myarray
array([[ 1.01, 9.4 , 0.0 , 6.9 , 5.7 ],
[ 1.9 , 2.6 , nan, 4.7 , -2.45],
[ nan, 0.2 , 0.3 , 4.2 , 15.1 ]])
Как видите, мой массив содержит числа с плавающей запятой, положительные, отрицательные, нули и NaN. Я хотел бы переназначить (переклассифицировать) значения в массиве на основе нескольких операторов if. Я прочитал много ответов и документов, но все, что я видел, относятся к простому одному или двум условиям, которые можно легко решить, например, с помощью np.where.
У меня есть несколько условий, для простоты скажем, у меня есть четыре условия (желаемое решение должно обрабатывать больше условий). Мои условия:
if x > 6*y:
x=3
elif x < 4*z:
x=2
elif x == np.nan:
x=np.nan # maybe pass is better?
else:
x=0
где x — значение в массиве, y и z — переменные, которые будут меняться между массивами. Например, массив № 1 будет иметь y = 5, z = 2, массив № 2 будет иметь y = 0,9, z = 0,5 и т. д. Условие для np.nan просто означает, что если значение равно nan, не изменяйте его, сохраните. нан.
Обратите внимание, что это нужно выполнять одновременно, потому что если я использую несколько np.where один за другим, то условие № 2 перезапишет условие № 1.
Я попытался создать функцию, а затем применить ее к массиву, но безуспешно. Кажется, что для того, чтобы применить функцию к массиву, функция должна включать только один аргумент (массив), а если я хочу использовать функцию, она должна содержать 3 аргумента: массив и значения y и z.
Что было бы наиболее эффективным способом достижения моей цели?
Пожалуйста, смотрите мой отредактированный вопрос. Спасибо
См. этот ответ.
Спасибо. Я пробовал это вложенное np.where раньше, и это не сработало, но теперь я скопировал и вставил синтаксис из ответа, который вы связали, и соответствующим образом изменил его, и, похоже, он работает. Если у меня есть несколько больших массивов, есть ли более эффективный способ добиться этого?
Это зависит от вашего варианта использования. Без дополнительных знаний я бы сказал, что вы можете создавать свои условия и варианты выбора также с несколькими массивами.
Вы можете рассчитать все маски условий по начальному x array.. Then use them sequentially to modify x`
@hpaulj, можешь подробнее?






In [11]: myarray = np.array([[1.01,9.4,0.0,6.9,5.7],[1.9,2.6,np.nan,4.7,-2.45],[
...: np.nan,0.2,0.3,4.2,15.1]])
In [13]: y, z = 0.9, 0.5
Если я выполню один из ваших тестов на всем массиве:
In [14]: mask1 = myarray >6*y
/usr/local/bin/ipython3:1: RuntimeWarning: invalid value encountered in greater
Это предупреждение вызывается np.nan.
Итак, давайте сначала определим эти nan (и заменим):
In [25]: mask0 = np.isnan(myarray)
In [26]: mask0
Out[26]:
array([[False, False, False, False, False],
[False, False, True, False, False],
[ True, False, False, False, False]])
In [27]: arr = myarray.copy()
In [28]: arr[mask0] = 0 # temp replace the nan with 0
myarray == np.nan не работает; он везде выдает False.
arr = np.nan_to_num(myarray) также работает, заменив nan на 0.
Теперь найдите маски для тестов y и z. Неважно, как они обрабатывают оригинал nan (теперь 0). Сначала рассчитайте обе маски, чтобы уменьшить взаимные помехи.
In [29]: mask1 = arr > 6*y
In [30]: mask2 = arr < 4*z
In [31]: arr[mask1]
Out[31]: array([ 9.4, 6.9, 5.7, 15.1])
In [32]: arr[mask2]
Out[32]: array([ 1.01, 0. , 1.9 , 0. , -2.45, 0. , 0.2 , 0.3 ])
In [33]: arr[mask0]
Out[33]: array([0., 0.])
Поскольку вы хотите, чтобы все остальное было равно 0, давайте инициализируем массив нулей:
In [34]: res = np.zeros_like(arr)
Теперь примените 3 маски:
In [35]: res[mask1] = 3
In [36]: res[mask2] = 2
In [37]: res[mask0] = np.nan
In [38]: res
Out[38]:
array([[ 2., 3., 2., 3., 3.],
[ 2., 0., nan, 0., 2.],
[nan, 2., 2., 0., 3.]])
Я мог бы применить маски к arr:
In [40]: arr[mask1] = 3 # np.where(mask1, 3, arr) should also work
In [41]: arr[mask2] = 2
In [42]: arr[mask0] = np.nan
In [43]: arr
Out[43]:
array([[2. , 3. , 2. , 3. , 3. ],
[2. , 2.6, nan, 4.7, 2. ],
[nan, 2. , 2. , 4.2, 3. ]])
Мне все еще нужно использовать некоторую логику, чтобы объединить маски, чтобы определить слоты, которые должны быть равны 0.
Хотя вы можете применять такие тесты к элементам
x, вы не можете применить их к самомуx.myarray>6— это логический массив, который не работает в контекстеif(а не вandилиor). Еще одно предостережение; не используйте== np.nan.