Необходимо сравнить два элемента массива внутри цикла for в Python 3 и получить ошибку «Значение истинности массива …»

#python-3.x #for-loop #if-statement #numpy-ndarray #boolean-operations

#python-3.x #for-цикл #if-оператор #numpy-ndarray #логические операции

Вопрос:

У меня есть массив numpy в виде:

 y_sol = 
[[0. 0. 1.]
 [0. 0. 1.]
 [0. 0. 1.]
 ...
 [1. 0. 0.]
 [0. 1. 0.]
 [1. 0. 0.]]
  

и мне нужно перевести его для категориального строкового значения, используя корреляции, заданные списком кортежей:

 transf_codes = [('Alert', [1., 0., 0.]),     
                ('Neutral', [0., 1., 0.]),     
                ('Urgent', [0., 0., 1.])]   
  

Обратите внимание, что я не использовал здесь словарь, чтобы избежать осложнений при поиске ключей, имеющих значения в качестве входных данных для поиска.

Во всяком случае, я попробовал следующий код, чтобы выполнить работу:

 for i in np.arange(len(y_sol)-1): 
    for j in np.arange(3):
        if np.equal(transf_codes[j][1], y_sol[i].all()):  # <-error line 
            y_categ[i] = transf_codes[j][0] 
  

и я получаю ошибку «Значение истинности массива с более чем одним элементом неоднозначно. Используйте .any() или.all() «

В строке «if» выше более естественная форма >>> transf_codes[j][1] == y_sol[i] <<< , с или без .all() или .any(), вызывает ту же ошибку.

Каков правильный и наилучший подход для поэлементного сравнения массивов, списков и т. Д. в if-инструкции?

Заранее большое спасибо.

Ответ №1:

Ошибка, которую вы видите, возникает всякий раз, когда numpy пытается преобразовать массив в логическое значение. Он не понимает, как это сделать, поэтому выдает эту ошибку.

Поэтому, когда вы делаете что-то подобное if (a == b) с a, b являющимися массивами, вы получаете ошибку.

Однако a == b это приведет к логическому массиву с поэлементным сравнением. Обратите внимание, что для этого a b должны быть массивы numpy. Поведение списка отличается.

Один из способов, которым мы могли бы использовать логический массив, — это метод np.all, который, как я вижу, вы использовали, но не в нужном месте. В настоящее время вы выполняете .all() на y_sol[i] .

Итак, следующий код и выходные данные являются правильными.

 import numpy as np
y_sol = np.array( 
[[0., 0., 1.],
 [0., 0., 1.],
 [0., 0., 1.],
 [1., 0., 0.],
 [0., 1., 0.],
 [1., 0., 0.]])

transf_codes = [('Alert', [1., 0., 0.]),
                ('Neutral', [0., 1., 0.]),
                ('Urgent', [0., 0., 1.])]

for i in np.arange(len(y_sol)-1):
    for j in np.arange(3):
        if (transf_codes[j][1] == y_sol[i]).all():  # <-error line
            print(f'y_sol[i]={y_sol[i]}, transf_codes={transf_codes[j][0]}')
  

И это выводит:

 y_sol[i]=[0. 0. 1.], transf_codes=Urgent
y_sol[i]=[0. 0. 1.], transf_codes=Urgent
y_sol[i]=[0. 0. 1.], transf_codes=Urgent
y_sol[i]=[1. 0. 0.], transf_codes=Alert
y_sol[i]=[0. 1. 0.], transf_codes=Neutral
  

Обратите внимание, что я использовал .all() после сравнения векторов.

Комментарии:

1. Привет, Йонатан, добрый день! Большое вам спасибо за ваш быстрый ответ. Полностью разобрался. Только одно сомнение, связанное с вашим комментарием: «Обратите внимание, что для этого a, b должны быть массивами numpy. Поведение списка отличается «. В приведенном выше сравнении есть список (кортежей) и массив numpy, но магия сработала нормально, как я и хотел. PS: У меня недостаточно очков, чтобы проголосовать за ваш ответ. 🙂

2. С удовольствием 🙂 О списках — это было общее замечание, поскольку, когда вы вообще не вызываете функции numpy, некоторые действия отличаются, например: [1, 0] == [1, 0] дает одно логическое значение = True. Но если вы используете «np.equal», он возвращает [True, True] . Хорошего дня 🙂