Использование Numpy.where() с функцией для каждого элемента

#numpy

#numpy

Вопрос:

У меня есть довольно сложная функция, скажем:

 def func(elem):
    // blah blah blah
    return True
    // blah blah blah
    return False
 

Я хочу использовать функцию numpy.where() в соответствии с

 arr2 = np.where(func(arr1), arr1, 0)
 

Но когда я пробую этот синтаксис и отлаживаю, я вижу func , что передается весь массив, а не отдельные элементы. Типичные варианты использования, которые я вижу в документации / примерах, основаны только на простых компараторах, таких как arr < 5 , но мне нужно что-то более причудливое, что я не хочу пытаться писать в одной строке.

Если это возможно, или если есть какая-то векторизованная замена (акцент на эффективности), любые идеи приветствуются.

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

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

Ответ №1:

Я понял, как это сделать, используя np.vectorize , за которым следует a list comprehension , not np.where . Возможно, из этого можно найти способ использовать numpy, а не для понимания списка.

 func_vec = np.vectorize(func)
[arr1 if cond else 0 for cond in func_vec(arr1)]
 

В любом случае, используя func_vec(arr1) вы получаете значения True / False для каждого элемента.


Примечание: если вам нужен новый массив типа arr1 , заменяющий на 0 элементы, которые возвращают False в вашей функции, то это должно сработать:

 arr2 = np.where(func_vec(arr1), arr1, 0)
 

Редактировать:

Действительно, np.vectorize не оптимизирован для производительности (по bad), по сути, является циклом for под капотом. Поэтому я бы рекомендовал попытаться написать вашу функцию векторизованным способом, а не пытаться векторизовать ее после этого.

Например, попробуйте преобразовать функцию следующим образом:

 def func(elem):
    if elem > 5:
        return True
    else:
        return False
 

для чего-то вроде этого:

 def func(elem):
    return elem > 5
 

так что вы можете легко применить func(arr1) без ошибок.

Если у вас действительно есть функция, которая возвращает просто True или False , я уверен, что вы сможете это сделать, независимо от ее сложности. В любом случае, мы здесь, чтобы помочь вам!

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

1. Хотя теперь, когда я пытаюсь это сделать, кажется, что это так же медленно, как просто перебирать массив и применять func. Интересно, существуют ли другие методы / ресурсы для эффективного применения функции к каждому элементу массива.

2. Эй, какой из фрагментов кода сработал для вас? Первый с list comprehension или последний с np.where ? Просто чтобы знать вашу цель…

3. За np.vectorize следует понимание списка. Ну, все это «сработало», это просто вопрос скорости.

4. Я отредактировал ответ. Я думаю, что лучший способ решить вашу проблему — это работать непосредственно в вашей функции. Дайте мне знать, если это сработает. Если нет, возможно, лучше удалить этот ответ как принятый, чтобы кто-то другой мог предложить лучшее решение.

Ответ №2:

Кажется, что вы пытаетесь получить arr1 нужные вам элементы, используя func функцию, но, судя по определению func , работает для одного элемента. Для этого вам нужен массив True / False той же формы, arr1 что и для этого.

Если я правильно понял, потенциальным решением было бы изменить func , чтобы работать со всем массивом, а не только с одним элементом, и возвращать массив True / False arr1.shape нужной вам формы np.where , поскольку вы хотите сделать это в одной строке таким образом.