Параметры numpy из функции
Я еще не понял ключевые понятия в numpy
.
Я хотел бы создать трехмерный массив и заполнить каждую ячейку результатом вызова функции - то есть функция будет вызываться много раз с разными индексами и возвращать разные значения.
Примечание. После написания этого вопроса документация была обновлена, чтобы сделать ее более понятной.
Я мог бы создать его с нулями (или пустым), а затем перезаписать каждое значение с помощью цикла for, но кажется, что заполнение его непосредственно из функции кажется более чистым.
fromfunction
звучит идеально. Читая документацию, звучит так, как будто функция вызывается один раз для каждой ячейки.
Но когда я действительно попробую это...
from numpy import *
def sum_of_indices(x, y, z):
# What type are X, Y and Z ? Expect int or duck-type equivalent.
# Getting 3 individual arrays
print "Value of X is:"
print x
print "Type of X is:", type(x)
return x + y + z
a = fromfunction(sum_of_indices, (2, 2, 2))
Я ожидаю получить что-то вроде:
Value of X is:
0
Type of X is: int
Value of X is:
1
Type of X is: int
повторяется 4 раза.
Я получил:
Value of X is:
[[[ 0. 0.]
[ 0. 0.]]
[[ 1. 1.]
[ 1. 1.]]]
[[[ 0. 0.]
[ 1. 1.]]
[[ 0. 0.]
[ 1. 1.]]]
[[[ 0. 1.]
[ 0. 1.]]
[[ 0. 1.]
[ 0. 1.]]]
Type of X is: <type 'numpy.ndarray'>
Функция вызывается только один раз и, похоже, возвращает весь массив как результат.
Как правильно заполнить массив на основе нескольких вызовов функции индексов?
Ответы
Ответ 1
Я, очевидно, не давал себе понять. Я получаю ответы, что fromfunc
самом деле работает, как показывает мой тестовый код, что я уже знал, потому что мой тестовый код продемонстрировал это.
Ответ, который я искал, кажется, состоит из двух частей:
Документация fromfunc
вводит в заблуждение. Это работает, чтобы заполнить весь массив сразу.
Примечание. После написания этого вопроса документация была обновлена, чтобы сделать ее более понятной.
В частности, эта строка в документации была неверной (или, как минимум, вводящей в заблуждение)
Например, если shape
была (2, 2), то параметры в свою очередь были бы (0, 0), (0, 1), (1, 0), (1, 1).
Нет. Если бы shape
(т.е. из контекста, второй параметр функции fromfunction
) была (2,2), параметры были бы (не "по очереди", а в единственном вызове):
(array([[ 0., 0.], [ 1., 1.]]), array([[ 0., 1.], [ 0., 1.]]))
Документация была обновлена, и в настоящее время читается более точно:
Функция вызывается с N параметрами, где N - ранг формы. Каждый параметр представляет координаты массива, изменяющиеся вдоль определенной оси. Например, если бы форма была (2, 2), то параметрами были бы массив ([[0, 0], [1, 1]]) и массив ([[0, 1], [0, 1]])
(Мой простой пример, полученный из примеров в руководстве, мог ввести в заблуждение, потому что +
может работать как с массивами, так и с индексами. Эта неоднозначность является еще одной причиной, по которой документация неясна. Я хочу в конечном итоге использовать функцию, которая не ' • на основе массива, но на основе ячеек - например, каждое значение может быть получено из URL или базы данных на основе индексов или даже ввода от пользователя.)
Возвращаясь к проблеме - как я могу заполнить массив из функции, которая вызывается один раз для каждого элемента, ответ выглядит так:
Вы не можете сделать это в функциональном стиле.
Вы можете сделать это в императивном/итеративном стиле - т.е. писать вложенные циклы for и самостоятельно управлять длиной индекса.
Вы также можете сделать это как итератор, но итератору все еще нужно отслеживать свои собственные индексы.
Ответ 2
В этом отношении документация очень вводит в заблуждение. Это так же, как вы отмечаете: вместо выполнения f(0,0), f(0,1), f(1,0), f(1,1)
, numpy выполняет
f([[0., 0.], [1., 1.]], [[0., 1.], [0., 1.]])
Использование ndarrays, а не обещанных целых координат довольно сложно, когда вы пытаетесь использовать что-то вроде lambda i: l[i]
, где l
- это другой массив или список (хотя действительно есть, вероятно, лучшие способы сделать это в numpy).
Функция numpy vectorize
фиксирует это. Где у вас есть
m = fromfunction(f, shape)
Попробуйте использовать
g = vectorize(f)
m = fromfunction(g, shape)
Ответ 3
Я думаю, вы не понимаете, что из этой fromfunction
.
Из исходного кода numpy
.
def fromfunction(function, shape, **kwargs):
dtype = kwargs.pop('dtype', float)
args = indices(shape, dtype=dtype)
return function(*args,**kwargs)
Где indices
достаточно эквивалентны meshgrid
где каждая переменная np.arange(x)
.
>>> side = np.arange(2)
>>> side
array([0, 1])
>>> x,y,z = np.meshgrid(side,side,side)
>>> x
array([[[0, 0],
[1, 1]],
[[0, 0],
[1, 1]]])
>>> x+y+z #Result of your code.
array([[[0, 1],
[1, 2]],
[[1, 2],
[2, 3]]])
Ответ 4
Это дает вам неправильный результат? a
должно быть как и ожидалось (и это когда я его протестировал) и кажется прекрасным способом делать то, что вы хотите.
>>> a
array([[[ 0., 1.], # 0+0+0, 0+0+1
[ 1., 2.]], # 0+1+0, 0+1+1
[[ 1., 2.], # 1+0+0, 1+0+1
[ 2., 3.]]]) # 1+1+0, 1+1+1
Поскольку fromfunction
работает по индексам массивов для ввода, вы можете видеть, что ее нужно только один раз вызывать. Документация не делает это ясным, но вы можете видеть, что функция вызывается в массивах индексов в исходном коде (от numeric.py
):
def fromfunction(function, shape, **kwargs):
. . .
args = indices(shape, dtype=dtype)
return function(*args,**kwargs)
sum_of_indices
вызывается на входы массива, где каждый массив содержит значения индекса для этого измерения.
array([[[ 0., 0.],
[ 1., 1.]],
[[ 1., 1.],
[ 1., 1.]]])
+
array([[[ 0., 0.],
[ 1., 1.]],
[[ 0., 0.],
[ 1., 1.]]])
+
array([[[ 0., 1.],
[ 0., 1.]],
[[ 0., 1.],
[ 0., 1.]]])
=
array([[[ 1., 1.],
[ 1., 2.]],
[[ 1., 2.],
[ 2., 3.]]])