Как функция python может обрабатывать как матрицу numpy, так и скаляр?

Есть простая функция, которая принимает скалярный параметр, но работает и с пустой матрицей. Почему функция fun работает для матрицы?

>>> import numpy as np
>>> def fun(a):
      return 1.0 / a

>>> b = 2
>>> c = np.mat([1,2,3])
>>> c
matrix([[1, 2, 3]])

>>> fun(b)
0.5
>>> fun(c)
matrix([[ 1.        ,  0.5       ,  0.33333333]])

>>> v_fun = np.vectorize(fun)
>>> v_fun(b)
array(0.5)
>>> v_fun(c)
matrix([[ 1.        ,  0.5       ,  0.33333333]])

Кажется, что fun каким-то образом векторизована, потому что явно векторизованная функция v_fun ведет себя так же на матрице c. Но они получают разные результаты на скаляре b. Кто-нибудь может это объяснить? Спасибо.


person Cole    schedule 17.04.2017    source источник


Ответы (2)


То, что происходит в случае fun, называется трансляцией.

Общие правила вещания

При работе с двумя массивами NumPy сравнивает их формы по элементам. Он начинается с конечных размеров и продвигается вперед. Два измерения совместимы, когда

  1. они равны или
  2. один из них 1

Если эти условия не выполняются, выдается исключение ValueError: фреймы не выровнены, указывая на то, что массивы имеют несовместимые формы. Размер результирующего массива является максимальным размером по каждому измерению входных массивов.

person matusko    schedule 17.04.2017
comment
Спасибо. Мне очень помогло. - person Cole; 17.04.2017
comment
Размер результирующего массива равен максимальному размеру входных массивов по каждому измерению. На самом деле это немного неточно: np.zeros((1,0)) + np.zeros((3,1)) дает array([], shape=(3, 0), dtype=float64). - person Paul Panzer; 17.04.2017
comment
np.vectorize применяет широковещание при работе с 2 или более входными аргументами. Но эта функция принимает только один. - person hpaulj; 17.04.2017

fun уже работает как для скаляров, так и для массивов, потому что для обоих определено поэлементное деление (их собственные методы). fun(b) вообще не включает numpy, это просто операция Python.

np.vectorize предназначен для того, чтобы взять функцию, которая работает только со скалярами, и передать ей элементы из массива. В вашем примере он сначала преобразует b в массив np.array(b). И для c, и для этого модифицированного b результатом является массив соответствующего размера. c - это 2d np.matrix, и результат тот же. Обратите внимание, что fun(b) относится к типу array, а не matrix.

Это не хороший пример использования np.vectorize и не пример трансляции. np.vectorize — это довольно «простая» функция, которая не обрабатывает скаляры особым образом.

1/c или даже b/c работают, потому что c массив "знает" о делении. Аналогично определяется умножение и сложение массива: 1+c или 2*c.

У меня возникает соблазн пометить это как дубликат

Функция Python, которая обрабатывает скаляры или массивы

person hpaulj    schedule 17.04.2017