2013-09-09 3 views
20

Я еще не рассмотрел ключевые понятия в numpy.Параметры для функции numpy

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

Я мог бы создать его с нулями (или пустым), а затем перезаписать каждое значение с помощью цикла for, но кажется, что он чист, чтобы заполнить его непосредственно из функции.

fromfunction звучит идеально. Reading the documentation звучит так, как функция вызывается один раз на ячейку.

Но когда я на самом деле попробовать ...

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'> 

функция вызывается только один раз, и, кажется, возвращает весь массив в качестве результата.

Каков правильный способ заполнения массива на основе нескольких вызовов функции индексов?

+0

Что ваш ожидаемый результат? из функции вызывается один раз на ячейку - что вы подразумеваете под «множественными вызовами функции индексов»? – YXD

+0

В вашем первом блоке кода 'a' является вашим заполненным массивом, где' a [i, j, k] = sum_of_indices (i, j, k) ' – YXD

+0

Извините, я думал, что ожидаемый результат был ясен из комментариев. Я расширился. Да, я знаю, что «a» - это заполненный массив, но (я полагаю) только из-за добавления массива. Когда я заменяю sum_of_indices на «реальную» функцию (например,поиск базы данных), что будет невозможно. – Oddthinking

ответ

14

Я, очевидно, не уточнил. Я получаю ответы, что fromfunc действительно работает, как показывает мой тестовый код, который я уже знал, потому что мой тестовый код продемонстрировал это.

Ответ, который я искал, кажется, в двух частях:


fromfunc документация вводит в заблуждение. Он работает, чтобы заполнить весь массив сразу.

В частности, эта линия в documentation неверно (или в самом минимуме, вводящим в заблуждение)

Например, если shape были (2, 2), то параметры, в свою очередь быть (0, 0), (0, 1), (1, 0), (1, 1).

No. Если shape (т.е. из контекста, то второй параметр в fromfunction) были (2,2), параметры были бы (не 'в свою очередь', но в единственном вызове):

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

(Мой простой пример, полученный из примеров в руководстве, возможно, вводил в заблуждение, поскольку + может работать как с массивами, так и с индексами. Эта неоднозначность является еще одной причиной, по которой документация неясна. Я хочу, в конечном счете, использовать функция, не основанная на массиве, но основанная на ядре - например, каждое значение может быть выбрано из URL-адреса или базы данных на основе индексов или даже ввода из Е. Пользователь)


Возвращаясь к проблеме - что, как я могу заполнить массив из функции, которая вызывается один раз для каждого элемента, то ответ, как представляется:

Вы не можете сделать это в функциональный стиль.

Вы можете сделать это в императивном/итеративном стиле, т. Е. Писать вложенные петли и управлять длиной индекса самостоятельно.

Вы также можете сделать это как итератор, но итератору по-прежнему необходимо отслеживать собственные индексы.

+5

Это невероятно вводящая в заблуждение часть документации. Добавьте это к тому факту, что 'x == y' имеет совершенно нелепое поведение, заключающееся в точечном сравнении и возвращении массива, и у вас есть примеры документации, которые, по-видимому, подразумевают, для кого-то с опытом вне numpy, что он делает ячейку вычисление по ячейкам –

2

Я думаю, что вы не понимаете, что делает fromfunction.

От numpysource code.

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]]]) 
+0

Понял (сейчас), но вижу мой ответ. Документация не соответствует этому коду, и это не касается вопроса о том, какой правильный способ это сделать. – Oddthinking

1

Получает ли это неверный результат? 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.]]]) 
+0

Извините, мой пример привел вас по неверному пути. Да, пример работал так, как описано, но я хочу заменить sum_of_indices на реальную функцию, которая не может работать на уровне массива. См. Мой ответ. – Oddthinking

21

Документация очень вводит в заблуждение в этом отношении. Это так же, как вы обратите внимание: вместо выполнения 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)