функция numpy apply над двумя 3d матрицами - PullRequest
0 голосов
/ 11 октября 2019

Итак, я хотел бы применить функцию к двум 3d-матрицам с помощью numpy, и я не могу понять, как это сделать. Я читал о numpy.apply_over_axes (), но не могу заставить его работать.

Теперь это мой код:

c = np.random.beta(2,3,size=(2,80))

def my_func(a,b):
    xi = np.matmul(b, c)

    spe = np.power(a - xi, 2)
    return spe.sum()

a = np.zeros(shape=(5,1000,80))
b = np.random.beta(2,3,size=(5,1000,2))

np.apply_over_axes(func=my_func,a=[a,b],axes=[0,0,0])

, который не работает и возвращает

could not broadcast input array from shape (5,1000,80) into shape (5,1000)

Я хотел бы повторить, хотя a и b и применить my_func к каждому вектору 3-го измерения.

Это будет работать, но с нормальным для циклов:

results = []
for i in range(len(a)): #5 Iterations
    for j in range(len(a[i])): #1000 Iterations
        results.append(my_func(a[i][j], b[i][j]))

Я бы хотел получить это results, но используя функции numpy.

Ответы [ 2 ]

1 голос
/ 11 октября 2019

Операция сжатия, скрытая в np.matmul(b, c), может быть достигнута с помощью np.tensordot(b, c, axes=[2, 0]), где [2, 0] указывает, что третья ось в b стянута с первой осью в c. То есть np.tensordot(b, c, axes=[2, 0]).shape - это (5, 1000, 80). С этого момента применяется обычное вещание, и ваш код сводится к

a = np.zeros(shape=(5, 1000, 80))
b = np.random.beta(2, 3, size=(5, 1000, 2))
c = np.random.beta(2, 3, size=(2, 80))

xi = np.tensordot(b, c, axes=[2, 0])
spe = np.power(a - xi, 2)
results2 = spe.sum(axis=2)

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

In [55]: results = np.array(results).reshape(5, 1000)

In [56]: np.allclose(results, results2)
Out[56]: True
0 голосов
/ 11 октября 2019

Запуск вашего кода в сеансе ipython:

In [88]: c = np.random.beta(2,3,size=(2,80)) 
    ...:  
    ...: def my_func(a,b): 
    ...:     xi = np.matmul(b, c) 
    ...:  
    ...:     spe = np.power(a - xi, 2) 
    ...:     return spe.sum() 
    ...:  
    ...: a = np.zeros(shape=(5,1000,80)) 
    ...: b = np.random.beta(2,3,size=(5,1000,2)) 
    ...:  
    ...: np.apply_over_axes(func=my_func,a=[a,b],axes=[0,0,0])                  
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-88-c5e5a66c9d0a> in <module>
     10 b = np.random.beta(2,3,size=(5,1000,2))
     11 
---> 12 np.apply_over_axes(func=my_func,a=[a,b],axes=[0,0,0])

<__array_function__ internals> in apply_over_axes(*args, **kwargs)

/usr/local/lib/python3.6/dist-packages/numpy/lib/shape_base.py in apply_over_axes(func, a, axes)
    485 
    486     """
--> 487     val = asarray(a)
    488     N = a.ndim
    489     if array(axes).ndim == 0:

/usr/local/lib/python3.6/dist-packages/numpy/core/_asarray.py in asarray(a, dtype, order)
     83 
     84     """
---> 85     return array(a, dtype, copy=False, order=order)
     86 
     87 

ValueError: could not broadcast input array from shape (5,1000,80) into shape (5,1000)

Вы должны были показать нам полную ошибку при трассировке.

Этот трассировщик показывает нам, что он пытается создать один массивиз вашего списка двух. Поскольку формы не совпадают, возникает ошибка. При другом несоответствии он создал бы (2,) объектный массив, который просто переместил бы проблемы с поднятиями позже:

In [89]: np.array([a,b])                                                        
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-89-964832cdcfcd> in <module>
----> 1 np.array([a,b])

ValueError: could not broadcast input array from shape (5,1000,80) into shape (5,1000)

Но проблема в том, что вы не читали документы или не относились к ним серьезно:

func : function
    This function must take two arguments, `func(a, axis)`.
a : array_like
    Input array.
axes : array_like
    Axes over which `func` is applied; the elements must be integers.

a должен быть массивом, а не списком из двух массивов. func должен принимать параметр axis, а не другой массив. И я не знаю, что вы пытаетесь сделать с [0,0,0]. Для трехмерных массивов [0,1] может применяться, но не повторяется 0.

ваш цикл

С немного лучшим стилем numpy:

In [91]: results = [] 
    ...: for i in range(a.shape[0]): #5 Iterations 
    ...:     for j in range(a.shape[1]): #1000 Iterations 
    ...:         results.append(my_func(a[i,j], b[i,j])) 
    ...:                                                                        
In [92]: np.array(results).shape                                                
Out[92]: (5000,)

rework my_func

Чтобы сделать это без циклов, нам нужно использовать функции целого массива в my_func. Не существует numpy apply, который компилирует код Python - для этого нужно посмотреть numba или cython.

xi=np.matmul(b,c). b - (5,1000,2), c - (2,80). matmul счастлив делать dot, объединяя последнюю ось b со 2-ой по последнюю из c.

In [93]: xi = np.matmul(b,c)                                                    
In [94]: xi.shape                                                               
Out[94]: (5, 1000, 80)

Это соответствует a, поэтому

In [97]: spe = np.power(a-xi,2)                                                 
In [98]: spe.shape                                                              
Out[98]: (5, 1000, 80)

затем сумма по этой последней оси:

In [99]: res = spe.sum(axis=2)                                                  
In [100]: res.shape                                                             
Out[100]: (5, 1000)

, которая соответствует вашему циклу:

In [101]: np.allclose(res.ravel(), np.array(results))                           
Out[101]: True

За исключением последнего sum, ваш myfunc работает с целыммассивы.

In [103]: my_func(a,b)                                                          
Out[103]: 46883.49325596101
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...