Могу ли я векторизовать понимание списка, используя np.vectorize ()? - PullRequest
1 голос
/ 13 февраля 2020

Я довольно новичок в Python, начал с NumPy.
Я пытался сделать следующее:

a = np.arange(1, 20)  
f = np.vectorize([x/(x+1) for x in a])  
f(a)  
TypeError: 'list' object is not callable <-- got this error

Поэтому мне было интересно, возможно ли векторизовать понимание списка? что значит «объект не может быть вызван»? За будущее спасибо заранее

Ответы [ 3 ]

1 голос
/ 13 февраля 2020

Не тратьте время на попытки использовать np.vectorize, особенно когда вы можете сделать real numpy векторизацию. Не обманывайте себя по имени. Это не короткий путь к быстрым вычислениям чисел c.

In [442]: a = np.arange(1,5)

понимание вашего списка:

In [443]: [x/(x+1) for x in a]
Out[443]: [0.5, 0.6666666666666666, 0.75, 0.8]

можно сделать с помощью простой операции numpy массива:

In [444]: a/(a+1)
Out[444]: array([0.5, 0.66666667, 0.75, 0.8])

Но давайте представим, что у нас есть функция s, которая работает только со скалярными входами:

In [445]: f = np.vectorize(lambda x: x/(x+1), otypes=[float])
In [446]: f(a)
Out[446]: array([0.5, 0.66666667, 0.75 , 0.8])

Она работает, но намного медленнее, чем [444], и не быстрее, чем [443 ].

1 голос
/ 13 февраля 2020

Поэтому мне было интересно, возможно ли векторизовать понимание списка.

np.vectorize преобразует функцию в функцию, которая принимает массивы в качестве входных данных. Затем вы можете использовать его вместо понимания списка.

Но он не «векторизует» операцию с точки зрения производительности. На самом деле, он часто медленнее и используется для тестирования или для корректировки синтаксиса.

Кроме того, что означает «объект не подлежит вызову»?

В Python, «вызываемый» - это объект, который можно использовать «как функцию». Конечно, функции могут быть вызваны. Вы можете добавить метод __call__ к другим объектам.

Ниже приведен пример класса, который имеет метод __call__.

In [33]: class myclass():
    ...:     def __init__(self):
    ...:         pass
    ...:     def __call__(self, x):
    ...:         return x**2
    ...: 
    ...: 

In [34]: A = myclass()

In [35]: A(10)
Out[35]: 100

[x/(x+1) for x in a] - это выражение, это возвращает значение и не может быть вызван. Аргумент np.vectorize должен быть вызываемым.

Другие здесь предлагают использовать np.vectorize(lambda x: x/(1+x)) или

def f(x):
    return x/(1+x)

f_vec = np.vectorize(f)

Первый - это «лямбда-функция», второй - обычные функции. Оба могут быть вызваны.

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

y = x/(1+x)

, и для этого будут использоваться операции NumPy. Поскольку x является массивом, это считается формой векторизации (вычисления будут выполняться в оптимизированном и векторизованном коде C ++).

Для более сложных вычислений ищите Cython, numbersxpr или Numba.

0 голосов
/ 13 февраля 2020

Я думаю, вы можете быть немного озадачены тем, что понимает список и что делает np.vectorize. np.vectorize изменяет функцию таким образом, чтобы ее можно было применить к списку в целом. То, что вы должны использовать -

def foo(x):
    return(x/(x+1))

f = np.vectorize(foo)
a = np.arange(1, 20) 

f(a)

Использование [x/(x+1) for x in a] даст вам тот же результат, что и f (a), только время выполнения будет другим.

Причина, по которой вы ошибка «list not callable» вызвана тем, что f - это список, а не функция, и вы пытаетесь передать аргумент (a) списку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...