Np.where в матрице NumPy MxN, но возвращает M строк с индексами, в которых существует условие

Я пытаюсь использовать np.where в цифровой матрице MxN, где я хочу вернуть такое же количество строк M, но индексы в каждой строке, где существует элемент. Возможно ли это сделать? Например:

a = [[1 ,2, 2]
     [2, 3, 5]]

np.where(a == 2)

Я хотел бы, чтобы это вернулось:

[[1, 2],
 [0]]

Без использования явного цикла for такого решения, скорее всего, не существует. Проблема здесь в том, что каждая строка ожидаемого результата может иметь произвольную длину. С другой стороны, функции NumPy обычно оптимизируются для данных регулярной структуры (например, входных данных). Если вас устраивает петля for, то, конечно, можно просто применять np.where() отдельно в каждом ряду. Например, вы можете использовать result = [np.where(row == 2)[0].tolist() for row in a]

simon 15.07.2024 17:44

Спасибо. Я думаю, вы имеете в виду np.where(row == 2)[1] в своем ответе вместо np.where(row == 2)[0]

KidSudi 15.07.2024 17:58

Нет, я имею в виду np.where(row == 2)[0]; это потому, что каждый результат вызоваwhere возвращает кортеж. В данном случае это кортеж из одного элемента, и мы хотим получить первый (и единственный) элемент.

simon 15.07.2024 18:00

Попробуйте следующее: a = np.asarray([[1, 2, 2], [2, 3, 5]]); print([np.where(row == 2)[0].tolist() for row in a])

simon 15.07.2024 18:01

Понял, спасибо! В качестве дополнительного вопроса: могу ли я использовать этот результат для подмножества другой матрицы (те же размеры, что и результат np.where)? Причина в том, что я хочу рассчитать некоторую статистику для каждой строки (среднее значение, стандартное значение и т. д.).

KidSudi 15.07.2024 18:22

Ну собственно для этого и создан результат np.where. Если у вас есть другой массив MxN, скажем b = np.arange(6).reshape(2, 3), вы можете сделать b[np.where(a==2)]. Но ещё короче можно было бы написать b[a==2].

simon 15.07.2024 18:34

Но это выбирает все элементы в один массив, если я не ошибаюсь. Мне все еще нужно иметь M строк.

KidSudi 15.07.2024 18:42

Я думаю, ответ @mozway вас покрыл :)

simon 15.07.2024 19:30
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
8
72
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Один из вариантов — постобработка вывода где , а затем разделить:

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

i, j = np.where(a == 2)

out = np.split(j, np.diff(i).nonzero()[0]+1)

Альтернативно, используя понимание списка:

out = [np.where(x==2)[0] for x in a]

Выход:

[array([1, 2]), array([0])]

использование этого вывода для усреднения другого массива

a = np.array([[1, 2, 2], [2, 3, 5]])
b = np.array([[10, 20, 30], [40, 50, 60]])

m = a == 2
i, j = np.where(m)
# (array([0, 0, 1]), array([1, 2, 0]))

idx = np.r_[0, np.diff(i).nonzero()[0]+1]
# array([0, 2])

out = np.add.reduceat(b[m], idx)/np.add.reduceat(m[m], idx)
# array([50, 40])/array([2, 1])

Выход:

array([25., 40.])
обработка NaN:
a = np.array([[1, 2, 2], [2, 3, 5]])
b = np.array([[10, 20, np.nan], [40, 50, 60]])

m = a == 2
i, j = np.where(m)
# (array([0, 0, 1]), array([1, 2, 0]))

idx = np.r_[0, np.diff(i).nonzero()[0]+1]
# array([0, 2])

b_m = b[m]
# array([20., nan, 40.])
nans = np.isnan(b_m)
# array([False,  True, False])

out = np.add.reduceat(np.where(nans, 0, b_m), idx)/np.add.reduceat(~nans, idx)
# array([20., 40.])/array([1, 1])

Выход:

array([20., 40.])

Очень полезно, спасибо. Как я писал в комментариях выше, есть ли способ выбрать элементы по строке другой матрицы, используя «выходные» значения из вашей функции?

KidSudi 15.07.2024 18:58

@KidSudi, можешь привести пример? (вход + ожидаемый результат)

mozway 15.07.2024 19:00

так скажем так b = np.array([[10, 20, 30], [40, 50, 60]]). Я хочу, чтобы среднее значение каждой строки матрицы выбранных элементов использовало «выходные» значения, т. е. np.array([25, 40]).

KidSudi 15.07.2024 19:11

@KidSudi Понятно, это непросто (это мог быть другой вопрос), на самом деле лучше использовать другой метод без списка индексов, см. обновление.

mozway 15.07.2024 19:23

очень круто, спасибо за этот метод. Итак, похоже, что мы не можем использовать np.mean здесь для моего примера - на самом деле я собирался использовать np.nanmean, что может быть невозможно в этом решении?

KidSudi 15.07.2024 19:32

Ну можно, но без nanmean, см. обновление (это определенно должен был быть другой вопрос) ;)

mozway 15.07.2024 19:39

Большое спасибо. Согласен - обязательно должен быть в другом вопросе. У меня есть еще один, который я опубликую отдельно, но связанный :)

KidSudi 15.07.2024 21:29

Я добавил продолжение здесь: stackoverflow.com/questions/78751642/…

KidSudi 15.07.2024 21:42

На самом деле я сравнил это с написанной мной версией pandas и заметил, что есть много ошибок, особенно в начале набора данных (это временной ряд данных, содержащий около 100 000 строк и 1000 столбцов). Есть ли что-то, что мне здесь не хватает? Почему может быть такое несоответствие?

KidSudi 16.07.2024 00:41

ваш ввод представляет собой массив с плавающей запятой?

mozway 16.07.2024 07:27

Да, входные данные представляют собой массив float64.

KidSudi 16.07.2024 17:20

тогда np.diff(i).nonzero() может работать неправильно, отображая арифметику с плавающей запятой, вместо этого вам следует установить пороговое значение.

mozway 16.07.2024 17:37

Другие вопросы по теме