#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] . Хорошего дня 🙂